summaryrefslogtreecommitdiffstats
path: root/key-bindings.c
diff options
context:
space:
mode:
authornicm <nicm>2015-04-20 15:34:56 +0000
committernicm <nicm>2015-04-20 15:34:56 +0000
commitbded7437064c76dd6cf4e76e558d826859adcc79 (patch)
tree708c5dee6ddf671161b5ffa7208cba05e52eb4c5 /key-bindings.c
parent3497843f0272e573d0a63cb6e94948591ae07667 (diff)
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.
Diffstat (limited to 'key-bindings.c')
-rw-r--r--key-bindings.c112
1 files changed, 85 insertions, 27 deletions
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,