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:
parent
6f34c65ef9
commit
e0d9a641d3
8 changed files with 195 additions and 132 deletions
6
Makefile
6
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
|
||||
|
|
|
|||
8
buffer.c
8
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));
|
||||
|
|
|
|||
64
extras.c
64
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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
207
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 <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
16
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);
|
||||
|
|
|
|||
11
qeconfig.h
11
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue