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
> [email protected]
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users