vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit 6d568eb40c180c78b019c25a20a0ea97a9b2894d
parent 3e1e0b092f6f1233496f58d348d0574ca1a49753
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Fri,  3 Nov 2017 15:14:06 +0100

vis: take symbolic keys into account when evaluating key prefixes

Previously `ci<` would have no immediate effect because in operator
pending mode `i<` was wrongly treated as a powwible prefix of `i<Tab>`.

Fix #624

Diffstat:
Mvis.c | 38++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/vis.c b/vis.c @@ -1113,6 +1113,26 @@ bool vis_keys_utf8(Vis *vis, const char *keys, char utf8[static UTFmax+1]) { return true; } +typedef struct { + Vis *vis; + size_t len; // length of the prefix + int count; // how many bindings can complete this prefix + bool angle_bracket; // does the prefix end with '<' +} PrefixCompletion; + +static bool isprefix(const char *key, void *value, void *data) { + PrefixCompletion *completion = data; + if (!completion->angle_bracket) { + completion->count++; + } else { + const char *start = key + completion->len; + const char *end = vis_keys_next(completion->vis, start); + if (end && start + 1 == end) + completion->count++; + } + return completion->count == 1; +} + static void vis_keys_process(Vis *vis, size_t pos) { Buffer *buf = &vis->input_queue; char *keys = buf->data + pos, *start = keys, *cur = keys, *end = keys, *binding_end = keys;; @@ -1143,12 +1163,18 @@ static void vis_keys_process(Vis *vis, size_t pos) { 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)); - } + + const Map *pmap = map_prefix(mode->bindings, start); + PrefixCompletion completions = { + .vis = vis, + .len = cur - start, + .count = 0, + .angle_bracket = !strcmp(cur, "<"), + }; + map_iterate(pmap, isprefix, &completions); + + prefix = (!match && completions.count > 0) || + ( match && completions.count > 1); } }