From bded7437064c76dd6cf4e76e558d826859adcc79 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 20 Apr 2015 15:34:56 +0000 Subject: Support for multiple key tables to commands to be bound to sequences of keys. The default key bindings become the "prefix" table and -n the "root" table. Keys may be bound in new tables with bind -T and switch-client -T used to specify the table in which the next key should be looked up. Based on a diff from Keith Amling. --- key-bindings.c | 112 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 27 deletions(-) (limited to 'key-bindings.c') diff --git a/key-bindings.c b/key-bindings.c index c6cdeeb7..c34db710 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -25,60 +25,120 @@ #include "tmux.h" RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); +RB_GENERATE(key_tables, key_table, entry, key_table_cmp); +struct key_tables key_tables = RB_INITIALIZER(&key_tables); -struct key_bindings key_bindings; +int +key_table_cmp(struct key_table *e1, struct key_table *e2) +{ + return (strcmp(e1->name, e2->name)); +} int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) { - int key1, key2; - - key1 = bd1->key & ~KEYC_PREFIX; - key2 = bd2->key & ~KEYC_PREFIX; - if (key1 != key2) - return (key1 - key2); - - if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX)) - return (-1); - if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX)) - return (1); - return (0); + return (bd1->key - bd2->key); } -struct key_binding * -key_bindings_lookup(int key) +struct key_table * +key_bindings_get_table(const char *name, int create) { - struct key_binding bd; + struct key_table table_find, *table; + + table_find.name = name; + table = RB_FIND(key_tables, &key_tables, &table_find); + if (table != NULL || !create) + return (table); - bd.key = key; - return (RB_FIND(key_bindings, &key_bindings, &bd)); + table = xmalloc(sizeof *table); + table->name = xstrdup(name); + RB_INIT(&table->key_bindings); + + table->references = 1; /* one reference in key_tables */ + RB_INSERT(key_tables, &key_tables, table); + + return (table); } void -key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) +key_bindings_unref_table(struct key_table *table) { struct key_binding *bd; - key_bindings_remove(key); + if (--table->references != 0) + return; + + while (!RB_EMPTY(&table->key_bindings)) { + bd = RB_ROOT(&table->key_bindings); + RB_REMOVE(key_bindings, &table->key_bindings, bd); + cmd_list_free(bd->cmdlist); + free(bd); + } + + free((void *)table->name); + free(table); +} + +void +key_bindings_add(const char *name, int key, int can_repeat, + struct cmd_list *cmdlist) +{ + struct key_table *table; + struct key_binding bd_find, *bd; + + table = key_bindings_get_table(name, 1); + + bd_find.key = key; + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); + if (bd != NULL) { + RB_REMOVE(key_bindings, &table->key_bindings, bd); + cmd_list_free(bd->cmdlist); + free(bd); + } bd = xmalloc(sizeof *bd); bd->key = key; - RB_INSERT(key_bindings, &key_bindings, bd); + RB_INSERT(key_bindings, &table->key_bindings, bd); bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } void -key_bindings_remove(int key) +key_bindings_remove(const char *name, int key) { - struct key_binding *bd; + struct key_table *table; + struct key_binding bd_find, *bd; + + table = key_bindings_get_table(name, 0); + if (table == NULL) + return; - if ((bd = key_bindings_lookup(key)) == NULL) + bd_find.key = key; + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); + if (bd == NULL) return; - RB_REMOVE(key_bindings, &key_bindings, bd); + + RB_REMOVE(key_bindings, &table->key_bindings, bd); cmd_list_free(bd->cmdlist); free(bd); + + if (RB_EMPTY(&table->key_bindings)) { + RB_REMOVE(key_tables, &key_tables, table); + key_bindings_unref_table(table); + } +} + +void +key_bindings_remove_table(const char *name) +{ + struct key_table *table; + + table = key_bindings_get_table(name, 0); + if (table != NULL) { + RB_REMOVE(key_tables, &key_tables, table); + key_bindings_unref_table(table); + } } void @@ -169,8 +229,6 @@ key_bindings_init(void) int error; struct cmd_q *cmdq; - RB_INIT(&key_bindings); - cmdq = cmdq_new(NULL); for (i = 0; i < nitems(defaults); i++) { error = cmd_string_parse(defaults[i], &cmdlist, -- cgit v1.2.3