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 <
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;
> +
> + 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> 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."
> > > http://p.sf.net/sfu/SauceLabs
> > >
> >
> >
> > Has work on this continued? I made an issue about it
> > (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
> https://github.com/rosshadden/dotfiles/blob/master/src/.tmux.conf#L79-L85
> > and 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
> > 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
>
------------------------------------------------------------------------------
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