From e0d9a641d3dc525ed65fc99a9f2e567cb1301b2c Mon Sep 17 00:00:00 2001 From: Charlie Gordon Date: Sat, 25 May 2024 23:37:05 +0200 Subject: [PATCH] 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 --- Makefile | 6 +- buffer.c | 8 ++ extras.c | 64 ++++++++-------- modes/bufed.c | 14 +++- modes/shell.c | 5 ++ qe.c | 207 +++++++++++++++++++++++++++++--------------------- qe.h | 16 +++- qeconfig.h | 11 ++- 8 files changed, 197 insertions(+), 134 deletions(-) diff --git a/Makefile b/Makefile index 8f37f77..13043f4 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/buffer.c b/buffer.c index 95adf62..4ff0ef1 100644 --- a/buffer.c +++ b/buffer.c @@ -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)); diff --git a/extras.c b/extras.c index d2a9947..5c379f1 100644 --- a/extras.c +++ b/extras.c @@ -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) diff --git a/modes/bufed.c b/modes/bufed.c index 097e9f2..ebccbb1 100644 --- a/modes/bufed.c +++ b/modes/bufed.c @@ -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); diff --git a/modes/shell.c b/modes/shell.c index 58af2ad..e42e4b9 100644 --- a/modes/shell.c +++ b/modes/shell.c @@ -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); } diff --git a/qe.c b/qe.c index 7597855..e7edf9c 100644 --- a/qe.c +++ b/qe.c @@ -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 , , , "); + 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 and "); + 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) { diff --git a/qe.h b/qe.h index 558fe51..be95551 100644 --- a/qe.h +++ b/qe.h @@ -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); diff --git a/qeconfig.h b/qeconfig.h index 8051eea..78d4db3 100644 --- a/qeconfig.h +++ b/qeconfig.h @@ -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)