diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2016-12-16 12:37:55 +0100 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2017-01-16 19:46:07 +0100 |
| commit | 9997739b96a7fc142a18cb72cb7589bd4b4d61b0 (patch) | |
| tree | 58ec9864c78d917ecc3d70066dbc4c1dd2bda8b5 /vis.c | |
| parent | 55f79e75f34ccf740d3f1c92ab35c604b067b01c (diff) | |
| download | vis-9997739b96a7fc142a18cb72cb7589bd4b4d61b0.tar.gz vis-9997739b96a7fc142a18cb72cb7589bd4b4d61b0.tar.xz | |
vis: change key input handling model
Previously if you had a mapping for both `a` and `ab` the latter would
in effect be unreachable because the greedy search would always match
and then execute the former. With the new behavior we keep reading keys
until we have a non ambigious sequence. That is after pressing `a` nothing
will happen, if the next key is a `b` we will execute the `ab` mapping
otherwise we will perform `a` and whatever the action is for the next key.
Close #386
Diffstat (limited to 'vis.c')
| -rw-r--r-- | vis.c | 45 |
1 files changed, 28 insertions, 17 deletions
@@ -946,7 +946,7 @@ long vis_keys_codepoint(Vis *vis, const char *keys) { static void vis_keys_process(Vis *vis, size_t pos) { Buffer *buf = vis->keys; - char *keys = buf->data + pos, *start = keys, *cur = keys, *end = keys; + char *keys = buf->data + pos, *start = keys, *cur = keys, *end = keys, *binding_end = keys;; bool prefix = false; KeyBinding *binding = NULL; @@ -960,39 +960,50 @@ static void vis_keys_process(Vis *vis, size_t pos) { char tmp = *end; *end = '\0'; prefix = false; - binding = NULL; - for (Mode *mode = vis->mode; mode && !binding && !prefix; mode = mode->parent) { - for (int global = 0; global < 2 && !binding && !prefix; global++) { - Mode *mode_local = global || !vis->win ? mode : &vis->win->modes[mode->id]; - if (!mode_local->bindings) + for (Mode *global_mode = vis->mode; global_mode && !prefix; global_mode = global_mode->parent) { + for (int global = 0; global < 2 && !prefix; global++) { + Mode *mode = (global || !vis->win) ? + global_mode : + &vis->win->modes[global_mode->id]; + if (!mode->bindings) continue; - binding = map_get(mode_local->bindings, start); - /* "<" is never treated as a prefix because it is used to denote - * special key symbols */ - if (strcmp(cur, "<")) - prefix = !binding && map_contains(mode_local->bindings, start); + /* keep track of longest matching binding */ + KeyBinding *match = map_get(mode->bindings, start); + if (match && end > binding_end) { + binding = match; + binding_end = end; + } + /* "<" is never treated as a prefix because it + * is used to denote special key symbols */ + if (strcmp(start, "<")) { + prefix = (!match && map_contains(mode->bindings, start)) || + (match && !map_leaf(mode->bindings, start)); + } } } *end = tmp; - if (binding) { /* exact match */ + if (prefix) { + /* input sofar is ambigious, wait for more */ + cur = end; + end = start; + } else if (binding) { /* exact match */ if (binding->action) { - end = (char*)binding->action->func(vis, end, &binding->action->arg); + end = (char*)binding->action->func(vis, binding_end, &binding->action->arg); if (!end) { end = start; break; } start = cur = end; } else if (binding->alias) { - buffer_remove(buf, start - buf->data, end - start); + buffer_remove(buf, start - buf->data, binding_end - start); buffer_insert0(buf, start - buf->data, binding->alias); cur = end = start; } - } else if (prefix) { /* incomplete key binding? */ - cur = end; - end = start; + binding = NULL; + binding_end = start; } else { /* no keybinding */ KeyAction *action = NULL; if (start[0] == '<' && end[-1] == '>') { |
