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