Skip to content

Commit

Permalink
vis: change key input handling model
Browse files Browse the repository at this point in the history
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 martanne#386
  • Loading branch information
martanne committed Jan 16, 2017
1 parent 55f79e7 commit 9997739
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 19 deletions.
4 changes: 2 additions & 2 deletions vis-modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ static bool mode_map(Vis *vis, Mode *mode, bool force, const char *key, const Ke
if (!mode->bindings && !(mode->bindings = map_new()))
return false;
if (force)
map_prefix_delete(mode->bindings, key);
return (strcmp(key, "<") == 0 || !map_contains(mode->bindings, key)) && map_put(mode->bindings, key, binding);
map_delete(mode->bindings, key);
return map_put(mode->bindings, key, binding);
}

bool vis_mode_map(Vis *vis, enum VisMode id, bool force, const char *key, const KeyBinding *binding) {
Expand Down
45 changes: 28 additions & 17 deletions vis.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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] == '>') {
Expand Down

0 comments on commit 9997739

Please sign in to comment.