From 5a1a1066371328f9d53a9bc5e5c4c53acb26c2b2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 24 Jul 2009 14:52:47 +0000 Subject: Permit commands to be bound to key presses without the prefix key first. The new -n flag to bind-key and unbind-key sets or removes these bindings, and list-key shows them in []s. --- cmd-bind-key.c | 11 ++++++++--- cmd-list-keys.c | 18 ++++++++++++------ cmd-unbind-key.c | 11 ++++++++--- key-bindings.c | 16 ++++++++++++++-- server.c | 11 ++++++++--- tmux.1 | 19 ++++++++++++++++++- tmux.h | 14 ++++++++------ 7 files changed, 76 insertions(+), 24 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 14a93831..82ab14b0 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -39,7 +39,7 @@ struct cmd_bind_key_data { const struct cmd_entry cmd_bind_key_entry = { "bind-key", "bind", - "[-r] key command [arguments]", + "[-nr] key command [arguments]", 0, 0, NULL, cmd_bind_key_parse, @@ -54,14 +54,17 @@ int cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_bind_key_data *data; - int opt; + int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); data->can_repeat = 0; data->cmdlist = NULL; - while ((opt = getopt(argc, argv, "r")) != -1) { + while ((opt = getopt(argc, argv, "nr")) != -1) { switch (opt) { + case 'n': + no_prefix = 1; + break; case 'r': data->can_repeat = 1; break; @@ -78,6 +81,8 @@ cmd_bind_key_parse(struct cmd *self, int argc, char **argv, char **cause) xasprintf(cause, "unknown key: %s", argv[0]); goto error; } + if (!no_prefix) + data->key |= KEYC_PREFIX; argc--; argv++; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index af3a0208..717812d9 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -46,27 +46,33 @@ cmd_list_keys_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct key_binding *bd; const char *key; - char tmp[BUFSIZ]; - int width, keywidth; + char tmp[BUFSIZ], keytmp[64]; + int width, keywidth; width = 0; SPLAY_FOREACH(bd, key_bindings, &key_bindings) { - if ((key = key_string_lookup_key(bd->key)) == NULL) + key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); + if (key == NULL) continue; keywidth = strlen(key) + 1; + if (!(bd->key & KEYC_PREFIX)) + keywidth += 2; if (keywidth > width) width = keywidth; } - SPLAY_FOREACH(bd, key_bindings, &key_bindings) { - if ((key = key_string_lookup_key(bd->key)) == NULL) + key = key_string_lookup_key(bd->key & ~KEYC_PREFIX); + if (key == NULL) continue; *tmp = '\0'; cmd_list_print(bd->cmdlist, tmp, sizeof tmp); - + if (!(bd->key & KEYC_PREFIX)) { + xsnprintf(keytmp, sizeof keytmp, "[%s]", key); + key = keytmp; + } ctx->print(ctx, "%*s: %s", width, key, tmp); } diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 7272bc77..0100e5a9 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -36,7 +36,7 @@ struct cmd_unbind_key_data { const struct cmd_entry cmd_unbind_key_entry = { "unbind-key", "unbind", - "key", + "[-n] key", 0, 0, NULL, cmd_unbind_key_parse, @@ -51,12 +51,15 @@ int cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) { struct cmd_unbind_key_data *data; - int opt; + int opt, no_prefix = 0; self->data = data = xmalloc(sizeof *data); - while ((opt = getopt(argc, argv, "")) != -1) { + while ((opt = getopt(argc, argv, "n")) != -1) { switch (opt) { + case 'n': + no_prefix = 1; + break; default: goto usage; } @@ -70,6 +73,8 @@ cmd_unbind_key_parse(struct cmd *self, int argc, char **argv, char **cause) xasprintf(cause, "unknown key: %s", argv[0]); goto error; } + if (!no_prefix) + data->key |= KEYC_PREFIX; return (0); diff --git a/key-bindings.c b/key-bindings.c index d37e23b3..186c1a9b 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -32,7 +32,18 @@ struct key_bindings dead_key_bindings; int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) { - return (bd1->key - bd2->key); + int key1, key2; + + key1 = bd1->key & ~KEYC_PREFIX; + key2 = bd2->key & ~KEYC_PREFIX; + if (key1 != key2) + return (key1 - key2); + + if (bd1->key & KEYC_PREFIX && !(bd2->key & KEYC_PREFIX)) + return (-1); + if (bd2->key & KEYC_PREFIX && !(bd1->key & KEYC_PREFIX)) + return (1); + return (0); } struct key_binding * @@ -170,7 +181,8 @@ key_bindings_init(void) cmd->entry->init(cmd, table[i].key); TAILQ_INSERT_HEAD(cmdlist, cmd, qentry); - key_bindings_add(table[i].key, table[i].can_repeat, cmdlist); + key_bindings_add( + table[i].key | KEYC_PREFIX, table[i].can_repeat, cmdlist); } } diff --git a/server.c b/server.c index 8012e900..ce793076 100644 --- a/server.c +++ b/server.c @@ -802,14 +802,19 @@ server_handle_client(struct client *c) if (!(c->flags & CLIENT_PREFIX)) { if (key == prefix) c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); + else { + /* Try as a non-prefix key binding. */ + if ((bd = key_bindings_lookup(key)) == NULL) + window_pane_key(wp, c, key); + else + key_bindings_dispatch(bd, c); + } continue; } /* Prefix key already pressed. Reset prefix and lookup key. */ c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key)) == NULL) { + if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { /* If repeating, treat this as a key, else ignore. */ if (c->flags & CLIENT_REPEAT) { c->flags &= ~CLIENT_REPEAT; diff --git a/tmux.1 b/tmux.1 index 1d70e88f..54e46a3d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -617,7 +617,7 @@ If no server is started, will attempt to start it; this will fail unless sessions are created in the configuration file. .It Xo Ic bind-key -.Op Fl r +.Op Fl nr .Ar key Ar command Op Ar arguments .Xc .D1 (alias: Ic bind ) @@ -632,6 +632,13 @@ or for Ctrl keys, or .Ql M- for Alt (meta) keys. +If +.Fl n +is specified, it is not necessary to use the prefix key, +.Ar command +is bound to +.Ar key +alone. The .Fl r flag indicates this key may repeat, see the @@ -842,6 +849,10 @@ List the syntax of all commands supported by .Xc .D1 (alias: Ic lsk ) List all key bindings. +Keys bound without the prefix key (see +.Ic bind-key +.Fl n ) +are enclosed in square brackets. .It Xo Ic list-sessions .Xc .D1 (alias: Ic ls ) @@ -1613,11 +1624,17 @@ Switch the current session for client to .Ar target-session . .It Xo Ic unbind-key +.Op Fl n .Ar key .Xc .D1 (alias: Ic unbind ) Unbind the command bound to .Ar key . +If +.Fl n +is specified, the command bound to +.Ar key +without a prefix (if any) is removed. .It Xo Ic unlink-window .Op Fl k .Op Fl t Ar target-window diff --git a/tmux.h b/tmux.h index e57b607c..2eeb9f5d 100644 --- a/tmux.h +++ b/tmux.h @@ -102,10 +102,12 @@ struct buffer { #define BELL_CURRENT 2 /* Key codes. ncurses defines KEY_*. Grrr. */ -#define KEYC_NONE 0x0fff -#define KEYC_ESCAPE 0x2000 -#define KEYC_CTRL 0x4000 -#define KEYC_SHIFT 0x8000 +#define KEYC_NONE 0xfff +/* 0x1000 is base for special keys */ +#define KEYC_ESCAPE 0x2000 +#define KEYC_CTRL 0x4000 +#define KEYC_SHIFT 0x8000 +#define KEYC_PREFIX 0x10000 enum key_code { /* Mouse key. */ @@ -856,8 +858,6 @@ struct client_ctx { /* Key/command line command. */ struct cmd_ctx { - struct client *cmdclient; - /* * curclient is the client where this command was executed if inside * tmux. This is NULL if the command came from the command-line. @@ -869,6 +869,8 @@ struct cmd_ctx { * configuration file. */ struct client *curclient; + struct client *cmdclient; + struct session *cursession; struct msg_command_data *msgdata; -- cgit v1.2.3