*) Merged key_binding_map_{value|entry}, now key_table
*) Renamed key_binding_map to key_tables
*) Fixed backward -n in unbind-key
*) Inlined/rearranged bind-key last three code paths
Keith
---
cmd-bind-key.c | 16 +++++--
cmd-list-keys.c | 80 +++++++++++++++----------------
cmd-switch-client.c | 15 +++++-
cmd-unbind-key.c | 27 +++++++----
format.c | 3 +-
key-bindings.c | 136 +++++++++++++++++++++++++++++++++++++++++-----------
server-client.c | 127 ++++++++++++++++++++++++++++--------------------
server-fn.c | 7 +++
tmux.1 | 37 ++++++++++++++
tmux.h | 37 ++++++++++----
10 files changed, 341 insertions(+), 144 deletions(-)
diff --git a/cmd-bind-key.c b/cmd-bind-key.c
index 27a03ce11ad7..1d815850db6c 100644
--- a/cmd-bind-key.c
+++ b/cmd-bind-key.c
@@ -33,8 +33,8 @@ enum cmd_retval cmd_bind_mode_key_table(struct cmd *,
struct cmd_q *, int);
const struct cmd_entry cmd_bind_key_entry = {
"bind-key", "bind",
- "cnrt:", 1, -1,
- "[-cnr] [-t mode-key-table] key command [arguments]",
+ "cnrt:T:", 1, -1,
+ "[-cnr] [-t mode-key-table] [-T key-table] key command [arguments]",
0,
NULL,
cmd_bind_key_exec
@@ -47,6 +47,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
char *cause;
struct cmd_list *cmdlist;
int key;
+ const char *table;
if (args_has(args, 't')) {
if (args->argc != 2 && args->argc != 3) {
@@ -69,6 +70,13 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
if (args_has(args, 't'))
return (cmd_bind_mode_key_table(self, cmdq, key));
+ if (args_has(args, 'T'))
+ table = args_get(args, 'T');
+ else if (args_has(args, 'n'))
+ table = "root";
+ else
+ table = "prefix";
+
cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1, NULL, 0,
&cause);
if (cmdlist == NULL) {
@@ -77,9 +85,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
- if (!args_has(args, 'n'))
- key |= KEYC_PREFIX;
- key_bindings_add(key, args_has(args, 'r'), cmdlist);
+ key_bindings_add(table, key, args_has(args, 'r'), cmdlist);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-list-keys.c b/cmd-list-keys.c
index 615c5ce1fe67..7e4472283e33 100644
--- a/cmd-list-keys.c
+++ b/cmd-list-keys.c
@@ -41,56 +41,56 @@ const struct cmd_entry cmd_list_keys_entry = {
enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
{
- struct args *args = self->args;
- struct key_binding *bd;
- const char *key;
- char tmp[BUFSIZ], flags[8];
- size_t used;
- int width, keywidth;
+ struct args *args = self->args;
+ struct key_table *table;
+ struct key_binding *bd;
+ const char *key;
+ char tmp[BUFSIZ];
+ size_t used;
+ int hasrepeat, maxtablewidth, tablewidth,
maxkeywidth, keywidth;
if (args_has(args, 't'))
return (cmd_list_keys_table(self, cmdq));
- width = 0;
+ hasrepeat = 0;
+ maxtablewidth = 0;
+ maxkeywidth = 0;
- RB_FOREACH(bd, key_bindings, &key_bindings) {
- key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
- if (key == NULL)
- continue;
+ RB_FOREACH(table, key_tables, &key_tables) {
+ RB_FOREACH(bd, key_bindings, &(table->key_bindings)) {
+ key = key_string_lookup_key(bd->key);
+ if (key == NULL)
+ continue;
- keywidth = strlen(key);
- if (!(bd->key & KEYC_PREFIX)) {
if (bd->can_repeat)
- keywidth += 4;
- else
- keywidth += 3;
- } else if (bd->can_repeat)
- keywidth += 3;
- if (keywidth > width)
- width = keywidth;
- }
+ hasrepeat = 1;
- RB_FOREACH(bd, key_bindings, &key_bindings) {
- key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
- if (key == NULL)
- continue;
+ tablewidth = strlen(table->name);
+ if (tablewidth > maxtablewidth)
+ maxtablewidth = tablewidth;
- *flags = '\0';
- if (!(bd->key & KEYC_PREFIX)) {
- if (bd->can_repeat)
- xsnprintf(flags, sizeof flags, "-rn ");
- else
- xsnprintf(flags, sizeof flags, "-n ");
- } else if (bd->can_repeat)
- xsnprintf(flags, sizeof flags, "-r ");
-
- used = xsnprintf(tmp, sizeof tmp, "%s%*s ",
- flags, (int) (width - strlen(flags)), key);
- if (used >= sizeof tmp)
- continue;
+ keywidth = strlen(key);
+ if (keywidth > maxkeywidth)
+ maxkeywidth = keywidth;
+ }
+ }
- cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used);
- cmdq_print(cmdq, "bind-key %s", tmp);
+ RB_FOREACH(table, key_tables, &key_tables) {
+ RB_FOREACH(bd, key_bindings, &(table->key_bindings)) {
+ key = key_string_lookup_key(bd->key);
+ if (key == NULL)
+ continue;
+
+ used = xsnprintf(tmp, sizeof tmp, "%s-T %-*s %-*s ",
+ (hasrepeat ? (bd->can_repeat ? "-r " : " ") :
""),
+ (int) maxtablewidth, table->name,
+ (int) maxkeywidth, key);
+ if (used >= sizeof tmp)
+ continue;
+
+ cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) -
used);
+ cmdq_print(cmdq, "bind-key %s", tmp);
+ }
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index 9e7967cd4e3d..11b8b283786d 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -32,8 +32,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *,
struct cmd_q *);
const struct cmd_entry cmd_switch_client_entry = {
"switch-client", "switchc",
- "lc:npt:r", 0, 0,
- "[-lnpr] [-c target-client] [-t target-session]",
+ "lc:npt:rT:", 0, 0,
+ "[-lnpr] [-c target-client] [-t target-session] [-T key-table]",
CMD_READONLY,
cmd_switch_client_key_binding,
cmd_switch_client_exec
@@ -66,6 +66,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w = NULL;
struct window_pane *wp = NULL;
const char *tflag;
+ struct key_table *table;
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
@@ -77,6 +78,16 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq)
c->flags |= CLIENT_READONLY;
}
+ if (args_has(args, 'T')) {
+ table = key_bindings_lookup_table(args_get(args, 'T'), 0);
+ if (!table) {
+ cmdq_error(cmdq, "table %s doesn't exist",
args_get(args, 'T'));
+ return (CMD_RETURN_ERROR);
+ }
+ key_bindings_unreference_table(c->keytable);
+ c->keytable = table;
+ }
+
tflag = args_get(args, 't');
if (args_has(args, 'n')) {
if ((s = session_next_session(c->session)) == NULL) {
diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c
index 1c4decb46b98..0adb41de531e 100644
--- a/cmd-unbind-key.c
+++ b/cmd-unbind-key.c
@@ -31,8 +31,8 @@ enum cmd_retval cmd_unbind_mode_key_table(struct cmd
*, struct cmd_q *, int);
const struct cmd_entry cmd_unbind_key_entry = {
"unbind-key", "unbind",
- "acnt:", 0, 1,
- "[-acn] [-t mode-key-table] key",
+ "acnt:T:", 0, 1,
+ "[-acn] [-t mode-key-table] [-T key-table] key",
0,
NULL,
cmd_unbind_key_exec
@@ -42,7 +42,6 @@ enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- struct key_binding *bd;
int key;
if (!args_has(args, 'a')) {
@@ -67,16 +66,26 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq)
return (cmd_unbind_mode_key_table(self, cmdq, key));
if (key == KEYC_NONE) {
- while (!RB_EMPTY(&key_bindings)) {
- bd = RB_ROOT(&key_bindings);
- key_bindings_remove(bd->key);
+ if (args_has(args, 'T')) {
+ key_bindings_remove_table(args_get(args, 'T'));
+ return (CMD_RETURN_NORMAL);
}
+ key_bindings_remove_table("root");
+ key_bindings_remove_table("prefix");
return (CMD_RETURN_NORMAL);
}
- if (!args_has(args, 'n'))
- key |= KEYC_PREFIX;
- key_bindings_remove(key);
+ if (args_has(args, 'T')) {
+ key_bindings_remove(args_get(args, 'T'), key);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (args_has(args, 'n')) {
+ key_bindings_remove("root", key);
+ return (CMD_RETURN_NORMAL);
+ }
+
+ key_bindings_remove("prefix", key);
return (CMD_RETURN_NORMAL);
}
diff --git a/format.c b/format.c
index 6f988b9ac2cc..8630aabed5d7 100644
--- a/format.c
+++ b/format.c
@@ -435,7 +435,8 @@ format_client(struct format_tree *ft, struct client *c)
*strchr(tim, '\n') = '\0';
format_add(ft, "client_activity_string", "%s", tim);
- format_add(ft, "client_prefix", "%d", !!(c->flags & CLIENT_PREFIX));
+ format_add(ft, "client_prefix", strcmp(c->keytable->name, "root") ?
"1": "0");
+ format_add(ft, "client_keytablename", "%s", c->keytable->name);
if (c->tty.flags & TTY_UTF8)
format_add(ft, "client_utf8", "%d", 1);
diff --git a/key-bindings.c b/key-bindings.c
index 58be0c6fe896..d391744a1bff 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -24,61 +24,143 @@
#include "tmux.h"
+struct key_table *key_bindings_lookup_table_noref(const char *, int);
+
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;
-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_lookup_table_noref(const char *name, int create)
{
- struct key_binding bd;
+ struct key_table table_search;
+ struct key_table *table;
- bd.key = key;
- return (RB_FIND(key_bindings, &key_bindings, &bd));
+ table_search.name = name;
+ table = RB_FIND(key_tables, &key_tables, &table_search);
+ if (table)
+ return table;
+
+ if (!create)
+ return NULL;
+
+ table = xmalloc(sizeof *table);
+ table->name = table->name_for_free = xstrdup(name);
+ RB_INIT(&(table->key_bindings));
+ /* for key_tables */
+ table->references = 1;
+ RB_INSERT(key_tables, &key_tables, table);
+
+ return table;
+}
+
+struct key_table *
+key_bindings_lookup_table(const char *name, int create)
+{
+ struct key_table *table;
+
+ table = key_bindings_lookup_table_noref(name, create);
+ if (!table)
+ return NULL;
+
+ table->references++;
+ return table;
}
void
-key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
+key_bindings_unreference_table(struct key_table *table)
{
struct key_binding *bd;
- key_bindings_remove(key);
+ if (--table->references == 0) {
+ 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(table->name_for_free);
+ 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_search;
+ struct key_binding *bd;
+
+ table = key_bindings_lookup_table_noref(name, 1);
+
+ bd_search.key = key;
+ bd = RB_FIND(key_bindings, &(table->key_bindings), &bd_search);
+ 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_search;
+ struct key_binding *bd;
- if ((bd = key_bindings_lookup(key)) == NULL)
+ table = key_bindings_lookup_table_noref(name, 0);
+ if (!table)
return;
- RB_REMOVE(key_bindings, &key_bindings, bd);
+
+ bd_search.key = key;
+ bd = RB_FIND(key_bindings, &(table->key_bindings), &bd_search);
+ if (!bd)
+ return;
+
+ 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);
+ /* This represents key_tables's reference */
+ key_bindings_unreference_table(table);
+ }
+}
+
+void
+key_bindings_remove_table(const char *name)
+{
+ struct key_table *table;
+
+ table = key_bindings_lookup_table_noref(name, 0);
+ if (!table)
+ return;
+
+ RB_REMOVE(key_tables, &key_tables, table);
+ /* This represents key_tables's reference */
+ key_bindings_unreference_table(table);
}
void
@@ -167,7 +249,7 @@ key_bindings_init(void)
struct cmd *cmd;
struct cmd_list *cmdlist;
- RB_INIT(&key_bindings);
+ RB_INIT(&key_tables);
for (i = 0; i < nitems(table); i++) {
cmdlist = xcalloc(1, sizeof *cmdlist);
@@ -183,7 +265,7 @@ key_bindings_init(void)
TAILQ_INSERT_HEAD(&cmdlist->list, cmd, qentry);
key_bindings_add(
- table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist);
+ "prefix", table[i].key, table[i].can_repeat, cmdlist);
}
}
diff --git a/server-client.c b/server-client.c
index e225de309b5f..a979e3573b85 100644
--- a/server-client.c
+++ b/server-client.c
@@ -98,6 +98,7 @@ server_client_create(int fd)
c->tty.mouse.flags = 0;
c->flags |= CLIENT_FOCUSED;
+ c->keytable = key_bindings_lookup_table("root", 1);
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
@@ -170,6 +171,8 @@ server_client_lost(struct client *c)
evtimer_del(&c->repeat_timer);
+ key_bindings_unreference_table(c->keytable);
+
if (event_initialized(&c->identify_timer))
evtimer_del(&c->identify_timer);
@@ -360,12 +363,14 @@ server_client_assume_paste(struct session *s)
void
server_client_handle_key(struct client *c, int key)
{
- struct session *s;
- struct window *w;
- struct window_pane *wp;
- struct timeval tv;
- struct key_binding *bd;
- int xtimeout, isprefix, ispaste;
+ struct session *s;
+ struct window *w;
+ struct window_pane *wp;
+ struct timeval tv;
+ struct key_table *table;
+ struct key_binding bd_search;
+ struct key_binding *bd;
+ int xtimeout, isprefix, ispaste;
/* Check the client is good to accept input. */
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
@@ -427,64 +432,82 @@ server_client_handle_key(struct client *c, int key)
/* Treat prefix as a regular key when pasting is detected. */
ispaste = server_client_assume_paste(s);
- if (ispaste)
- isprefix = 0;
+ if (ispaste) {
+ if (!(c->flags & CLIENT_READONLY))
+ window_pane_key(wp, s, key);
+ return;
+ }
+
+ /* Try to see if we hit a key binding. */
+ for (;;) {
+ bd_search.key = key;
+ if ((bd = RB_FIND(key_bindings, &(c->keytable->key_bindings),
&bd_search)) != NULL) {
+ if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) {
+ /* We don't honor repeating into a non-repeat
binding, fall back to root and try again */
+ server_keytable_client(c, "root");
+ c->flags &= ~CLIENT_REPEAT;
+ server_status_client(c);
+ continue;
+ }
+
+ /* Hold a reference to this table to make sure the key
binding doesn't disappear */
+ table = c->keytable;
+ table->references++;
+
+ xtimeout = options_get_number(&s->options,
"repeat-time");
+ if (xtimeout != 0 && bd->can_repeat) {
+ /* Now repeating in same keytable */
+ c->flags |= CLIENT_REPEAT;
+
+ tv.tv_sec = xtimeout / 1000;
+ tv.tv_usec = (xtimeout % 1000) * 1000L;
+ evtimer_del(&c->repeat_timer);
+ evtimer_add(&c->repeat_timer, &tv);
+ }
+ else {
+ /* "Stop" (or don't start) repeating */
+ c->flags &= ~CLIENT_REPEAT;
+ server_keytable_client(c, "root");
+ }
- /* No previous prefix key. */
- if (!(c->flags & CLIENT_PREFIX)) {
- if (isprefix) {
- c->flags |= CLIENT_PREFIX;
server_status_client(c);
+ key_bindings_dispatch(bd, c);
+
+ key_bindings_unreference_table(table);
return;
}
- /* Try as a non-prefix key binding. */
- if (ispaste || (bd = key_bindings_lookup(key)) == NULL) {
- if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
- } else
- key_bindings_dispatch(bd, c);
- return;
- }
-
- /* Prefix key already pressed. Reset prefix and lookup key. */
- c->flags &= ~CLIENT_PREFIX;
- server_status_client(c);
- if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
- /* If repeating, treat this as a key, else ignore. */
if (c->flags & CLIENT_REPEAT) {
+ /* We missed, but we were in repeat, fall back to root
and try again */
+ server_keytable_client(c, "root");
c->flags &= ~CLIENT_REPEAT;
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
+ server_status_client(c);
+ continue;
}
- return;
+
+ /* Actual miss */
+ break;
}
- /* If already repeating, but this key can't repeat, skip it. */
- if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
- c->flags &= ~CLIENT_REPEAT;
- if (isprefix)
- c->flags |= CLIENT_PREFIX;
- else if (!(c->flags & CLIENT_READONLY))
- window_pane_key(wp, s, key);
+ /* A miss in a non-root keytable fails out to root */
+ if (strcmp(c->keytable->name, "root")) {
+ server_keytable_client(c, "root");
+ server_status_client(c);
return;
}
- /* If this key can repeat, reset the repeat flags and timer. */
- xtimeout = options_get_number(&s->options, "repeat-time");
- if (xtimeout != 0 && bd->can_repeat) {
- c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
-
- tv.tv_sec = xtimeout / 1000;
- tv.tv_usec = (xtimeout % 1000) * 1000L;
- evtimer_del(&c->repeat_timer);
- evtimer_add(&c->repeat_timer, &tv);
+ /* A prefix miss in root switched to prefix */
+ if (isprefix) {
+ /* Prefix key switches to prefix table */
+ server_keytable_client(c, "prefix");
+ server_status_client(c);
+ return;
}
- /* Dispatch the command. */
- key_bindings_dispatch(bd, c);
+ /* Anything else in root is straight through */
+ if (!(c->flags & CLIENT_READONLY)) {
+ window_pane_key(wp, s, key);
+ }
}
/* Client functions that need to happen every loop. */
@@ -700,9 +723,9 @@ server_client_repeat_timer(unused int fd, unused short
events, void *data)
struct client *c = data;
if (c->flags & CLIENT_REPEAT) {
- if (c->flags & CLIENT_PREFIX)
- server_status_client(c);
- c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
+ server_keytable_client(c, "root");
+ c->flags &= ~CLIENT_REPEAT;
+ server_status_client(c);
}
}
diff --git a/server-fn.c b/server-fn.c
index e0859f707034..6f3491693d76 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -101,6 +101,13 @@ server_status_client(struct client *c)
}
void
+server_keytable_client(struct client *c, const char *name)
+{
+ key_bindings_unreference_table(c->keytable);
+ c->keytable = key_bindings_lookup_table(name, 1);
+}
+
+void
server_redraw_session(struct session *s)
{
struct client *c;
diff --git a/tmux.1 b/tmux.1
index 7fd26cd7a199..e19904a2c8cc 100644
--- a/tmux.1
+++ b/tmux.1
@@ -808,6 +808,7 @@ Suspend a client by sending
.Op Fl lnpr
.Op Fl c Ar target-client
.Op Fl t Ar target-session
+.Op Fl T Ar key-table
.Xc
.D1 (alias: Ic switchc )
Switch the current session for client
@@ -825,6 +826,9 @@ respectively.
toggles whether a client is read-only (see the
.Ic attach-session
command).
+.Fl T
+sets the client's key table; the next key from the client will be interpretted
from
+.Ar key-table .
.El
.Sh WINDOWS AND PANES
A
@@ -1843,6 +1847,7 @@ Commands related to key bindings are as follows:
.It Xo Ic bind-key
.Op Fl cnr
.Op Fl t Ar mode-key-table
+.Op Fl T Ar key-table
.Ar key Ar command Op Ar arguments
.Xc
.D1 (alias: Ic bind )
@@ -1878,6 +1883,21 @@ or for normal mode without.
To view the default bindings and possible commands, see the
.Ic list-keys
command.
+.Pp
+If
+.Fl T
+is present,
+.Ar key
+is bound in
+.Ar key-table :
+.Em prefix
+corresponds to the default,
+.Em root
+corresponds to
+.Fl n ,
+and custom values may be used with
+.Ic switch-client
+.Fl T .
.It Ic list-keys Op Fl t Ar key-table
.D1 (alias: Ic lsk )
List all key bindings.
@@ -1930,6 +1950,7 @@ the secondary prefix key, to a window as if it was
pressed.
.It Xo Ic unbind-key
.Op Fl acn
.Op Fl t Ar mode-key-table
+.Op Fl T Ar key-table
.Ar key
.Xc
.D1 (alias: Ic unbind )
@@ -1955,6 +1976,22 @@ in
is unbound: the binding for command mode with
.Fl c
or for normal mode without.
+.Pp
+If
+.Fl T
+is present,
+.Ar key
+in
+.Ar key-table
+is unbound:
+.Em prefix
+corresponds to the default,
+.Em root
+corresponds to
+.Fl n ,
+and custom values may be used with
+.Ic switch-client
+.Fl T .
.El
.Sh OPTIONS
The appearance and behaviour of
diff --git a/tmux.h b/tmux.h
index f9d6087ab714..dcd2c8d25f44 100644
--- a/tmux.h
+++ b/tmux.h
@@ -164,10 +164,9 @@ extern char **environ;
#define KEYC_ESCAPE 0x2000
#define KEYC_CTRL 0x4000
#define KEYC_SHIFT 0x8000
-#define KEYC_PREFIX 0x10000
/* Mask to obtain key w/o modifiers. */
-#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT|KEYC_PREFIX)
+#define KEYC_MASK_MOD (KEYC_ESCAPE|KEYC_CTRL|KEYC_SHIFT)
#define KEYC_MASK_KEY (~KEYC_MASK_MOD)
/* Other key codes. */
@@ -1298,7 +1297,7 @@ struct client {
struct screen status;
#define CLIENT_TERMINAL 0x1
-#define CLIENT_PREFIX 0x2
+/* replaced by keytablename: #define CLIENT_PREFIX 0x2 */
#define CLIENT_EXIT 0x4
#define CLIENT_REDRAW 0x8
#define CLIENT_STATUS 0x10
@@ -1317,6 +1316,7 @@ struct client {
#define CLIENT_256COLOURS 0x20000
#define CLIENT_IDENTIFIED 0x40000
int flags;
+ struct key_table *keytable;
struct event identify_timer;
@@ -1444,6 +1444,22 @@ struct key_binding {
RB_ENTRY(key_binding) entry;
};
RB_HEAD(key_bindings, key_binding);
+struct key_table {
+ /*
+ * Search needs to be able to use const char * and free needs to be
+ * able to free the name we allocated when we put it in the tree for
+ * real. Search and keying is done by name, free is done with
+ * name_for_free.
+ */
+ const char *name;
+ char *name_for_free;
+ struct key_bindings key_bindings;
+
+ u_int references;
+
+ RB_ENTRY(key_table) entry;
+};
+RB_HEAD(key_tables, key_table);
/*
* Option table entries. The option table is the user-visible part of the
@@ -1865,12 +1881,16 @@ int cmd_string_parse(const char *, struct cmd_list
**, const char *,
int client_main(int, char **, int);
/* key-bindings.c */
-extern struct key_bindings key_bindings;
-int key_bindings_cmp(struct key_binding *, struct key_binding *);
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
-struct key_binding *key_bindings_lookup(int);
-void key_bindings_add(int, int, struct cmd_list *);
-void key_bindings_remove(int);
+RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp);
+extern struct key_tables key_tables;
+int key_table_cmp(struct key_table *, struct key_table *);
+int key_bindings_cmp(struct key_binding *, struct key_binding *);
+struct key_table *key_bindings_lookup_table(const char *, int);
+void key_bindings_unreference_table(struct key_table *);
+void key_bindings_add(const char *, int, int, struct cmd_list *);
+void key_bindings_remove(const char *, int);
+void key_bindings_remove_table(const char *);
void key_bindings_init(void);
void key_bindings_dispatch(struct key_binding *, struct client *);
@@ -1906,6 +1926,7 @@ void server_write_session(struct session *, enum
msgtype, const void *,
size_t);
void server_redraw_client(struct client *);
void server_status_client(struct client *);
+void server_keytable_client(struct client *, const char *);
void server_redraw_session(struct session *);
void server_redraw_session_group(struct session *);
void server_status_session(struct session *);
--
1.9.1
------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
tmux-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users