2 * Copyright Neil Brown ©2015-2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
7 * A keymap maps a key to a command.
8 * Keys are ordered for fast binary-search lookup.
9 * A "key" is an arbitrary string which typically contains
10 * some 'mode' prefix and some specific tail.
11 * e.g emacs:A:C-X is Alt-Control-X in emacs mode.
12 * As far as the map is concerned, it is just a lexically order string.
14 * A 'command' is a struct provided by any of various
17 * A range can be stored by setting the lsb of the command pointer at
18 * the start of the range.
19 * When searching for a key we find the first entry that is not less
20 * than the target. If it is an exact match, use it. If previous entry
21 * exists and has the lsb set, then use that command.
23 * So to add a range, the start is entered with lsb set, and the end it
24 * entered with lsb clear.
26 * If a key is registered a second time, the new over-rides the old.
27 * This is particularly useful for registering a range, and then some
29 * To delete a key from a range we need to make two ranges, one that ends
30 * just before the new key, one that starts just after.
31 * The 'ends just before' is easy - we just add the new key or range.
32 * The 'starts just after' is managed by entering the same key twice.
33 * The first instance of the key has a 'lsb clear' command and is used for
34 * exact matches. The second instance has 'lsb set' and is used for everything
37 * A 'prefix' can be registered which creates a command which temporarily
38 * enabled the given prefix. It is applied to the next command, but is
39 * discarded after that. This is just a convenience function.
43 #define _GNU_SOURCE /* for asprintf */
52 inline static int qhash(char key, unsigned int start)
54 return (start ^ key) * 0x61C88647U;
58 unsigned long bloom[256 / (sizeof(unsigned long)*8) ];
63 char * safe *keys safe;
64 struct command * safe *comms safe;
67 static inline struct command * safe GETCOMM(struct command *c safe)
69 return (struct command * safe)(((unsigned long)c) & ~1UL);
72 static inline int IS_RANGE(struct command *c)
74 return ((unsigned long)c) & 1;
77 static inline struct command *SET_RANGE(struct command *c)
79 return (struct command *)(((unsigned long)c) | 1UL);
85 int len = ci->str ? strlen(ci->str) : 0;
88 if (ci->comm == &keymap_list)
89 /* should be impossible */
91 /* ci->comm MUST be the keymap */
92 m = (struct map* safe)ci->comm;
94 for (i = 0; i < m->size; i++)
95 if (!len || strncmp(ci->str, m->keys[i], len) == 0)
96 if (comm_call(ci->comm2, "cb", ci->focus,
97 IS_RANGE(m->comms[i]), NULL, m->keys[i]) <= 0)
102 static int size2alloc(int size)
104 /* Alway multiple of 8. */
105 return ((size-1) | 7) + 1;
108 struct map *safe key_alloc(void)
110 struct map *m = calloc(1, sizeof(*m));
112 key_add(m, "keymap:list", &keymap_list);
116 void key_free(struct map *m safe)
119 for (i = 0; i < m->size; i++) {
121 command_put(GETCOMM(m->comms[i]));
128 static bool hash_str(const char *key safe, int len, unsigned int *hashes safe)
134 for (i = 0; (len < 0 || i < len) && key[i]; i++) {
135 h = qhash(key[i], h);
136 if (key[i] == '-' || key[i] == ':') {
142 for (; (len < 0 || i < len) && key[i]; i++)
143 h = qhash(key[i], h);
148 inline static void set_bit(unsigned long *set safe, int bit)
150 set[bit/(sizeof(unsigned long)*8)] |=
151 1UL << (bit % (sizeof(unsigned long)*8));
154 inline static int test_bit(unsigned long *set safe, int bit)
156 return !! (set[bit/(sizeof(unsigned long)*8)] &
157 (1UL << (bit % (sizeof(unsigned long)*8))));
160 static bool key_present(struct map *map safe, unsigned int *hashes safe)
164 map->check_all = False;
165 for (i = 0; i < map->size; i++) {
167 bool prefix = hash_str(map->keys[i], -1, h);
168 if (IS_RANGE(map->comms[i])) {
170 map->check_all = True;
171 set_bit(map->bloom, h[1]&0xff);
172 set_bit(map->bloom, (h[1]>>8)&0xff);
173 set_bit(map->bloom, (h[1]>>16)&0xff);
175 set_bit(map->bloom, h[0]&0xff);
176 set_bit(map->bloom, (h[0]>>8)&0xff);
177 set_bit(map->bloom, (h[0]>>16)&0xff);
180 map->changed = False;
185 if (test_bit(map->bloom, hashes[0]&0xff) &&
186 test_bit(map->bloom, (hashes[0]>>8)&0xff) &&
187 test_bit(map->bloom, (hashes[0]>>16)&0xff))
189 if (test_bit(map->bloom, hashes[1]&0xff) &&
190 test_bit(map->bloom, (hashes[1]>>8)&0xff) &&
191 test_bit(map->bloom, (hashes[1]>>16)&0xff))
196 /* Find first entry >= k */
197 static int key_find(struct map *map safe, const char *k safe)
202 /* all entries before 'lo' are < k.
203 * all entries at 'hi' or later are >= k.
204 * So when lo==hi, hi is the answer.
207 int mid = (hi + lo)/ 2;
208 if (strcmp(map->keys[mid], k) < 0)
216 void key_add(struct map *map safe, const char *k safe, struct command *comm)
220 struct command *comm2 = NULL;
225 if (strcmp(k, "Close") == 0 &&
227 LOG("WARNING: Command %s registered for \"Close\" but not marked closed_ok",
231 pos = key_find(map, k);
233 * 1/ match start of range: insert before
234 * 2/ match non-range start: replace
235 * 3/ not in range: insert before like 1
236 * 4/ in a range: insert match and range start.
238 if (pos >= map->size) {
239 /* Insert k,comm - default action */
240 } else if (strcmp(k, map->keys[pos]) == 0) {
241 /* match: need to check if range-start */
242 if (IS_RANGE(map->comms[pos])) {
243 /* Changing the start of a range,
244 * insert an exact match */
246 /* replace a non-range */
247 command_put(map->comms[pos]);
248 map->comms[pos] = command_get(comm);
251 } else if (pos > 0 && IS_RANGE(map->comms[pos-1])) {
252 /* insert within a range.
253 * Add given command as non-range match, and old command
256 comm2 = map->comms[pos-1];
258 /* Not in a range, simple insert */
261 ins_cnt = comm2 ? 2 : 1;
262 size = size2alloc(map->size + ins_cnt);
264 if (size2alloc(map->size) != size) {
265 map->keys = realloc(map->keys, size * sizeof(map->keys[0]));
266 map->comms = realloc(map->comms,
267 size * sizeof(struct command *));
270 memmove(map->keys+pos+ins_cnt, map->keys+pos,
271 (map->size - pos) * sizeof(map->keys[0]));
272 memmove(map->comms+pos+ins_cnt, map->comms+pos,
273 (map->size - pos) * sizeof(struct command *));
274 map->keys[pos] = strdup(k);
275 map->comms[pos] = command_get(comm);
277 map->keys[pos+1] = strdup(k);
278 map->comms[pos+1] = SET_RANGE(command_get(GETCOMM(comm2)));
280 map->size += ins_cnt;
284 void key_add_range(struct map *map safe,
285 const char *first safe, const char *last safe,
286 struct command *comm)
292 if (!comm || strcmp(first, last) >= 0)
295 /* Add the first entry using key_add */
296 key_add(map, first, comm);
297 pos = key_find(map, first);
298 pos2 = key_find(map, last);
300 /* Now 'pos' is a stand-alone entry for 'first'.
301 * If the entry before pos2 is a range start, update to start at 'last',
302 * else discard it, and discard everything else between pos and pos2.
303 * Then insert a stand-alone for 'last' and update 'pos' to be a
306 if (pos2 - 1 > pos && IS_RANGE(map->comms[pos2-1])) {
307 free(map->keys[pos2-1]);
308 map->keys[pos2-1] = strdup(last);
311 /* Need to insert 'last', and remove extras. so +1 and -(pos2-pos-1); */
312 move_size = 1 - (pos2 - pos - 1);
313 size = size2alloc(map->size + move_size);
314 if (size2alloc(map->size) < size) {
315 map->keys = realloc(map->keys, size * sizeof(map->keys[0]));
316 map->comms = realloc(map->comms,
317 size * sizeof(struct command *));
319 for (i = pos + 1; i < pos2; i++) {
321 command_put(GETCOMM(map->comms[i]));
323 memmove(map->keys+pos2 + move_size, map->keys+pos2,
324 (map->size - pos2) * sizeof(map->keys[0]));
325 memmove(map->comms+pos2+ move_size, map->comms+pos2,
326 (map->size - pos2) * sizeof(struct command *));
328 map->comms[pos] = SET_RANGE(comm);
329 map->keys[pos+1] = strdup(last);
330 map->comms[pos+1] = command_get(comm);
331 map->size += move_size;
335 void key_add_chain(struct map *map safe, struct map *chain)
343 void key_del(struct map *map, wint_t k)
347 pos = key_find(map, k, -1);
348 if (pos >= map->size || strcmp(map->keys[pos], k) == 0)
351 memmove(map->keys+pos, map->keys+pos+1,
352 (map->size-pos-1) * sizeof(map->keys[0]));
353 memmove(map->comms+pos, map->comms+pos+1,
354 (map->size-pos-1) * sizeof(struct command *));
360 int key_pfx_func(const struct cmd_info *ci safe)
362 struct pfx_cmd *m = container_of(ci->comm, struct pfx_cmd, c);
364 call("Mode:set-all", ci->focus, ci->num, NULL, m->pfx, ci->num2);
368 struct command *key_lookup_cmd(struct map *m safe, const char *c safe)
370 int pos = key_find(m, c);
374 else if (strcmp(m->keys[pos], c) == 0)
375 /* Exact match - use this entry */
376 return GETCOMM(m->comms[pos]);
377 else if (pos > 0 && IS_RANGE(m->comms[pos-1]))
378 /* In a range, use previous */
379 return GETCOMM(m->comms[pos-1]);
384 /* FIXME this makes lots of things non re-entrant */
385 static struct backtrace {
386 struct command *comm safe;
387 const struct cmd_info *ci safe;
388 struct backtrace *prev;
390 static int backtrace_depth;
392 static char *mark_info(struct mark *m)
397 asprintf(&ret, "M-");
400 if (!mark_valid(m)) {
401 asprintf(&ret, "M-FREED");
404 ret = pane_call_ret(str, m->owner, "doc:debug:mark",
409 asprintf(&ret, "M:%d<%p>%d", m->seq, m, m->ref.i);
415 struct backtrace *bt;
416 LOG("Start Backtrace:");
417 for (bt = backtrace; bt; bt = bt->prev) {
418 const struct cmd_info *ci = bt->ci;
419 struct command *h = ci->home->handle;
420 struct command *f = ci->focus->handle;
421 char *m1 = mark_info(ci->mark);
422 char *m2 = mark_info(ci->mark2);
424 LOG(" H:%s \"%s\" F:%s: %d %s \"%s\" %d %s \"%s\" (%d,%d) %s",
428 ci->num, m1, ci->str,
429 ci->num2, m2, ci->str2,
431 ci->comm2 ? ci->comm2->name : "");
435 LOG("End Backtrace");
438 int do_comm_call(struct command *comm safe, const struct cmd_info *ci safe)
443 if (ci->home->damaged & DAMAGED_DEAD)
445 if (times_up_fast(ci->home))
447 if ((ci->home->damaged & DAMAGED_CLOSED) &&
451 if (backtrace_depth > 100) {
453 LOG("Recursion limit of 100 reached");
455 backtrace_depth = 100;
456 pane_root(ci->home)->timestamp = 1;
463 backtrace_depth += 1;
464 ret = comm->func(ci);
466 backtrace_depth -= 1;
470 int key_lookup(struct map *m safe, const struct cmd_info *ci safe)
472 struct command *comm;
474 if (ci->hash && !key_present(m, ci->hash)) {
475 stat_count("bloom-miss");
479 comm = key_lookup_cmd(m, ci->key);
481 stat_count("bloom-hit-bad");
484 stat_count("bloom-hit-good");
485 ((struct cmd_info*)ci)->comm = comm;
487 if (comm->func == keymap_list_func)
488 ((struct cmd_info*)ci)->comm = (struct command *safe)m;
490 return do_comm_call(comm, ci);
494 int key_lookup_prefix(struct map *m safe, const struct cmd_info *ci safe,
497 /* A "Simple" lookup avoids the backtrace. It is used in
500 const char *k = ci->key;
502 int pos = key_find(m, k);
503 struct command *comm, *prev = NULL;
504 int ret = Efallthrough;
508 ret == Efallthrough && pos+i < m->size &&
509 strncmp(m->keys[pos+i], k, len) == 0;
511 comm = GETCOMM(m->comms[pos+i]);
512 if (comm && comm != prev) {
513 ((struct cmd_info*)ci)->comm = comm;
514 ((struct cmd_info*)ci)->key = m->keys[pos+i];
516 ret = comm->func(ci);
518 ret = do_comm_call(comm, ci);
519 ASSERT(ret >= Efallthrough || ret < Eunused);
521 /* something might have been added, recalc
524 pos = key_find(m, k);
527 ((struct cmd_info*)ci)->key = k;
531 int key_lookup_cmd_func(const struct cmd_info *ci safe)
533 struct lookup_cmd *l = container_of(ci->comm, struct lookup_cmd, c);
534 struct map *m = safe_cast *l->m;
535 int ret = key_lookup(m, ci);
537 while (!ret && m->chain) {
539 ret = key_lookup(m, ci);
544 /* key_handle. Search towards root for the pane which handles the command.
546 int key_handle(const struct cmd_info *ci safe)
548 struct cmd_info *vci = (struct cmd_info*)ci;
550 unsigned int hash[2];
552 if (ci->mark && !mark_valid(ci->mark))
554 if (ci->mark2 && !mark_valid(ci->mark2))
557 if (times_up(ci->home))
559 time_start_key(ci->key);
560 if ((void*) ci->comm) {
561 int ret = do_comm_call(ci->comm, ci);
562 time_stop_key(ci->key);
566 hash_str(ci->key, -1, hash);
569 /* If 'home' is set, search from there, else search
577 int ret = Efallthrough;
579 (p->handle->closed_ok ||
580 !(p->damaged & DAMAGED_CLOSED))) {
582 vci->comm = p->handle;
583 /* Don't add this to the call stack as it
584 * should simply call the desired function and
585 * that will appear on the call stack.
587 ret = p->handle->func(ci);
589 if (ret != Efallthrough) {
590 time_stop_key(ci->key);
591 /* 'p' might have been destroyed */
599 time_stop_key(ci->key);