It needs a bit of love again after the mouse keys stuff that just went
in so it may not be for a while...


On Sun, Apr 19, 2015 at 10:45:38PM +0100, Nicholas Marriott wrote:
> We don't need a merge request, I'll commit it when I'm happy with it. Thanks
> 
> 
> On Sun, Apr 19, 2015 at 06:49:30PM +0000, Ross Hadden wrote:
> >    Would you mind making a merge request for it?** I could, but it wouldn't
> >    really be right to make a merge request with someone else's hard work!**
> >    Your name should be on this.
> >    Thanks,
> >    ~Ross
> >    On Mon, Apr 13, 2015 at 5:30 PM Nicholas Marriott
> >    <[1]nicholas.marri...@gmail.com> wrote:
> > 
> >      Here's the latest diff.
> > 
> >      It actually seems to work fine, although I haven't done a lot of
> >      testing.
> > 
> >      IIRC I wasn't wild about the cmd-list-keys.c and cmd-bind-key.c 
> > changes;
> >      certainly lsk -T should error on an unknown table, same as bind -T. I
> >      think the manpage bits could do with some improvement too.
> > 
> >      Index: cmd-bind-key.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/cmd-bind-key.c,v
> >      retrieving revision 1.20
> >      diff -u -p -r1.20 cmd-bind-key.c
> >      --- cmd-bind-key.c** ** ** 10 Apr 2015 16:00:08 -0000** ** ** 1.20
> >      +++ cmd-bind-key.c** ** ** 13 Apr 2015 21:29:21 -0000
> >      @@ -33,8 +33,8 @@ enum cmd_retval** ** ** ** cmd_bind_key_mode_table
> > 
> >      **const struct cmd_entry cmd_bind_key_entry = {
> >      ** ** ** ** "bind-key", "bind",
> >      -** ** ** **"cnrt:", 1, -1,
> >      -** ** ** **"[-cnr] [-t mode-table] key command [arguments]",
> >      +** ** ** **"cnrt:T:", 1, -1,
> >      +** ** ** **"[-cnr] [-t mode-table] [-T key-table] key command
> >      [arguments]",
> >      ** ** ** ** 0,
> >      ** ** ** ** cmd_bind_key_exec
> >      **};
> >      @@ -46,6 +46,7 @@ cmd_bind_key_exec(struct cmd *self, stru
> >      ** ** ** ** char** ** ** ** ** ** *cause;
> >      ** ** ** ** struct cmd_list *cmdlist;
> >      ** ** ** ** int** ** ** ** ** ** ** key;
> >      +** ** ** **const char** ** ** *tablename;
> > 
> >      ** ** ** ** if (args_has(args, 't')) {
> >      ** ** ** ** ** ** ** ** if (args->argc != 2 && args->argc != 3) {
> >      @@ -68,6 +69,13 @@ cmd_bind_key_exec(struct cmd *self, stru
> >      ** ** ** ** if (args_has(args, 't'))
> >      ** ** ** ** ** ** ** ** return (cmd_bind_key_mode_table(self, cmdq,
> >      key));
> > 
> >      +** ** ** **if (args_has(args, 'T'))
> >      +** ** ** ** ** ** ** **tablename = args_get(args, 'T');
> >      +** ** ** **else if (args_has(args, 'n'))
> >      +** ** ** ** ** ** ** **tablename = "root";
> >      +** ** ** **else
> >      +** ** ** ** ** ** ** **tablename = "prefix";
> >      +
> >      ** ** ** ** cmdlist = cmd_list_parse(args->argc - 1, args->argv + 1,
> >      NULL, 0,
> >      ** ** ** ** ** ** &cause);
> >      ** ** ** ** if (cmdlist == NULL) {
> >      @@ -76,9 +84,7 @@ cmd_bind_key_exec(struct cmd *self, stru
> >      ** ** ** ** ** ** ** ** return (CMD_RETURN_ERROR);
> >      ** ** ** ** }
> > 
> >      -** ** ** **if (!args_has(args, 'n'))
> >      -** ** ** ** ** **key |= KEYC_PREFIX;
> >      -** ** ** **key_bindings_add(key, args_has(args, 'r'), cmdlist);
> >      +** ** ** **key_bindings_add(tablename, key, args_has(args, 'r'),
> >      cmdlist);
> >      ** ** ** ** return (CMD_RETURN_NORMAL);
> >      **}
> > 
> >      Index: cmd-list-keys.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/cmd-list-keys.c,v
> >      retrieving revision 1.25
> >      diff -u -p -r1.25 cmd-list-keys.c
> >      --- cmd-list-keys.c** ** **20 Oct 2014 23:27:14 -0000** ** ** 1.25
> >      +++ cmd-list-keys.c** ** **13 Apr 2015 21:29:21 -0000
> >      @@ -33,8 +33,8 @@ enum cmd_retval** ** ** ** cmd_list_keys_commands(
> > 
> >      **const struct cmd_entry cmd_list_keys_entry = {
> >      ** ** ** ** "list-keys", "lsk",
> >      -** ** ** **"t:", 0, 0,
> >      -** ** ** **"[-t key-table]",
> >      +** ** ** **"t:T:", 0, 0,
> >      +** ** ** **"[-t mode-table] [-T key-table]",
> >      ** ** ** ** 0,
> >      ** ** ** ** cmd_list_keys_exec
> >      **};
> >      @@ -51,58 +51,65 @@ enum cmd_retval
> >      **cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq)
> >      **{
> >      ** ** ** ** struct args** ** ** ** ** ** ***args = self->args;
> >      +** ** ** **struct key_table** ** ** ** *table;
> >      ** ** ** ** struct key_binding** ** ** *bd;
> >      -** ** ** **const char** ** ** ** ** ** ** *key;
> >      -** ** ** **char** ** ** ** ** ** ** ** ** ** **tmp[BUFSIZ], flags[8];
> >      +** ** ** **const char** ** ** ** ** ** ** *key, *tablename, *r;
> >      +** ** ** **char** ** ** ** ** ** ** ** ** ** **tmp[BUFSIZ];
> >      ** ** ** ** size_t** ** ** ** ** ** ** ** ** **used;
> >      -** ** ** **int** ** ** ** ** ** ** ** ** ** ** width, keywidth;
> >      +** ** ** **int** ** ** ** ** ** ** ** ** ** ** repeat, width,
> >      tablewidth, keywidth;
> > 
> >      ** ** ** ** if (self->entry == &cmd_list_commands_entry)
> >      ** ** ** ** ** ** ** ** return (cmd_list_keys_commands(self, cmdq));
> > 
> >      ** ** ** ** if (args_has(args, 't'))
> >      ** ** ** ** ** ** ** ** return (cmd_list_keys_table(self, cmdq));
> >      +** ** ** **tablename = args_get(args, 'T');
> > 
> >      -** ** ** **width = 0;
> >      -
> >      -** ** ** **RB_FOREACH(bd, key_bindings, &key_bindings) {
> >      -** ** ** ** ** ** ** **key = key_string_lookup_key(bd->key &
> >      ~KEYC_PREFIX);
> >      -** ** ** ** ** ** ** **if (key == NULL)
> >      +** ** ** **repeat = 0;
> >      +** ** ** **tablewidth = keywidth = 0;
> >      +** ** ** **RB_FOREACH(table, key_tables, &key_tables) {
> >      +** ** ** ** ** ** ** **if (tablename != NULL && strcmp(table->name,
> >      tablename) != 0)
> >      ** ** ** ** ** ** ** ** ** ** ** ** continue;
> >      +** ** ** ** ** ** ** **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;
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **repeat = 1;
> >      +
> >      +** ** ** ** ** ** ** ** ** ** ** **width = strlen(table->name);
> >      +** ** ** ** ** ** ** ** ** ** ** **if (width > tablewidth)
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **tablewidth =width;
> >      +** ** ** ** ** ** ** ** ** ** ** **width = strlen(key);
> >      +** ** ** ** ** ** ** ** ** ** ** **if (width > keywidth)
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **keywidth = width;
> >      +** ** ** ** ** ** ** **}
> >      ** ** ** ** }
> > 
> >      -** ** ** **RB_FOREACH(bd, key_bindings, &key_bindings) {
> >      -** ** ** ** ** ** ** **key = key_string_lookup_key(bd->key &
> >      ~KEYC_PREFIX);
> >      -** ** ** ** ** ** ** **if (key == NULL)
> >      +** ** ** **RB_FOREACH(table, key_tables, &key_tables) {
> >      +** ** ** ** ** ** ** **if (tablename != NULL && strcmp(table->name,
> >      tablename) != 0)
> >      ** ** ** ** ** ** ** ** ** ** ** ** continue;
> >      -
> >      -** ** ** ** ** ** ** ***flags = '\0';
> >      -** ** ** ** ** ** ** **if (!(bd->key & KEYC_PREFIX)) {
> >      -** ** ** ** ** ** ** ** ** ** ** **if (bd->can_repeat)
> >      -** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **xsnprintf(flags, sizeof
> >      flags, "-rn ");
> >      +** ** ** ** ** ** ** **RB_FOREACH(bd, key_bindings,
> >      &(table->key_bindings)) {
> >      +** ** ** ** ** ** ** ** ** ** ** **key =
> >      key_string_lookup_key(bd->key);
> >      +** ** ** ** ** ** ** ** ** ** ** **if (key == NULL)
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **continue;
> >      +
> >      +** ** ** ** ** ** ** ** ** ** ** **if (!repeat)
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **r = "";
> >      +** ** ** ** ** ** ** ** ** ** ** **else if (bd->can_repeat)
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **r = "-r ";
> >      ** ** ** ** ** ** ** ** ** ** ** ** 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;
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **r = "** **";
> >      +** ** ** ** ** ** ** ** ** ** ** **used = xsnprintf(tmp, sizeof tmp,
> >      "%s-T %-*s %-*s ", r,
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** **(int)tablewidth, table->name,
> >      (int)keywidth, key);
> >      +** ** ** ** ** ** ** ** ** ** ** **if (used < sizeof tmp) {
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** **
> >      **cmd_list_print(bd->cmdlist, tmp + used,
> >      +** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **(sizeof tmp) -
> >      used);
> >      +** ** ** ** ** ** ** ** ** ** ** **}
> > 
> >      -** ** ** ** ** ** ** **cmd_list_print(bd->cmdlist, tmp + used, (sizeof
> >      tmp) - used);
> >      -** ** ** ** ** ** ** **cmdq_print(cmdq, "bind-key %s", tmp);
> >      +** ** ** ** ** ** ** ** ** ** ** **cmdq_print(cmdq, "bind-key %s",
> >      tmp);
> >      +** ** ** ** ** ** ** **}
> >      ** ** ** ** }
> > 
> >      ** ** ** ** return (CMD_RETURN_NORMAL);
> >      Index: cmd-switch-client.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/cmd-switch-client.c,v
> >      retrieving revision 1.22
> >      diff -u -p -r1.22 cmd-switch-client.c
> >      --- cmd-switch-client.c 20 Oct 2014 22:29:25 -0000** ** ** 1.22
> >      +++ cmd-switch-client.c 13 Apr 2015 21:29:21 -0000
> >      @@ -31,8 +31,8 @@ enum cmd_retval** ** ** ** cmd_switch_client_exec(
> > 
> >      **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_exec
> >      **};
> >      @@ -46,7 +46,8 @@ cmd_switch_client_exec(struct cmd *self,
> >      ** ** ** ** struct winlink** ** ** ** ** *wl = NULL;
> >      ** ** ** ** struct window** ** ** ** ** ***w = NULL;
> >      ** ** ** ** struct window_pane** ** ** *wp = NULL;
> >      -** ** ** **const char** ** ** ** ** ** ** *tflag;
> >      +** ** ** **const char** ** ** ** ** ** ** *tflag, *tablename;
> >      +** ** ** **struct key_table** ** ** ** *table;
> > 
> >      ** ** ** ** if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) ==
> >      NULL)
> >      ** ** ** ** ** ** ** ** return (CMD_RETURN_ERROR);
> >      @@ -56,6 +57,18 @@ cmd_switch_client_exec(struct cmd *self,
> >      ** ** ** ** ** ** ** ** ** ** ** ** c->flags &= ~CLIENT_READONLY;
> >      ** ** ** ** ** ** ** ** else
> >      ** ** ** ** ** ** ** ** ** ** ** ** c->flags |= CLIENT_READONLY;
> >      +** ** ** **}
> >      +
> >      +** ** ** **tablename = args_get(args, 'T');
> >      +** ** ** **if (tablename != NULL) {
> >      +** ** ** ** ** ** ** **table = key_bindings_get_table(tablename, 0);
> >      +** ** ** ** ** ** ** **if (table == NULL) {
> >      +** ** ** ** ** ** ** ** ** ** ** **cmdq_error(cmdq, "table %s doesn't
> >      exist", tablename);
> >      +** ** ** ** ** ** ** ** ** ** ** **return (CMD_RETURN_ERROR);
> >      +** ** ** ** ** ** ** **}
> >      +** ** ** ** ** ** ** **table->references++;
> >      +** ** ** ** ** ** ** **key_bindings_unref_table(c->keytable);
> >      +** ** ** ** ** ** ** **c->keytable = table;
> >      ** ** ** ** }
> > 
> >      ** ** ** ** tflag = args_get(args, 't');
> >      Index: cmd-unbind-key.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/cmd-unbind-key.c,v
> >      retrieving revision 1.20
> >      diff -u -p -r1.20 cmd-unbind-key.c
> >      --- cmd-unbind-key.c** ** 20 Oct 2014 22:29:25 -0000** ** ** 1.20
> >      +++ cmd-unbind-key.c** ** 13 Apr 2015 21:29:21 -0000
> >      @@ -31,8 +31,8 @@ enum cmd_retval** ** ** ** cmd_unbind_key_mode_tab
> > 
> >      **const struct cmd_entry cmd_unbind_key_entry = {
> >      ** ** ** ** "unbind-key", "unbind",
> >      -** ** ** **"acnt:", 0, 1,
> >      -** ** ** **"[-acn] [-t mode-table] key",
> >      +** ** ** **"acnt:T:", 0, 1,
> >      +** ** ** **"[-acn] [-t mode-table] [-T key-table] key",
> >      ** ** ** ** 0,
> >      ** ** ** ** cmd_unbind_key_exec
> >      **};
> >      @@ -40,9 +40,9 @@ const struct cmd_entry cmd_unbind_key_en
> >      **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;
> >      +** ** ** **struct args** ** ***args = self->args;
> >      +** ** ** **int** ** ** ** ** ** ** key;
> >      +** ** ** **const char** ** ** *tablename;
> > 
> >      ** ** ** ** if (!args_has(args, 'a')) {
> >      ** ** ** ** ** ** ** ** if (args->argc != 1) {
> >      @@ -66,16 +66,23 @@ cmd_unbind_key_exec(struct cmd *self, st
> >      ** ** ** ** ** ** ** ** return (cmd_unbind_key_mode_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'))
> >      +** ** ** ** ** ** ** **tablename = args_get(args, 'T');
> >      +** ** ** **else if (args_has(args, 'n'))
> >      +** ** ** ** ** ** ** **tablename = "root";
> >      +** ** ** **else
> >      +** ** ** ** ** ** ** **tablename = "prefix";
> >      +
> >      +** ** ** **key_bindings_remove(tablename, key);
> >      ** ** ** ** return (CMD_RETURN_NORMAL);
> >      **}
> > 
> >      Index: format.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/format.c,v
> >      retrieving revision 1.60
> >      diff -u -p -r1.60 format.c
> >      --- format.c** ** 31 Mar 2015 17:58:36 -0000** ** ** 1.60
> >      +++ format.c** ** 13 Apr 2015 21:29:21 -0000
> >      @@ -545,7 +545,11 @@ format_defaults_client(struct format_tre
> >      ** ** ** ** format_add(ft, "client_activity", "%lld", (long long) t);
> >      ** ** ** ** format_add(ft, "client_activity_string", "%s",
> >      format_time_string(t));
> > 
> >      -** ** ** **format_add(ft, "client_prefix", "%d", !!(c->flags &
> >      CLIENT_PREFIX));
> >      +** ** ** **if (strcmp(c->keytable->name, "root") == 0)
> >      +** ** ** ** ** ** ** **format_add(ft, "client_prefix", "%d", 0);
> >      +** ** ** **else
> >      +** ** ** ** ** ** ** **format_add(ft, "client_prefix", "%d", 1);
> >      +** ** ** **format_add(ft, "client_key_table", "%s", 
> > c->keytable->name);
> > 
> >      ** ** ** ** if (c->tty.flags & TTY_UTF8)
> >      ** ** ** ** ** ** ** ** format_add(ft, "client_utf8", "%d", 1);
> >      Index: key-bindings.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/key-bindings.c,v
> >      retrieving revision 1.43
> >      diff -u -p -r1.43 key-bindings.c
> >      --- key-bindings.c** ** ** 22 Oct 2014 23:18:53 -0000** ** ** 1.43
> >      +++ key-bindings.c** ** ** 13 Apr 2015 21:29:21 -0000
> >      @@ -25,60 +25,121 @@
> >      **#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;
> >      +** ** ** **return (bd1->key - bd2->key);
> >      +}
> >      +
> >      +struct key_table *
> >      +key_bindings_get_table(const char *name, int create)
> >      +{
> >      +** ** ** **struct key_table** ** ** ** table_search, *table;
> >      +
> >      +** ** ** **[2]table_search.name = name;
> >      +** ** ** **table = RB_FIND(key_tables, &key_tables, &table_search);
> >      +** ** ** **if (table != NULL || !create)
> >      +** ** ** ** ** ** ** **return (table);
> > 
> >      -** ** ** **key1 = bd1->key & ~KEYC_PREFIX;
> >      -** ** ** **key2 = bd2->key & ~KEYC_PREFIX;
> >      -** ** ** **if (key1 != key2)
> >      -** ** ** ** ** ** ** **return (key1 - key2);
> >      +** ** ** **table = xmalloc(sizeof *table);
> >      +** ** ** **table->name = xstrdup(name);
> >      +** ** ** **RB_INIT(&table->key_bindings);
> > 
> >      -** ** ** **if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX))
> >      -** ** ** ** ** ** ** **return (-1);
> >      -** ** ** **if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX))
> >      -** ** ** ** ** ** ** **return (1);
> >      -** ** ** **return (0);
> >      +** ** ** **table->references = 1; /* one reference in key_tables */
> >      +** ** ** **RB_INSERT(key_tables, &key_tables, table);
> >      +
> >      +** ** ** **return (table);
> >      **}
> > 
> >      -struct key_binding *
> >      -key_bindings_lookup(int key)
> >      +void
> >      +key_bindings_unref_table(struct key_table *table)
> >      **{
> >      -** ** ** **struct key_binding** ** ** bd;
> >      +** ** ** **struct key_binding** ** ** *bd;
> > 
> >      -** ** ** **bd.key = key;
> >      -** ** ** **return (RB_FIND(key_bindings, &key_bindings, &bd));
> >      +** ** ** **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(int key, int can_repeat, struct cmd_list *cmdlist)
> >      +key_bindings_add(const char *name, int key, int can_repeat,
> >      +** ** struct cmd_list *cmdlist)
> >      **{
> >      -** ** ** **struct key_binding** ** ** *bd;
> >      +** ** ** **struct key_table** ** ** ** *table;
> >      +** ** ** **struct key_binding** ** ** **bd_search, *bd;
> > 
> >      -** ** ** **key_bindings_remove(key);
> >      +** ** ** **table = key_bindings_get_table(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, *bd;
> >      +
> >      +** ** ** **table = key_bindings_get_table(name, 0);
> >      +** ** ** **if (table == NULL)
> >      +** ** ** ** ** ** ** **return;
> > 
> >      -** ** ** **if ((bd = key_bindings_lookup(key)) == NULL)
> >      +** ** ** **bd_search.key = key;
> >      +** ** ** **bd = RB_FIND(key_bindings, &table->key_bindings,
> >      &bd_search);
> >      +** ** ** **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)
> >      +** ** ** ** ** ** ** **return;
> >      +
> >      +** ** ** **RB_REMOVE(key_tables, &key_tables, table);
> >      +** ** ** **key_bindings_unref_table(table);
> >      **}
> > 
> >      **void
> >      @@ -164,8 +225,6 @@ key_bindings_init(void)
> >      ** ** ** ** char*** ** ** ** ** ** cause;
> >      ** ** ** ** int** ** ** ** ** ** ** error;
> >      ** ** ** ** struct cmd_q** ** *cmdq;
> >      -
> >      -** ** ** **RB_INIT(&key_bindings);
> > 
> >      ** ** ** ** cmdq = cmdq_new(NULL);
> >      ** ** ** ** for (i = 0; i < nitems(defaults); i++) {
> >      Index: server-client.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/server-client.c,v
> >      retrieving revision 1.129
> >      diff -u -p -r1.129 server-client.c
> >      --- server-client.c** ** **31 Mar 2015 17:45:10 -0000** ** ** 1.129
> >      +++ server-client.c** ** **13 Apr 2015 21:29:21 -0000
> >      @@ -100,6 +100,9 @@ server_client_create(int fd)
> > 
> >      ** ** ** ** c->flags |= CLIENT_FOCUSED;
> > 
> >      +** ** ** **c->keytable = key_bindings_get_table("root", 1);
> >      +** ** ** **c->keytable->references++;
> >      +
> >      ** ** ** ** evtimer_set(&c->repeat_timer, server_client_repeat_timer,
> >      c);
> > 
> >      ** ** ** ** for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
> >      @@ -171,6 +174,8 @@ server_client_lost(struct client *c)
> > 
> >      ** ** ** ** evtimer_del(&c->repeat_timer);
> > 
> >      +** ** ** **key_bindings_unref_table(c->keytable);
> >      +
> >      ** ** ** ** if (event_initialized(&c->identify_timer))
> >      ** ** ** ** ** ** ** ** evtimer_del(&c->identify_timer);
> > 
> >      @@ -362,33 +367,28 @@ server_client_assume_paste(struct sessio
> >      **void
> >      **server_client_handle_key(struct client *c, int key)
> >      **{
> >      -** ** ** **struct session** ** ** ** ** *s;
> >      +** ** ** **struct session** ** ** ** ** *s = c->session;
> >      ** ** ** ** struct window** ** ** ** ** ***w;
> >      ** ** ** ** struct window_pane** ** ** *wp;
> >      ** ** ** ** struct timeval** ** ** ** ** **tv;
> >      -** ** ** **struct key_binding** ** ** *bd;
> >      -** ** ** **int** ** ** ** ** ** ** ** ** ** ** xtimeout, isprefix,
> >      ispaste;
> >      +** ** ** **struct key_table** ** ** ** *table = c->keytable;
> >      +** ** ** **struct key_binding** ** ** **bd_search, *bd;
> >      +** ** ** **int** ** ** ** ** ** ** ** ** ** ** xtimeout;
> > 
> >      ** ** ** ** /* Check the client is good to accept input. */
> >      -** ** ** **if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
> >      -** ** ** ** ** ** ** **return;
> >      -
> >      -** ** ** **if (c->session == NULL)
> >      +** ** ** **if (s == NULL || (c->flags & 
> > (CLIENT_DEAD|CLIENT_SUSPENDED))
> >      != 0)
> >      ** ** ** ** ** ** ** ** return;
> >      -** ** ** **s = c->session;
> >      +** ** ** **w = c->session->curw->window;
> >      +** ** ** **wp = w->active;
> > 
> >      ** ** ** ** /* Update the activity timer. */
> >      ** ** ** ** if (gettimeofday(&c->activity_time, NULL) != 0)
> >      ** ** ** ** ** ** ** ** fatal("gettimeofday failed");
> >      -
> >      ** ** ** ** memcpy(&s->last_activity_time, &s->activity_time,
> >      ** ** ** ** ** ** sizeof s->last_activity_time);
> >      ** ** ** ** memcpy(&s->activity_time, &c->activity_time, sizeof
> >      s->activity_time);
> > 
> >      -** ** ** **w = c->session->curw->window;
> >      -** ** ** **wp = w->active;
> >      -
> >      -** ** ** **/* Special case: number keys jump to pane in identify mode.
> >      */
> >      +** ** ** **/* Number keys jump to pane in identify mode. */
> >      ** ** ** ** if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9')
> >      {
> >      ** ** ** ** ** ** ** ** if (c->flags & CLIENT_READONLY)
> >      ** ** ** ** ** ** ** ** ** ** ** ** return;
> >      @@ -419,74 +419,89 @@ server_client_handle_key(struct client *
> >      ** ** ** ** ** ** ** ** return;
> >      ** ** ** ** }
> > 
> >      -** ** ** **/* Is this a prefix key? */
> >      -** ** ** **if (key == options_get_number(&s->options, "prefix"))
> >      -** ** ** ** ** ** ** **isprefix = 1;
> >      -** ** ** **else if (key == options_get_number(&s->options, "prefix2"))
> >      -** ** ** ** ** ** ** **isprefix = 1;
> >      -** ** ** **else
> >      -** ** ** ** ** ** ** **isprefix = 0;
> >      +** ** ** **/* Treat everything as a regular key when pasting is
> >      detected. */
> >      +** ** ** **if (server_client_assume_paste(s)) {
> >      +** ** ** ** ** ** ** **if (!(c->flags & CLIENT_READONLY))
> >      +** ** ** ** ** ** ** ** ** ** ** **window_pane_key(wp, s, key);
> >      +** ** ** ** ** ** ** **return;
> >      +** ** ** **}
> > 
> >      -** ** ** **/* Treat prefix as a regular key when pasting is detected.
> >      */
> >      -** ** ** **ispaste = server_client_assume_paste(s);
> >      -** ** ** **if (ispaste)
> >      -** ** ** ** ** ** ** **isprefix = 0;
> >      -
> >      -** ** ** **/* No previous prefix key. */
> >      -** ** ** **if (!(c->flags & CLIENT_PREFIX)) {
> >      -** ** ** ** ** ** ** **if (isprefix) {
> >      -** ** ** ** ** ** ** ** ** ** ** **c->flags |= CLIENT_PREFIX;
> >      +retry:
> >      +** ** ** **/* Try to see if there is a key binding in the current
> >      table. */
> >      +** ** ** **bd_search.key = key;
> >      +** ** ** **bd = RB_FIND(key_bindings, &table->key_bindings,
> >      &bd_search);
> >      +** ** ** **if (bd != NULL) {
> >      +** ** ** ** ** ** ** **/*
> >      +** ** ** ** ** ** ** ** * Key was matched in this table. If currently
> >      repeating but
> >      +** ** ** ** ** ** ** ** * a non-repeating binding was found, stop
> >      repeating and try
> >      +** ** ** ** ** ** ** ** * again in the root table.
> >      +** ** ** ** ** ** ** ** */
> >      +** ** ** ** ** ** ** **if ((c->flags & CLIENT_REPEAT) &&
> >      !bd->can_repeat) {
> >      +** ** ** ** ** ** ** ** ** ** ** **server_set_key_table(c, "root");
> >      +** ** ** ** ** ** ** ** ** ** ** **c->flags &= ~CLIENT_REPEAT;
> >      ** ** ** ** ** ** ** ** ** ** ** ** server_status_client(c);
> >      -** ** ** ** ** ** ** ** ** ** ** **return;
> >      +** ** ** ** ** ** ** ** ** ** ** **goto retry;
> >      ** ** ** ** ** ** ** ** }
> > 
> >      -** ** ** ** ** ** ** **/* 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) {
> >      +** ** ** ** ** ** ** **/*
> >      +** ** ** ** ** ** ** ** * Take a reference to this table to make sure
> >      the key binding
> >      +** ** ** ** ** ** ** ** * doesn't disappear.
> >      +** ** ** ** ** ** ** ** */
> >      +** ** ** ** ** ** ** **table->references++;
> >      +
> >      +** ** ** ** ** ** ** **/*
> >      +** ** ** ** ** ** ** ** * If this is a repeating key, start the timer.
> >      Otherwise reset
> >      +** ** ** ** ** ** ** ** * the client back to the root table.
> >      +** ** ** ** ** ** ** ** */
> >      +** ** ** ** ** ** ** **xtimeout = options_get_number(&s->options,
> >      "repeat-time");
> >      +** ** ** ** ** ** ** **if (xtimeout != 0 && bd->can_repeat) {
> >      +** ** ** ** ** ** ** ** ** ** ** **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 {
> >      ** ** ** ** ** ** ** ** ** ** ** ** c->flags &= ~CLIENT_REPEAT;
> >      -** ** ** ** ** ** ** ** ** ** ** **if (isprefix)
> >      -** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **c->flags |=
> >      CLIENT_PREFIX;
> >      -** ** ** ** ** ** ** ** ** ** ** **else if (!(c->flags &
> >      CLIENT_READONLY))
> >      -** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **window_pane_key(wp, s,
> >      key);
> >      +** ** ** ** ** ** ** ** ** ** ** **server_set_key_table(c, "root");
> >      ** ** ** ** ** ** ** ** }
> >      +** ** ** ** ** ** ** **server_status_client(c);
> >      +
> >      +** ** ** ** ** ** ** **/* Dispatch the key binding. */
> >      +** ** ** ** ** ** ** **key_bindings_dispatch(bd, c);
> >      +** ** ** ** ** ** ** **key_bindings_unref_table(table);
> >      +
> >      ** ** ** ** ** ** ** ** return;
> >      ** ** ** ** }
> > 
> >      -** ** ** **/* If already repeating, but this key can't repeat, skip 
> > it.
> >      */
> >      -** ** ** **if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
> >      +** ** ** **/*
> >      +** ** ** ** * No match in this table. If repeating, switch the client
> >      back to the
> >      +** ** ** ** * root table and try again.
> >      +** ** ** ** */
> >      +** ** ** **if (c->flags & CLIENT_REPEAT) {
> >      +** ** ** ** ** ** ** **server_set_key_table(c, "root");
> >      ** ** ** ** ** ** ** ** c->flags &= ~CLIENT_REPEAT;
> >      -** ** ** ** ** ** ** **if (isprefix)
> >      -** ** ** ** ** ** ** ** ** ** ** **c->flags |= CLIENT_PREFIX;
> >      -** ** ** ** ** ** ** **else if (!(c->flags & CLIENT_READONLY))
> >      -** ** ** ** ** ** ** ** ** ** ** **window_pane_key(wp, s, key);
> >      -** ** ** ** ** ** ** **return;
> >      +** ** ** ** ** ** ** **server_status_client(c);
> >      +** ** ** ** ** ** ** **goto retry;
> >      ** ** ** ** }
> > 
> >      -** ** ** **/* 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);
> >      +** ** ** **/* If no match and we're not in the root table, that's it.
> >      */
> >      +** ** ** **if (strcmp(c->keytable->name, "root") != 0) {
> >      +** ** ** ** ** ** ** **server_set_key_table(c, "root");
> >      +** ** ** ** ** ** ** **server_status_client(c);
> >      +** ** ** ** ** ** ** **return;
> >      ** ** ** ** }
> > 
> >      -** ** ** **/* Dispatch the command. */
> >      -** ** ** **key_bindings_dispatch(bd, c);
> >      +** ** ** **/*
> >      +** ** ** ** * No match, but in the root table. Prefix switches to the
> >      prefix table
> >      +** ** ** ** * and everything else is passed through.
> >      +** ** ** ** */
> >      +** ** ** **if (key == options_get_number(&s->options, "prefix") ||
> >      +** ** ** ** ** **key == options_get_number(&s->options, "prefix2")) {
> >      +** ** ** ** ** ** ** **server_set_key_table(c, "prefix");
> >      +** ** ** ** ** ** ** **server_status_client(c);
> >      +** ** ** **} else if (!(c->flags & CLIENT_READONLY))
> >      +** ** ** ** ** ** ** **window_pane_key(wp, s, key);
> >      **}
> > 
> >      **/* Client functions that need to happen every loop. */
> >      @@ -692,9 +707,9 @@ server_client_repeat_timer(unused int fd
> >      ** ** ** ** 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_set_key_table(c, "root");
> >      +** ** ** ** ** ** ** **c->flags &= ~CLIENT_REPEAT;
> >      +** ** ** ** ** ** ** **server_status_client(c);
> >      ** ** ** ** }
> >      **}
> > 
> >      Index: server-fn.c
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/server-fn.c,v
> >      retrieving revision 1.79
> >      diff -u -p -r1.79 server-fn.c
> >      --- server-fn.c 31 Mar 2015 17:45:10 -0000** ** ** 1.79
> >      +++ server-fn.c 13 Apr 2015 21:29:22 -0000
> >      @@ -101,6 +101,14 @@ server_status_client(struct client *c)
> >      **}
> > 
> >      **void
> >      +server_set_key_table(struct client *c, const char *name)
> >      +{
> >      +** ** ** **key_bindings_unref_table(c->keytable);
> >      +** ** ** **c->keytable = key_bindings_get_table(name, 1);
> >      +** ** ** **c->keytable->references++;
> >      +}
> >      +
> >      +void
> >      **server_redraw_session(struct session *s)
> >      **{
> >      ** ** ** ** struct client** ***c;
> >      Index: tmux.1
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/tmux.1,v
> >      retrieving revision 1.417
> >      diff -u -p -r1.417 tmux.1
> >      --- tmux.1** ** ** 10 Apr 2015 16:00:08 -0000** ** ** 1.417
> >      +++ tmux.1** ** ** 13 Apr 2015 21:29:23 -0000
> >      @@ -838,6 +838,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
> >      @@ -855,6 +856,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
> >      interpreted from
> >      +.Ar key-table .
> >      **.El
> >      **.Sh WINDOWS AND PANES
> >      **A
> >      @@ -1905,6 +1909,7 @@ Commands related to key bindings are as
> >      **.It Xo Ic bind-key
> >      **.Op Fl cnr
> >      **.Op Fl t Ar mode-table
> >      +.Op Fl T Ar key-table
> >      **.Ar key Ar command Op Ar arguments
> >      **.Xc
> >      **.D1 (alias: Ic bind )
> >      @@ -1940,18 +1945,41 @@ or for normal mode without.
> >      **To view the default bindings and possible commands, see the
> >      **.Ic list-keys
> >      **command.
> >      -.It Ic list-keys Op Fl t Ar key-table
> >      +.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 Xo Ic list-keys
> >      +.Op Fl t Ar mode-table
> >      +.Op Fl T Ar key-table
> >      +.Xc
> >      **.D1 (alias: Ic lsk )
> >      **List all key bindings.
> >      **Without
> >      **.Fl t
> >      -the primary key bindings - those executed when preceded by the prefix
> >      key -
> >      -are printed.
> >      +or
> >      +.Fl T
> >      +all key tables are printed.
> >      +With
> >      +.Fl T
> >      +only
> >      +.Ar key-table .
> >      **.Pp
> >      **With
> >      **.Fl t ,
> >      **the key bindings in
> >      -.Ar key-table
> >      +.Ar mode-table
> >      **are listed; this may be one of:
> >      **.Em vi-edit ,
> >      **.Em emacs-edit ,
> >      @@ -1992,6 +2020,7 @@ the secondary prefix key, to a window as
> >      **.It Xo Ic unbind-key
> >      **.Op Fl acn
> >      **.Op Fl t Ar mode-table
> >      +.Op Fl T Ar key-table
> >      **.Ar key
> >      **.Xc
> >      **.D1 (alias: Ic unbind )
> >      @@ -2017,6 +2046,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
> >      Index: tmux.h
> >      ===================================================================
> >      RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
> >      retrieving revision 1.490
> >      diff -u -p -r1.490 tmux.h
> >      --- tmux.h** ** ** 6 Feb 2015 17:21:08 -0000** ** ** **1.490
> >      +++ tmux.h** ** ** 13 Apr 2015 21:29:23 -0000
> >      @@ -89,10 +89,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. */
> >      @@ -1287,7 +1286,7 @@ struct client {
> >      ** ** ** ** struct screen** ** status;
> > 
> >      **#define CLIENT_TERMINAL 0x1
> >      -#define CLIENT_PREFIX 0x2
> >      +/* 0x2 unused */
> >      **#define CLIENT_EXIT 0x4
> >      **#define CLIENT_REDRAW 0x8
> >      **#define CLIENT_STATUS 0x10
> >      @@ -1306,6 +1305,7 @@ struct client {
> >      **#define CLIENT_256COLOURS 0x20000
> >      **#define CLIENT_IDENTIFIED 0x40000
> >      ** ** ** ** int** ** ** ** ** ** ** flags;
> >      +** ** ** **struct key_table *keytable;
> > 
> >      ** ** ** ** struct event** ** **identify_timer;
> > 
> >      @@ -1423,15 +1423,24 @@ struct cmd_entry {
> >      ** ** ** ** enum cmd_retval** (*exec)(struct cmd *, struct cmd_q *);
> >      **};
> > 
> >      -/* Key binding. */
> >      +/* Key binding and key table. */
> >      **struct key_binding {
> >      -** ** ** **int** ** ** ** ** ** ** key;
> >      -** ** ** **struct cmd_list *cmdlist;
> >      -** ** ** **int** ** ** ** ** ** ** can_repeat;
> >      +** ** ** **int** ** ** ** ** ** ** ** ** ** ** key;
> >      +** ** ** **struct cmd_list** ** ** ** ***cmdlist;
> >      +** ** ** **int** ** ** ** ** ** ** ** ** ** ** can_repeat;
> > 
> >      -** ** ** **RB_ENTRY(key_binding) entry;
> >      +** ** ** **RB_ENTRY(key_binding)** ** entry;
> >      **};
> >      **RB_HEAD(key_bindings, key_binding);
> >      +struct key_table {
> >      +** ** ** **const char** ** ** ** ** ** ** ***name;
> >      +** ** ** **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
> >      @@ -1848,12 +1857,16 @@ void** ** cmd_wait_for_flush(void);
> >      **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_get_table(const char *,
> >      int);
> >      +void** ** key_bindings_unref_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
> >      *);
> > 
> >      @@ -1889,6 +1902,7 @@ void** ** ** **server_write_session(struct sessio
> >      ** ** ** ** ** ** **size_t);
> >      **void** ** server_redraw_client(struct client *);
> >      **void** ** server_status_client(struct client *);
> >      +void** ** server_set_key_table(struct client *, const char *);
> >      **void** ** server_redraw_session(struct session *);
> >      **void** ** server_redraw_session_group(struct session *);
> >      **void** ** server_status_session(struct session *);
> > 
> >      On Mon, Apr 13, 2015 at 03:21:52PM +0000, Ross Hadden wrote:
> >      > Keith Amling <amling <at> [3]palantir.com> writes:
> >      >
> >      > >
> >      > > > > > Or are you thinking of creating the table after running the
> >      set
> >      > command?
> >      > > > > > This shouldn't work - you shouldn't be able to set a client 
> > to
> >      a
> >      > > > > > nonexistent table.
> >      > > > >
> >      > > > > I guess I don't super care what happens since I won't 
> > personally
> >      be
> >      > > > > writing any switch-client -T into an empty table but I had
> >      assumed we
> >      > > > > would allow switching to a new [and ephemeral] table since
> >      otherwise
> >      > > > > switch-client -T can fail which just seems weird to me.
> >      > > >
> >      > > > I'd say it should fail if the table doesn't exist.
> >      > > >
> >      > > > I can't think of a case where I would want it to automatically
> >      create a
> >      > > > table, except to confuse people who make a typo in the table 
> > name.
> >      Do
> >      > > > you have a use in mind?
> >      > >
> >      > > Not specifically, I just prefer to see tools degrade what might be
> >      > > described as "uniformly" where possible.** Nonuniform behaviour
> >      makes
> >      > > tools dangerous for automated use because when writing a script
> >      you're
> >      > > unlikely to think of things like "what if this table is empty" or
> >      "what
> >      > > if this command barfs on no args when really no args means I just
> >      didn't
> >      > > need it to do anything".
> >      > >
> >      > > I'll switch it and the next set of patches will be up shortly.
> >      > >
> >      > > Keith
> >      > >
> >      > >
> >      
> > --------------------------------------------------------------------------
> >      > ----
> >      > > "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."
> >      > > [4]http://p.sf.net/sfu/SauceLabs
> >      > >
> >      >
> >      >
> >      > Has work on this continued?** I made an issue about it
> >      > ([5]https://sourceforge.net/p/tmux/tickets/172/) in an effort to 
> > bring
> >      > attention to this patch, but Thomas said it's pretty much not going
> >      anywhere
> >      > unless the original patch author continues or makes an effort to get
> >      it
> >      > merged himself.
> >      >
> >      > I would love to see this landed in tmux!** My current workaround can
> >      be seen
> >      > at
> >      
> > [6]https://github.com/rosshadden/dotfiles/blob/master/src/.tmux.conf#L79-L85
> >      > and
> >      [7]https://github.com/rosshadden/dotfiles/blob/master/src/lib/tmux-
> >      > cords.sh.
> >      >
> >      >
> >      >
> >      
> > ------------------------------------------------------------------------------
> >      > BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT
> >      > Develop your own process in accordance with the BPMN 2 standard
> >      > Learn Process modeling best practices with Bonita BPM through live
> >      exercises
> >      > [8]http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual-
> >      event?utm_
> >      > 
> > source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF
> >      > _______________________________________________
> >      > tmux-users mailing list
> >      > [9]tmux-users@lists.sourceforge.net
> >      > [10]https://lists.sourceforge.net/lists/listinfo/tmux-users
> > 
> > References
> > 
> >    Visible links
> >    1. mailto:nicholas.marri...@gmail.com
> >    2. http://table_search.name/
> >    3. http://palantir.com/
> >    4. http://p.sf.net/sfu/SauceLabs
> >    5. https://sourceforge.net/p/tmux/tickets/172/
> >    6. 
> > https://github.com/rosshadden/dotfiles/blob/master/src/.tmux.conf#L79-L85
> >    7. https://github.com/rosshadden/dotfiles/blob/master/src/lib/tmux-
> >    8. http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual-
> >    9. mailto:tmux-users@lists.sourceforge.net
> >   10. https://lists.sourceforge.net/lists/listinfo/tmux-users

------------------------------------------------------------------------------
BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT
Develop your own process in accordance with the BPMN 2 standard
Learn Process modeling best practices with Bonita BPM through live exercises
http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_
source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to