Add repeat-mode (#34)

- add `repeat` command on `C-x z`
- add `repeat-mode`, always enabled
- cycle all matching tags in current file on `goto-tag` and `find-tag`
- set up `repeat-mode` for these commands:
  - `undo` on `C-x u` (`u` repeats `undo`, `r` performs `redo`)
  - `undo` on `C-x r` (`r` repeats `redo`, `u` performs `undo`)
  - `find-window-left`, `find-window-right`, `find-window-up`, `find-window-dow`
    repeat navigation on `up`, `down`, `left`, `right`
  - `next-error`, `previous-error`: `M-n` and `M-p` repeat in corresponding direction
  - `next-buffer`, `previous-buffer: repeat buffers nagivation with `left` and `right`
  - `enlarge-window` / `shrink-window`: repeat resizing on `^`, `v`, `{`, `}`
     and cursor movement keys
  - `goto-tag` on `C-x ,` goto next tag with `,` and `.`
  - `call-last-kbd-macro` on `C-x e`: repeat macro on `e`
- add `eb_count_buffers` and `eb_get_buffer_from_index` for safe buffer navigation
- add transient bindings, known as repeat maps in GNU emacs
- pass `KeyDef **lp` (aka key maps) instead of mode for binding commands
- replace `do_next_buffer` and `do_prevous_buffer` with repeatable command
  `do_buffer_navigation`
- fix `bufed_select` crash bug when selecting buffer from a regular window
This commit is contained in:
Charlie Gordon 2024-05-25 23:37:05 +02:00 • committed by GitHub
commit e0d9a641d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 195 additions and 132 deletions

View file

@ -116,9 +116,9 @@ else
OBJS+= extras.o variables.o
endif
ifdef CONFIG_DARWIN
LDFLAGS += -L/opt/local/lib/
endif
#ifdef CONFIG_DARWIN
# LDFLAGS += -L/opt/local/lib/
#endif
ifdef CONFIG_PNG_OUTPUT
HTMLTOPPM_LIBS += -lpng

View file

@ -1235,6 +1235,7 @@ static void eb_addlog(EditBuffer *b, enum LogOperation op,
void do_undo(EditState *s)
{
QEmacsState *qs = s->qe_state;
EditBuffer *b = s->b;
int log_index, size_trailer;
LogBuffer lb;
@ -1264,6 +1265,13 @@ void do_undo(EditState *s)
} else {
put_status(s, "Undo!");
}
if (!qs->first_transient_key
&& (qs->last_key == 'u' || qs->last_key == 'u')) {
put_status(s, "repeat with 'u', 'r'");
qe_register_transient_binding(qs, "undo", "u");
qe_register_transient_binding(qs, "redo", "r");
}
/* go backward */
log_index -= sizeof(int);
eb_read(b->log_buffer, log_index, &size_trailer, sizeof(int));

View file

@ -429,7 +429,7 @@ void do_compare_files(EditState *s, const char *filename, int bflags)
#define QE_AW_VERTICAL 0
#define QE_AW_HORIZONTAL 2
static void do_adjust_window(EditState *s, int flags, int argval)
static void do_adjust_window(EditState *s, int argval, int flags)
{
QEmacsState *qs = s->qe_state;
EditState *e;
@ -437,8 +437,6 @@ static void do_adjust_window(EditState *s, int flags, int argval)
if (s->flags & WF_MINIBUF)
return;
if (argval == NO_ARG)
argval = 1;
if (argval < 0) {
flags ^= QE_AW_SHRINK;
argval = -argval;
@ -446,6 +444,14 @@ static void do_adjust_window(EditState *s, int flags, int argval)
if (flags & QE_AW_SHRINK)
argval = -argval;
if (!qs->first_transient_key) {
put_status(s, "adjusting window, repeat with ^, }, {, v");
qe_register_transient_binding(qs, "enlarge-window", "^, up");
qe_register_transient_binding(qs, "shrink-window", "v, down");
qe_register_transient_binding(qs, "enlarge-window-horizontally", "}, right");
qe_register_transient_binding(qs, "shrink-window-horizontally", "{, left");
}
if (flags & QE_AW_HORIZONTAL) {
delta = s->char_width * argval;
if ((delta > 0 && s->x1 > delta)
@ -489,37 +495,13 @@ static void do_adjust_window(EditState *s, int flags, int argval)
do_refresh(s);
}
static void resize_window_key(void *opaque, int key) {
EditState *s = opaque;
switch (key) {
case KEY_LEFT:
do_adjust_window(s, QE_AW_ENLARGE | QE_AW_HORIZONTAL, 1);
break;
case KEY_RIGHT:
do_adjust_window(s, QE_AW_SHRINK | QE_AW_HORIZONTAL, 1);
break;
case KEY_UP:
do_adjust_window(s, QE_AW_ENLARGE | QE_AW_VERTICAL, 1);
break;
case KEY_DOWN:
do_adjust_window(s, QE_AW_SHRINK | QE_AW_VERTICAL, 1);
break;
default:
qe_ungrab_keys();
put_status(s, "Done resizing");
break;
}
edit_display(s->qe_state);
dpy_flush(s->screen);
}
static void do_resize_window(EditState *s) {
/* prevent resizing minibuffer */
if (s->flags & WF_MINIBUF)
return;
put_status(s, "Resize window interactively with {left}, {right}, {up}, {down}");
qe_grab_keys(resize_window_key, s);
do_adjust_window(s, 0, 0);
}
void do_delete_horizontal_space(EditState *s)
@ -2120,16 +2102,30 @@ static int tag_get_entry(EditState *s, char *dest, int size, int offset)
}
static void do_find_tag(EditState *s, const char *str) {
QEmacsState *qs = s->qe_state;
QEProperty *p;
int offset = -1;
tag_buffer(s);
if (!qs->first_transient_key)
qe_register_transient_binding(qs, "goto-tag", ",, .");
for (p = s->b->property_list; p; p = p->next) {
if (p->type == QE_PROP_TAG && strequal(p->data, str)) {
s->offset = p->offset;
return;
if (offset < 0)
offset = p->offset;
if (s->offset < p->offset) {
s->offset = p->offset;
return;
}
}
}
if (offset >= 0) {
/* target not found after point, use first match */
s->offset = offset;
return;
}
put_status(s, "Tag not found: %s", str);
}
@ -2573,16 +2569,16 @@ static const CmdDef extra_commands[] = {
CMD3( "enlarge-window", "C-x ^",
"Enlarge window vertically",
do_adjust_window, ESii, "vp", QE_AW_ENLARGE | QE_AW_VERTICAL)
do_adjust_window, ESii, "p" "v", QE_AW_ENLARGE | QE_AW_VERTICAL)
CMD3( "shrink-window", "C-x v",
"Shrink window vertically",
do_adjust_window, ESii, "vp", QE_AW_SHRINK | QE_AW_VERTICAL)
do_adjust_window, ESii, "p" "v", QE_AW_SHRINK | QE_AW_VERTICAL)
CMD3( "enlarge-window-horizontally", "C-x }",
"Enlarge window horizontally",
do_adjust_window, ESii, "vp", QE_AW_ENLARGE | QE_AW_HORIZONTAL)
do_adjust_window, ESii, "p" "v", QE_AW_ENLARGE | QE_AW_HORIZONTAL)
CMD3( "shrink-window-horizontally", "C-x {",
"Shrink window horizontally",
do_adjust_window, ESii, "vp", QE_AW_SHRINK | QE_AW_HORIZONTAL)
do_adjust_window, ESii, "p" "v", QE_AW_SHRINK | QE_AW_HORIZONTAL)
CMD0( "resize-window", "C-x +",
"Resize window interactively using the cursor keys",
do_resize_window)

View file

@ -293,12 +293,18 @@ static void bufed_select(EditState *s, int temp)
if (e && b) {
switch_to_buffer(e, b);
e->last_buffer = last_buffer;
} else {
if (e == NULL) {
switch_to_buffer(s, b);
}
}
if (temp <= 0) {
/* delete bufed window */
do_delete_window(s, 1);
if (e)
e->qe_state->active_window = e;
if (s->flags & WF_POPUP) {
/* delete bufed window */
do_delete_window(s, 1);
if (e)
e->qe_state->active_window = e;
}
} else {
bs->last_index = index;
do_refresh_complete(s);

View file

@ -3474,6 +3474,11 @@ static void do_next_error(EditState *s, int arg, int dir)
do_find_file(s, fullpath, 0);
do_goto_line(qs->active_window, line_num, col_num);
if (!qs->first_transient_key) {
qe_register_transient_binding(qs, "next-error", "M-n");
qe_register_transient_binding(qs, "previous-error", "M-p");
}
put_status(s, "=> %s", error_message);
}

207
qe.c
View file

@ -210,7 +210,7 @@ void qe_register_mode(ModeDef *m, int flags)
if (m->bindings) {
int i;
for (i = 0; m->bindings[i]; i += 2) {
qe_register_bindings(m, m->bindings[i + 1], m->bindings[i]);
qe_register_bindings(&m->first_key, m->bindings[i + 1], m->bindings[i]);
}
}
}
@ -311,10 +311,17 @@ static CompletionDef command_completion = {
/* key binding handling */
static int qe_register_binding(ModeDef *m, const CmdDef *d, const unsigned int *keys, int nb_keys)
static void qe_free_bindings(KeyDef **lp) {
while (*lp) {
KeyDef *p = *lp;
*lp = p->next;
qe_free(&p);
}
}
static int qe_register_binding(KeyDef **lp, const CmdDef *d, const unsigned int *keys, int nb_keys)
{
QEmacsState *qs = &qe_state;
KeyDef **lp, *p;
KeyDef *p;
int i;
if (!nb_keys)
@ -331,8 +338,6 @@ static int qe_register_binding(ModeDef *m, const CmdDef *d, const unsigned int *
for (i = 0; i < nb_keys; i++) {
p->keys[i] = keys[i];
}
// XXX: should use fundamental_mode
lp = m ? &m->first_key : &qs->first_key;
/* Bindings must be prepended to override previous bindings
* skip bindings to the same command for consistency */
while (*lp != NULL && (*lp)->cmd == d)
@ -343,14 +348,12 @@ static int qe_register_binding(ModeDef *m, const CmdDef *d, const unsigned int *
}
/* remove a key binding from mode or globally */
static int qe_unregister_binding(ModeDef *m, unsigned int *keys, int nb_keys) {
QEmacsState *qs = &qe_state;
KeyDef **lp, *p;
static int qe_unregister_binding(KeyDef **lp, unsigned int *keys, int nb_keys) {
KeyDef *p;
if (!nb_keys)
return -2;
lp = m ? &m->first_key : &qs->first_key;
while (*lp) {
if ((*lp)->nb_keys == nb_keys && !blockcmp((*lp)->keys, keys, nb_keys)) {
p = *lp;
@ -364,7 +367,7 @@ static int qe_unregister_binding(ModeDef *m, unsigned int *keys, int nb_keys) {
}
/* if mode is non NULL, the defined keys are only active in this mode */
static int qe_register_command_bindings(ModeDef *m, const CmdDef *d, const char *keystr)
static int qe_register_command_bindings(KeyDef **lp, const CmdDef *d, const char *keystr)
{
unsigned int keys[MAX_KEYS];
int nb_keys, res = -2;
@ -372,23 +375,27 @@ static int qe_register_command_bindings(ModeDef *m, const CmdDef *d, const char
while (p && *p) {
nb_keys = strtokeys(p, keys, MAX_KEYS, &p);
res = qe_register_binding(m, d, keys, nb_keys);
res = qe_register_binding(lp, d, keys, nb_keys);
}
return res;
}
int qe_register_bindings(ModeDef *m, const char *cmd_name, const char *keys) {
return qe_register_command_bindings(m, qe_find_cmd(cmd_name), keys);
int qe_register_bindings(KeyDef **lp, const char *cmd_name, const char *keys) {
return qe_register_command_bindings(lp, qe_find_cmd(cmd_name), keys);
}
static void qe_unregister_bindings(ModeDef *m, const char *keystr) {
int qe_register_transient_binding(QEmacsState *qs, const char *cmd_name, const char *keys) {
return qe_register_command_bindings(&qs->first_transient_key, qe_find_cmd(cmd_name), keys);
}
static void qe_unregister_bindings(KeyDef **lp, const char *keystr) {
unsigned int keys[MAX_KEYS];
int nb_keys;
const char *p = keystr;
while (p && *p) {
nb_keys = strtokeys(p, keys, MAX_KEYS, &p);
qe_unregister_binding(m, keys, nb_keys);
qe_unregister_binding(lp, keys, nb_keys);
}
}
@ -396,6 +403,7 @@ static void qe_unregister_bindings(ModeDef *m, const char *keystr) {
int qe_register_commands(ModeDef *m, const CmdDef *cmds, int len)
{
QEmacsState *qs = &qe_state;
KeyDef **lp = m ? &m->first_key : &qs->first_key;
const CmdDef *d;
int i, allocated = 0;
@ -430,7 +438,7 @@ int qe_register_commands(ModeDef *m, const CmdDef *cmds, int len)
for (d = cmds, i = len; i-- > 0; d++) {
const char *p = d->name + strlen(d->name) + 1;
if (*p)
qe_register_command_bindings(m, d, p);
qe_register_command_bindings(lp, d, p);
}
return 0;
}
@ -438,8 +446,8 @@ int qe_register_commands(ModeDef *m, const CmdDef *cmds, int len)
void do_set_key(EditState *s, const char *keystr,
const char *cmd_name, int local)
{
ModeDef *m = local ? s->mode : NULL;
int res = qe_register_bindings(m, cmd_name, keystr);
KeyDef **lp = local ? &s->mode->first_key : &s->qe_state->first_key;
int res = qe_register_bindings(lp, cmd_name, keystr);
if (res == -2)
put_status(s, "Invalid keys: %s", keystr);
if (res == -1)
@ -447,7 +455,8 @@ void do_set_key(EditState *s, const char *keystr,
}
void do_unset_key(EditState *s, const char *keystr, int local) {
qe_unregister_bindings(local ? s->mode : NULL, keystr);
KeyDef **lp = local ? &s->mode->first_key : &s->qe_state->first_key;
qe_unregister_bindings(lp, keystr);
}
void do_toggle_control_h(EditState *s, int set)
@ -543,15 +552,16 @@ static const char * const gosmacs_bindings[] = {
static void register_emulation_bindings(QEmacsState *qs, const char * const *pp) {
int i;
for (i = 0; pp[i]; i += 3) {
ModeDef *mode = NULL;
KeyDef **lp = &qs->first_key;
if (pp[i + 2]) {
mode = qe_find_mode(pp[i + 2], 0);
ModeDef *mode = qe_find_mode(pp[i + 2], 0);
if (!mode)
continue;
lp = &mode->first_key;
}
qe_unregister_bindings(mode, pp[i]);
qe_unregister_bindings(lp, pp[i]);
if (pp[i])
qe_register_bindings(mode, pp[i + 1], pp[i]);
qe_register_bindings(lp, pp[i + 1], pp[i]);
}
}
@ -5542,7 +5552,7 @@ void do_end_kbd_macro(EditState *s)
void do_call_last_kbd_macro(EditState *s)
{
QEmacsState *qs = s->qe_state;
int key;
int set_repeat = (qs->last_key == 'e');
if (qs->defining_macro) {
qs->defining_macro = 0;
@ -5554,11 +5564,16 @@ void do_call_last_kbd_macro(EditState *s)
/* CG: should share code with do_execute_macro */
for (qs->macro_key_index = 0;
qs->macro_key_index < qs->nb_macro_keys;
qs->macro_key_index++) {
key = qs->macro_keys[qs->macro_key_index];
qs->macro_key_index++)
{
int key = qs->macro_keys[qs->macro_key_index];
qe_key_process(key);
}
qs->macro_key_index = -1;
qe_free_bindings(&qs->first_transient_key);
if (set_repeat)
qe_register_transient_binding(qs, "call-last-kbd-macro", "e");
}
}
@ -5796,9 +5811,18 @@ KeyDef *qe_find_binding(unsigned int *keys, int nb_keys, KeyDef *kd, int exact)
KeyDef *qe_find_current_binding(unsigned int *keys, int nb_keys, ModeDef *m, int exact)
{
QEmacsState *qs = &qe_state;
KeyDef *kd;
if (qs->first_transient_key) {
/* first look up transient repeat mode */
kd = qe_find_binding(keys, nb_keys, qs->first_transient_key, exact);
if (kd)
return kd;
qe_free_bindings(&qs->first_transient_key);
}
for (; m; m = m->fallback) {
KeyDef *kd = qe_find_binding(keys, nb_keys, m->first_key, exact);
kd = qe_find_binding(keys, nb_keys, m->first_key, exact);
if (kd != NULL)
return kd;
}
@ -5938,6 +5962,11 @@ static void qe_key_process(int key)
* dispatching the command
*/
qe_key_init(c);
if (d->action.ESi != do_repeat) {
qs->last_cmd = d;
qs->last_argval = argval;
qs->last_key = key;
}
exec_command(s, d, argval, key);
}
qe_key_init(c);
@ -7371,6 +7400,15 @@ EditState *find_window(EditState *s, int key, EditState *def)
void do_find_window(EditState *s, int key)
{
QEmacsState *qs = s->qe_state;
if (!qs->first_transient_key) {
put_status(s, "window navigation, repeat with <up>, <down>, <left>, <right>");
qe_register_transient_binding(qs, "find-window-down", "down");
qe_register_transient_binding(qs, "find-window-left", "left");
qe_register_transient_binding(qs, "find-window-right", "right");
qe_register_transient_binding(qs, "find-window-up", "up");
}
s->qe_state->active_window = find_window(s, key, s);
}
#endif
@ -7410,65 +7448,57 @@ void do_switch_to_buffer(EditState *s, const char *bufname)
switch_to_buffer(s, b);
}
/* Find next non-system buffer from the specified buffer. If the specified
buffer is the last one, returns the first one. If only one non-system buffer
exists currently, return itself. */
static EditBuffer *next_non_system_buffer(EditState *s, EditBuffer *b) {
EditBuffer *nb = b == NULL ? NULL : b->next;
if (nb == NULL) {
nb = s->qe_state->first_buffer;
int eb_count_buffers(QEmacsState *qs, EditBuffer *b0, int *countp, int mask, int val) {
EditBuffer *b;
int index = 0, count = 0;
for (b = qs->first_buffer; b; b = b->next) {
if (b == b0)
index = count;
if ((b->flags & mask) == val)
count++;
}
/* qemacs guarantees at least one non-system buffer (i.e. `*scratch*`) exists */
while (nb->flags & BF_SYSTEM) {
nb = nb->next;
if (nb == NULL) {
nb = s->qe_state->first_buffer;
}
}
return nb;
if (countp)
*countp = count;
return index;
}
void do_next_buffer(EditState *s)
EditBuffer *eb_get_buffer_from_index(QEmacsState *qs, int index, int mask, int val) {
EditBuffer *b;
for (b = qs->first_buffer; b; b = b->next) {
if ((b->flags & mask) == val) {
if (index == 0)
return b;
index--;
}
}
return NULL;
}
/* Find the n-th non-system buffer from the specified buffer in a given
direction. Set up repeat map */
void do_buffer_navigation(EditState *s, int argval, int dir)
{
QEmacsState *qs = s->qe_state;
int buffer_index, buffer_count;
EditBuffer *b;
/* ignore command from the minibuffer and popups */
if (s->flags & (WF_POPUP | WF_MINIBUF))
return;
b = next_non_system_buffer(s, s->b);
switch_to_buffer(s, b);
}
void do_previous_buffer(EditState *s)
{
// TODO(chqrlie): simplify this by counting non system buffers
// also handle universal argument
EditBuffer *orig, *curr, *curr_next;
/* ignore command from the minibuffer and popups */
if (s->flags & (WF_POPUP | WF_MINIBUF))
buffer_index = eb_count_buffers(qs, s->b, &buffer_count, BF_SYSTEM, 0);
/* no action if single non system buffer */
if (buffer_count <= 1)
return;
/* what we want to compare & find are non-system buffers, so need to ignore
all non-system buffers; or it may fall into an infinite loop. */
/* original buffer is immutable */
orig = s->b;
if (orig->flags & BF_SYSTEM) {
orig = next_non_system_buffer(s, orig);
if (!qs->first_transient_key) {
put_status(s, "buffer navigatiion, repeat with <left> and <right>");
qe_register_transient_binding(qs, "next-buffer", "right, C-right");
qe_register_transient_binding(qs, "previous-buffer", "left, C-left");
}
/* find from first buffer*/
curr = s->qe_state->first_buffer;
if (curr->flags & BF_SYSTEM) {
curr = next_non_system_buffer(s, curr);
}
curr_next = next_non_system_buffer(s, curr);
while (curr_next != orig) {
curr = curr_next;
curr_next = next_non_system_buffer(s, curr_next);
}
switch_to_buffer(s, curr);
buffer_index = (buffer_index + argval * dir) % buffer_count;
b = eb_get_buffer_from_index(qs, buffer_index, BF_SYSTEM, 0);
if (b)
switch_to_buffer(s, b);
}
void do_toggle_read_only(EditState *s)
@ -8495,6 +8525,21 @@ void do_refresh(EditState *s1)
}
}
void do_repeat(EditState *s, int argval)
{
QEmacsState *qs = s->qe_state;
int active = (s == qs->active_window);
if (!qs->first_transient_key)
qe_register_transient_binding(qs, "repeat", "z");
while (argval --> 0) {
exec_command(s, qs->last_cmd, qs->last_argval, qs->last_key);
if (active)
s = qs->active_window;
}
}
void do_refresh_complete(EditState *s)
{
QEmacsState *qs = s->qe_state;
@ -10139,20 +10184,12 @@ int main(int argc, char **argv)
}
qe_free(&qs->cmd_array);
}
while (qs->first_key) {
KeyDef *p = qs->first_key;
qs->first_key = p->next;
qe_free(&p);
}
qe_free_bindings(&qs->first_key);
while (qs->first_mode) {
ModeDef *m = qs->first_mode;
qs->first_mode = m->next;
while (m->first_key) {
KeyDef *p = m->first_key;
m->first_key = p->next;
qe_free(&p);
}
qe_free_bindings(&m->first_key);
// XXX: should free allocated ModeDef structures
}
while (qs->first_variable) {

16
qe.h
View file

@ -503,6 +503,7 @@ static inline int eb_prev(EditBuffer *b, int offset) {
}
//int eb_clip_offset(EditBuffer *b, int offset);
void do_repeat(EditState *s, int argval);
void do_undo(EditState *s);
void do_redo(EditState *s);
@ -573,6 +574,9 @@ int eb_is_in_indentation(EditBuffer *b, int offset);
int eb_goto_eol(EditBuffer *b, int offset);
int eb_next_line(EditBuffer *b, int offset);
int eb_count_buffers(QEmacsState *qs, EditBuffer *b0, int *totalp, int mask, int val);
EditBuffer *eb_get_buffer_from_index(QEmacsState *qs, int index, int mask, int val);
void eb_register_data_type(EditBufferDataType *bdt);
EditBufferDataType *eb_probe_data_type(const char *filename, int st_mode,
uint8_t *buf, int buf_size);
@ -845,7 +849,7 @@ struct ModeDef {
ModeDef *fallback; /* use bindings from fallback mode */
// XXX: should have a separate list to allow for contant data
// XXX: should have a separate list to allow for constant data
struct KeyDef *first_key;
ModeDef *next;
};
@ -906,6 +910,7 @@ struct QEmacsState {
//struct QEDisplay *first_dpy;
struct ModeDef *first_mode;
struct KeyDef *first_key;
struct KeyDef *first_transient_key;
struct CmdDefArray *cmd_array;
int cmd_array_count;
int cmd_array_size;
@ -970,6 +975,9 @@ struct QEmacsState {
int macro_keys_size;
int macro_key_index; /* -1 means no macro is being executed */
int ungot_key;
int last_key;
int last_argval;
const struct CmdDef *last_cmd; /* last dispatched command */
/* yank buffers */
EditBuffer *yank_buffers[NB_YANK_BUFFERS];
int yank_current;
@ -1131,7 +1139,8 @@ ModeDef *qe_find_mode_filename(const char *filename, int flags);
void qe_register_mode(ModeDef *m, int flags);
void mode_complete(CompleteState *cp, CompleteFunc enumerate);
int qe_register_commands(ModeDef *m, const CmdDef *cmds, int len);
int qe_register_bindings(ModeDef *m, const char *cmd_name, const char *keys);
int qe_register_bindings(KeyDef **lp, const char *cmd_name, const char *keys);
int qe_register_transient_binding(QEmacsState *qs, const char *cmd_name, const char *keys);
const CmdDef *qe_find_cmd(const char *cmd_name);
int qe_get_prototype(const CmdDef *d, char *buf, int size);
int qe_list_bindings(const CmdDef *d, ModeDef *mode, int inherit, char *buf, int size);
@ -1413,8 +1422,7 @@ void display_mode_line(EditState *s);
int edit_set_mode(EditState *s, ModeDef *m);
void qe_set_next_mode(EditState *s, int n, int status);
void do_set_next_mode(EditState *s, int n);
void do_next_buffer(EditState *s);
void do_previous_buffer(EditState *s);
void do_buffer_navigation(EditState *s, int dir, int argval);
/* loading files */
void do_exit_qemacs(EditState *s, int argval);

View file

@ -224,12 +224,12 @@ static const CmdDef basic_commands[] = {
do_kill_buffer, ESsi,
"s{Kill buffer: }[buffer]|buffer|"
"v", 0)
CMD0( "next-buffer", "C-x C-right",
CMD3( "next-buffer", "C-x C-right",
"Switch to the next buffer",
do_next_buffer)
CMD0( "previous-buffer", "C-x C-left",
do_buffer_navigation, ESii, "p" "v", 1)
CMD3( "previous-buffer", "C-x C-left",
"Switch to the previous buffer",
do_previous_buffer)
do_buffer_navigation, ESii, "p" "v", -1)
CMD0( "toggle-read-only", "C-x C-q, C-c %",
"Toggle the read-only flag of the current buffer",
do_toggle_read_only)
@ -474,6 +474,9 @@ static const CmdDef basic_commands[] = {
CMD0( "refresh", "C-l",
"Refresh the display, center the window contents at point",
do_refresh_complete)
CMD2( "repeat", "C-x z",
"Repeat last command with same prefix argument",
do_repeat, ESi, "p")
CMD0( "undo", "C-x u, C-_, f9",
"Undo the last change",
do_undo)