The branch, master has been updated via 0a88377086329786c438d4973365fdb21186f4e4 (commit) via 3909aff06aa6de748ae057cab1e723eec2387edd (commit) via 69f292a90e2fb9d48a77a9753127da13554715de (commit) via 93b2871cab399388a16ace64d8dfb9a8e2143543 (commit) via 7a72eff4a4717e975ab7ef39baff5667b12e8a13 (commit) via d16b640fe8583878d23436bd7515a8adade9faeb (commit) via 0e7219d437ce565a518b336a5db112eaeaeddc5c (commit) via d1337053b6119c4aab0c38b5fc082acf2fdfcbb1 (commit) via 4cf4302962558be4d5e7a87c57f084d1187fa330 (commit) via 1f404f6a23969516007c77eeec89876154c9a4a4 (commit) via bc3786ece940dc9c68f731734b45c129e0542ac7 (commit) via 0610f443808cc284171a4abc14bd3f95a9f3a57b (commit) via 07d93db427751512e6ae96a54e69846189da2dc2 (commit) via bded7437064c76dd6cf4e76e558d826859adcc79 (commit) via 3497843f0272e573d0a63cb6e94948591ae07667 (commit) from b25dc423b0b1369aaec5dee8e051d541bd55043f (commit)
- Log ----------------------------------------------------------------- commit 0a88377086329786c438d4973365fdb21186f4e4 Merge: b25dc42 3909aff Author: Thomas Adam <tho...@xteddy.org> Commit: Thomas Adam <tho...@xteddy.org> Merge branch 'obsd-master' client.c | 9 ++- cmd-bind-key.c | 16 ++++-- cmd-copy-mode.c | 5 +- cmd-if-shell.c | 33 +++++++---- cmd-list-keys.c | 86 ++++++++++++++++------------ cmd-move-window.c | 12 ++++- cmd-switch-client.c | 19 +++++- cmd-unbind-key.c | 37 +++++++++---- cmd.c | 8 +- format.c | 13 ++++- input-keys.c | 1 + key-bindings.c | 114 ++++++++++++++++++++++++++++--------- layout-custom.c | 4 +- server-client.c | 156 +++++++++++++++++++++++++++++++-------------------- server-fn.c | 1 - server.c | 22 +++++--- tmux.1 | 108 +++++++++++++++++++++++++---------- tmux.h | 41 +++++++++----- utf8.c | 4 +- window-copy.c | 16 ++--- window.c | 1 + 21 files changed, 469 insertions(+), 237 deletions(-) diff --cc server.c index 9b11e01,c810177..c02703b --- a/server.c +++ b/server.c @@@ -151,11 -150,12 +149,14 @@@ server_start(int lockfd, char *lockfile start_time = time(NULL); log_debug("socket path %s", socket_path); +#ifdef HAVE_SETPROCTITLE setproctitle("server (%s)", socket_path); +#endif server_fd = server_create_socket(); + if (server_fd == -1) + fatal("couldn't create socket"); + server_update_socket(); server_client_create(pair[1]); unlink(lockfile); commit 3909aff06aa6de748ae057cab1e723eec2387edd Author: nicm <nicm> Commit: nicm <nicm> Look up indexes as number before name, makes more sense if windows are named starting with numbers. From Thomas Adam. --- cmd.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd.c b/cmd.c index dd1a0a7..991e079 100644 --- a/cmd.c +++ b/cmd.c @@ -781,15 +781,15 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous) const char *errstr; u_int idx; + idx = strtonum(name, 0, INT_MAX, &errstr); + if (errstr == NULL) + return (idx); + if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL) return (wl->idx); if (*ambiguous) return (-1); - idx = strtonum(name, 0, INT_MAX, &errstr); - if (errstr == NULL) - return (idx); - return (-1); } commit 69f292a90e2fb9d48a77a9753127da13554715de Author: nicm <nicm> Commit: nicm <nicm> Always format real layout even when zoomed. --- format.c | 5 ++++- layout-custom.c | 4 ++-- tmux.h | 2 +- window.c | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/format.c b/format.c index 2be9834..7ded05d 100644 --- a/format.c +++ b/format.c @@ -577,7 +577,10 @@ format_defaults_window(struct format_tree *ft, struct window *w) ft->w = w; - layout = layout_dump(w); + if (w->saved_layout_root != NULL) + layout = layout_dump(w->saved_layout_root); + else + layout = layout_dump(w->layout_root); format_add(ft, "window_id", "@%u", w->id); format_add(ft, "window_name", "%s", w->name); diff --git a/layout-custom.c b/layout-custom.c index c9cf49c..5750351 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -55,12 +55,12 @@ layout_checksum(const char *layout) /* Dump layout as a string. */ char * -layout_dump(struct window *w) +layout_dump(struct layout_cell *root) { char layout[BUFSIZ], *out; *layout = '\0'; - if (layout_append(w->layout_root, layout, sizeof layout) != 0) + if (layout_append(root, layout, sizeof layout) != 0) return (NULL); xasprintf(&out, "%04x,%s", layout_checksum(layout), layout); diff --git a/tmux.h b/tmux.h index 1af4d07..53fd9b2 100644 --- a/tmux.h +++ b/tmux.h @@ -2225,7 +2225,7 @@ struct layout_cell *layout_split_pane( void layout_close_pane(struct window_pane *); /* layout-custom.c */ -char *layout_dump(struct window *); +char *layout_dump(struct layout_cell *); int layout_parse(struct window *, const char *); /* layout-set.c */ diff --git a/window.c b/window.c index 86cc8bb..3c8d495 100644 --- a/window.c +++ b/window.c @@ -519,6 +519,7 @@ window_unzoom(struct window *w) w->flags &= ~WINDOW_ZOOMED; layout_free(w); w->layout_root = w->saved_layout_root; + w->saved_layout_root = NULL; TAILQ_FOREACH(wp, &w->panes, entry) { wp->layout_cell = wp->saved_layout_cell; commit 93b2871cab399388a16ace64d8dfb9a8e2143543 Author: nicm <nicm> Commit: nicm <nicm> Do not die on USR1 if any of the socket parent directories are missing. Reported by Robin Powell. --- server.c | 22 ++++++++++++++-------- tmux.1 | 6 ++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/server.c b/server.c index 26bfddf..c810177 100644 --- a/server.c +++ b/server.c @@ -79,24 +79,22 @@ server_create_socket(void) size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); if (size >= sizeof sa.sun_path) { errno = ENAMETOOLONG; - fatal("socket failed"); + return (-1); } unlink(sa.sun_path); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket failed"); + return (-1); mask = umask(S_IXUSR|S_IXGRP|S_IRWXO); if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) - fatal("bind failed"); + return (-1); umask(mask); if (listen(fd, 16) == -1) - fatal("listen failed"); + return (-1); setblocking(fd, 0); - server_update_socket(); - return (fd); } @@ -155,6 +153,9 @@ server_start(int lockfd, char *lockfile) setproctitle("server (%s)", socket_path); server_fd = server_create_socket(); + if (server_fd == -1) + fatal("couldn't create socket"); + server_update_socket(); server_client_create(pair[1]); unlink(lockfile); @@ -387,6 +388,7 @@ server_add_accept(int timeout) void server_signal_callback(int sig, unused short events, unused void *data) { + int fd; switch (sig) { case SIGTERM: server_shutdown = 1; @@ -397,8 +399,12 @@ server_signal_callback(int sig, unused short events, unused void *data) break; case SIGUSR1: event_del(&server_ev_accept); - close(server_fd); - server_fd = server_create_socket(); + fd = server_create_socket(); + if (fd != -1) { + close(server_fd); + server_fd = fd; + server_update_socket(); + } server_add_accept(0); break; } diff --git a/tmux.1 b/tmux.1 index ab76238..68e9b9d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -163,7 +163,8 @@ If the socket is accidentally removed, the .Dv SIGUSR1 signal may be sent to the .Nm -server process to recreate it. +server process to recreate it (note that this will fail if any parent +directories are missing). .It Fl l Behave as a login shell. This flag currently has no effect and is for compatibility with other shells @@ -2004,7 +2005,8 @@ is bound in .Ar mode-table : the binding for command mode with .Fl c -or for normal mode without. See the +or for normal mode without. +See the .Sx WINDOWS AND PANES section and the .Ic list-keys commit 7a72eff4a4717e975ab7ef39baff5667b12e8a13 Author: nicm <nicm> Commit: nicm <nicm> Simplify error messages when socket connect fails, suggested by "Karthik K". --- client.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 6d4b8a5..d3ff05a 100644 --- a/client.c +++ b/client.c @@ -265,8 +265,13 @@ client_main(int argc, char **argv, int flags) /* Initialize the client socket and start the server. */ fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); if (fd == -1) { - fprintf(stderr, "failed to connect to server: %s\n", - strerror(errno)); + if (errno == ECONNREFUSED) { + fprintf(stderr, "no server running on %s\n", + socket_path); + } else { + fprintf(stderr, "error connecting to %s (%s)\n", + socket_path, strerror(errno)); + } return (1); } commit d16b640fe8583878d23436bd7515a8adade9faeb Author: nicm <nicm> Commit: nicm <nicm> The free callback could end up being fired before the done callback (happens on Cygwin), so use a reference count instead of a single flag. SF bug 188 reported by "iceboy". --- cmd-if-shell.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 9c57761..cdd2135 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -51,7 +51,7 @@ struct cmd_if_shell_data { struct mouse_event mouse; int bflag; - int started; + int references; }; enum cmd_retval @@ -113,11 +113,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) cdata->bflag = args_has(args, 'b'); - cdata->started = 0; cdata->cmdq = cmdq; memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse); cmdq->references++; + cdata->references = 1; job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata); free(shellcmd); @@ -152,12 +152,11 @@ cmd_if_shell_callback(struct job *job) return; } - cdata->started = 1; - cmdq1 = cmdq_new(cmdq->client); cmdq1->emptyfn = cmd_if_shell_done; cmdq1->data = cdata; + cdata->references++; cmdq_run(cmdq1, cmdlist, &cdata->mouse); cmd_list_free(cmdlist); } @@ -170,12 +169,14 @@ cmd_if_shell_done(struct cmd_q *cmdq1) if (cmdq1->client_exit >= 0) cmdq->client_exit = cmdq1->client_exit; + cmdq_free(cmdq1); + + if (--cdata->references != 0) + return; if (!cmdq_free(cmdq) && !cdata->bflag) cmdq_continue(cmdq); - cmdq_free(cmdq1); - free(cdata->cmd_else); free(cdata->cmd_if); free(cdata); @@ -187,7 +188,7 @@ cmd_if_shell_free(void *data) struct cmd_if_shell_data *cdata = data; struct cmd_q *cmdq = cdata->cmdq; - if (cdata->started) + if (--cdata->references != 0) return; if (!cmdq_free(cmdq) && !cdata->bflag) commit 0e7219d437ce565a518b336a5db112eaeaeddc5c Author: nicm <nicm> Commit: nicm <nicm> Fix moving windows to nonexistent indexes when renumber-windows is off. From Thomas Adam, reported by Daniel Levai and Theo Buehler. --- cmd-move-window.c | 12 +++++++++++- server-fn.c | 1 - 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cmd-move-window.c b/cmd-move-window.c index 3064cd6..e765b62 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -51,7 +51,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) struct session *src, *dst, *s; struct winlink *wl; char *cause; - int idx, kflag, dflag; + int idx, kflag, dflag, sflag; if (args_has(args, 'r')) { s = cmd_find_session(cmdq, args_get(args, 't'), 0); @@ -71,6 +71,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) kflag = args_has(self->args, 'k'); dflag = args_has(self->args, 'd'); + sflag = args_has(self->args, 's'); if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { cmdq_error(cmdq, "can't link window: %s", cause); @@ -79,6 +80,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) } if (self->entry == &cmd_move_window_entry) server_unlink_window(src, wl); + + /* + * Renumber the winlinks in the src session only, the destination + * session already has the correct winlink id to us, either + * automatically or specified by -s. + */ + if (!sflag && options_get_number(&src->options, "renumber-windows")) + session_renumber_windows(src); + recalculate_sizes(); return (CMD_RETURN_NORMAL); diff --git a/server-fn.c b/server-fn.c index a065dd7..83ea947 100644 --- a/server-fn.c +++ b/server-fn.c @@ -351,7 +351,6 @@ server_unlink_window(struct session *s, struct winlink *wl) server_destroy_session_group(s); else server_redraw_session_group(s); - session_renumber_windows(s); } void commit d1337053b6119c4aab0c38b5fc082acf2fdfcbb1 Author: nicm <nicm> Commit: nicm <nicm> Bind mouse dragging so that it is passed through to applications if they want it rather than entering copy mode. --- cmd-copy-mode.c | 5 ++++- key-bindings.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 19dca5f..d729ada 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -68,8 +68,11 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); window_copy_init_from_pane(wp); } - if (args_has(args, 'M')) + if (args_has(args, 'M')) { + if (wp->mode != NULL && wp->mode != &window_copy_mode) + return (CMD_RETURN_NORMAL); window_copy_start_drag(c, &cmdq->item->mouse); + } if (wp->mode == &window_copy_mode && args_has(self->args, 'u')) window_copy_pageup(wp); diff --git a/key-bindings.c b/key-bindings.c index c34db71..670300a 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -221,7 +221,7 @@ key_bindings_init(void) "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M", "bind -n MouseDrag1Border resize-pane -M", "bind -n MouseDown1Status select-window -t=", - "bind -n MouseDrag1Pane copy-mode -M", + "bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'", }; u_int i; struct cmd_list *cmdlist; commit 4cf4302962558be4d5e7a87c57f084d1187fa330 Author: nicm <nicm> Commit: nicm <nicm> Don't eat the mouse event that triggers a drag end because we may want to pass it on to application inside the pane. --- input-keys.c | 1 + server-client.c | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/input-keys.c b/input-keys.c index ae00e4a..d812a90 100644 --- a/input-keys.c +++ b/input-keys.c @@ -251,5 +251,6 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m) buf[len++] = x + 33; buf[len++] = y + 33; } + log_debug("writing mouse %.*s", (int)len, buf); bufferevent_write(wp->event, buf, len); } diff --git a/server-client.c b/server-client.c index b4d1f74..c022a36 100644 --- a/server-client.c +++ b/server-client.c @@ -391,7 +391,7 @@ server_client_check_mouse(struct client *c) c->tty.mouse_drag_release = NULL; c->tty.mouse_drag_flag = 0; - return (KEYC_NONE); + return (KEYC_MOUSE); /* not a key, but still may want to pass */ } /* Convert to a key binding. */ commit 1f404f6a23969516007c77eeec89876154c9a4a4 Author: nicm <nicm> Commit: nicm <nicm> Put mouse_any_flag back, don't know where it went to (still in man page). --- format.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/format.c b/format.c index eb4664d..2be9834 100644 --- a/format.c +++ b/format.c @@ -729,6 +729,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "wrap_flag", "%d", !!(wp->base.mode & MODE_WRAP)); + format_add(ft, "mouse_any_flag", "%d", + !!(wp->base.mode & (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON))); format_add(ft, "mouse_standard_flag", "%d", !!(wp->base.mode & MODE_MOUSE_STANDARD)); format_add(ft, "mouse_button_flag", "%d", commit bc3786ece940dc9c68f731734b45c129e0542ac7 Author: nicm <nicm> Commit: nicm <nicm> Pass mouse events through to commands for if-shell. --- cmd-if-shell.c | 20 +++++++++++++------- 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 9659511..9c57761 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -44,11 +44,14 @@ const struct cmd_entry cmd_if_shell_entry = { }; struct cmd_if_shell_data { - char *cmd_if; - char *cmd_else; - struct cmd_q *cmdq; - int bflag; - int started; + char *cmd_if; + char *cmd_else; + + struct cmd_q *cmdq; + struct mouse_event mouse; + + int bflag; + int started; }; enum cmd_retval @@ -95,21 +98,24 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) } return (CMD_RETURN_ERROR); } - cmdq_run(cmdq, cmdlist, NULL); + cmdq_run(cmdq, cmdlist, &cmdq->item->mouse); cmd_list_free(cmdlist); return (CMD_RETURN_NORMAL); } cdata = xmalloc(sizeof *cdata); + cdata->cmd_if = xstrdup(args->argv[1]); if (args->argc == 3) cdata->cmd_else = xstrdup(args->argv[2]); else cdata->cmd_else = NULL; + cdata->bflag = args_has(args, 'b'); cdata->started = 0; cdata->cmdq = cmdq; + memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse); cmdq->references++; job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata); @@ -152,7 +158,7 @@ cmd_if_shell_callback(struct job *job) cmdq1->emptyfn = cmd_if_shell_done; cmdq1->data = cdata; - cmdq_run(cmdq1, cmdlist, NULL); + cmdq_run(cmdq1, cmdlist, &cdata->mouse); cmd_list_free(cmdlist); } commit 0610f443808cc284171a4abc14bd3f95a9f3a57b Author: nicm <nicm> Commit: nicm <nicm> cmd_mouse_pane can return NULL, check for that. --- window-copy.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/window-copy.c b/window-copy.c index 4dc0735..eb00131 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2220,7 +2220,7 @@ window_copy_start_drag(struct client *c, unused struct mouse_event *m) u_int x, y; wp = cmd_mouse_pane(m, NULL, NULL); - if (wp->mode != &window_copy_mode) + if (wp == NULL || wp->mode != &window_copy_mode) return; if (cmd_mouse_at(wp, m, &x, &y, 1) != 0) @@ -2242,7 +2242,7 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m) u_int x, y, old_cy; wp = cmd_mouse_pane(m, NULL, NULL); - if (wp->mode != &window_copy_mode) + if (wp == NULL || wp->mode != &window_copy_mode) return; data = wp->modedata; @@ -2261,7 +2261,7 @@ window_copy_drag_release(unused struct client *c, struct mouse_event *m) struct window_pane *wp; wp = cmd_mouse_pane(m, NULL, NULL); - if (wp->mode != &window_copy_mode) + if (wp == NULL || wp->mode != &window_copy_mode) return; window_copy_copy_selection(wp, NULL); commit 07d93db427751512e6ae96a54e69846189da2dc2 Author: nicm <nicm> Commit: nicm <nicm> Remove unused-but-set variables, from Thomas Adam. --- window-copy.c | 10 +++------- 1 files changed, 3 insertions(+), 7 deletions(-) diff --git a/window-copy.c b/window-copy.c index afa609e..4dc0735 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2216,14 +2216,12 @@ window_copy_rectangle_toggle(struct window_pane *wp) void window_copy_start_drag(struct client *c, unused struct mouse_event *m) { - struct window_pane *wp; - struct window_copy_mode_data *data; - u_int x, y; + struct window_pane *wp; + u_int x, y; wp = cmd_mouse_pane(m, NULL, NULL); if (wp->mode != &window_copy_mode) return; - data = wp->modedata; if (cmd_mouse_at(wp, m, &x, &y, 1) != 0) return; @@ -2260,13 +2258,11 @@ window_copy_drag_update(unused struct client *c, struct mouse_event *m) void window_copy_drag_release(unused struct client *c, struct mouse_event *m) { - struct window_pane *wp; - struct window_copy_mode_data *data; + struct window_pane *wp; wp = cmd_mouse_pane(m, NULL, NULL); if (wp->mode != &window_copy_mode) return; - data = wp->modedata; window_copy_copy_selection(wp, NULL); window_pane_reset_mode(wp); commit bded7437064c76dd6cf4e76e558d826859adcc79 Author: nicm <nicm> Commit: nicm <nicm> Support for multiple key tables to commands to be bound to sequences of keys. The default key bindings become the "prefix" table and -n the "root" table. Keys may be bound in new tables with bind -T and switch-client -T used to specify the table in which the next key should be looked up. Based on a diff from Keith Amling. --- cmd-bind-key.c | 16 ++++-- cmd-list-keys.c | 86 ++++++++++++++++------------ cmd-switch-client.c | 19 +++++- cmd-unbind-key.c | 37 +++++++++---- format.c | 6 ++- key-bindings.c | 112 ++++++++++++++++++++++++++++--------- server-client.c | 156 +++++++++++++++++++++++++++++++-------------------- tmux.1 | 106 ++++++++++++++++++++++++---------- tmux.h | 39 +++++++++---- 9 files changed, 387 insertions(+), 190 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 47c58e5..fda39ef 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -33,8 +33,8 @@ enum cmd_retval cmd_bind_key_mode_table(struct cmd *, struct cmd_q *, int); 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, struct cmd_q *cmdq) 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, struct cmd_q *cmdq) 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, struct cmd_q *cmdq) 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); } diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 0733ee2..e2d5dc5 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -33,8 +33,8 @@ enum cmd_retval cmd_list_keys_commands(struct cmd *, struct cmd_q *); 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,11 +51,12 @@ 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)); @@ -63,46 +64,57 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_q *cmdq) if (args_has(args, 't')) return (cmd_list_keys_table(self, cmdq)); - width = 0; + tablename = args_get(args, 'T'); + if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) { + cmdq_error(cmdq, "table %s doesn't exist", tablename); + return (CMD_RETURN_ERROR); + } - 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; - - cmd_list_print(bd->cmdlist, tmp + used, (sizeof tmp) - used); - cmdq_print(cmdq, "bind-key %s", tmp); + 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); + } + + cmdq_print(cmdq, "bind-key %s", tmp); + } } return (CMD_RETURN_NORMAL); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 439f593..8c4daf9 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); 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 cmd_q *cmdq) 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); @@ -58,6 +59,18 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) 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'); if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 710210c..493f6dd 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_unbind_key_mode_table(struct cmd *, struct cmd_q *, int); 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_entry = { 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,31 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) 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); + tablename = args_get(args, 'T'); + if (tablename == NULL) { + key_bindings_remove_table("root"); + key_bindings_remove_table("prefix"); + return (CMD_RETURN_NORMAL); } + if (key_bindings_get_table(tablename, 0) == NULL) { + cmdq_error(cmdq, "table %s doesn't exist", tablename); + return (CMD_RETURN_ERROR); + } + key_bindings_remove_table(tablename); 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'); + if (key_bindings_get_table(tablename, 0) == NULL) { + cmdq_error(cmdq, "table %s doesn't exist", tablename); + return (CMD_RETURN_ERROR); + } + } else if (args_has(args, 'n')) + tablename = "root"; + else + tablename = "prefix"; + key_bindings_remove(tablename, key); return (CMD_RETURN_NORMAL); } diff --git a/format.c b/format.c index cf1713b..eb4664d 100644 --- a/format.c +++ b/format.c @@ -545,7 +545,11 @@ format_defaults_client(struct format_tree *ft, struct client *c) 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); diff --git a/key-bindings.c b/key-bindings.c index c6cdeeb..c34db71 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -25,60 +25,120 @@ #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; - - 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); + return (bd1->key - bd2->key); } -struct key_binding * -key_bindings_lookup(int key) +struct key_table * +key_bindings_get_table(const char *name, int create) { - struct key_binding bd; + struct key_table table_find, *table; + + table_find.name = name; + table = RB_FIND(key_tables, &key_tables, &table_find); + if (table != NULL || !create) + return (table); - bd.key = key; - return (RB_FIND(key_bindings, &key_bindings, &bd)); + table = xmalloc(sizeof *table); + table->name = xstrdup(name); + RB_INIT(&table->key_bindings); + + table->references = 1; /* one reference in key_tables */ + RB_INSERT(key_tables, &key_tables, table); + + return (table); } void -key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) +key_bindings_unref_table(struct key_table *table) { struct key_binding *bd; - key_bindings_remove(key); + 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(const char *name, int key, int can_repeat, + struct cmd_list *cmdlist) +{ + struct key_table *table; + struct key_binding bd_find, *bd; + + table = key_bindings_get_table(name, 1); + + bd_find.key = key; + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); + 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_find, *bd; + + table = key_bindings_get_table(name, 0); + if (table == NULL) + return; - if ((bd = key_bindings_lookup(key)) == NULL) + bd_find.key = key; + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); + 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) { + RB_REMOVE(key_tables, &key_tables, table); + key_bindings_unref_table(table); + } } void @@ -169,8 +229,6 @@ key_bindings_init(void) int error; struct cmd_q *cmdq; - RB_INIT(&key_bindings); - cmdq = cmdq_new(NULL); for (i = 0; i < nitems(defaults); i++) { error = cmd_string_parse(defaults[i], &cmdlist, diff --git a/server-client.c b/server-client.c index 3968c50..b4d1f74 100644 --- a/server-client.c +++ b/server-client.c @@ -30,6 +30,7 @@ #include "tmux.h" +void server_client_key_table(struct client *, const char *); void server_client_check_focus(struct window_pane *); void server_client_check_resize(struct window_pane *); int server_client_check_mouse(struct client *); @@ -45,6 +46,15 @@ void server_client_msg_command(struct client *, struct imsg *); void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); +/* Set client key table. */ +void +server_client_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++; +} + /* Create a new client. */ void server_client_create(int fd) @@ -93,6 +103,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++) { @@ -164,6 +177,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); @@ -527,16 +542,19 @@ void server_client_handle_key(struct client *c, int key) { struct mouse_event *m = &c->tty.mouse; - 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_find, *bd; + int xtimeout; /* Check the client is good to accept input. */ - if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) + if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) return; + w = s->curw->window; + wp = w->active; /* No session, do nothing. */ if (c->session == NULL) @@ -552,7 +570,7 @@ server_client_handle_key(struct client *c, int key) sizeof s->last_activity_time); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); - /* 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; @@ -593,74 +611,88 @@ server_client_handle_key(struct client *c, int key) } else m->valid = 0; - /* 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 prefix as a regular key when pasting is detected. */ - ispaste = server_client_assume_paste(s); - if (ispaste) - 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, c, s, key, m); + return; + } - /* 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_find.key = key; + bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); + 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_client_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, c, s, key, m); - } else - key_bindings_dispatch(bd, c, m); - 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, c, s, key, m); + server_client_key_table(c, "root"); } + server_status_client(c); + + /* Dispatch the key binding. */ + key_bindings_dispatch(bd, c, m); + 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_client_key_table(c, "root"); c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c, s, key, m); - 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_client_key_table(c, "root"); + server_status_client(c); + return; } - /* Dispatch the command. */ - key_bindings_dispatch(bd, c, m); + /* + * 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_client_key_table(c, "prefix"); + server_status_client(c); + } else if (!(c->flags & CLIENT_READONLY)) + window_pane_key(wp, c, s, key, m); } /* Client functions that need to happen every loop. */ @@ -848,9 +880,9 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) 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_client_key_table(c, "root"); + c->flags &= ~CLIENT_REPEAT; + server_status_client(c); } } diff --git a/tmux.1 b/tmux.1 index 9b6f834..ab76238 100644 --- a/tmux.1 +++ b/tmux.1 @@ -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,22 @@ respectively. toggles whether a client is read-only (see the .Ic attach-session command). +.Pp +.Fl T +sets the client's key table; the next key from the client will be interpreted from +.Ar key-table . +This may be used to configure multiple prefix keys, or to bind commands to +sequences of keys. +For example, to make typing +.Ql abc +run the +.Ic list-keys +command: +.Bd -literal -offset indent +bind-key -Ttable2 c list-keys +bind-key -Ttable1 b switch-client -Ttable2 +bind-key -Troot a switch-client -Ttable1 +.Ed .El .Sh WINDOWS AND PANES A @@ -1931,6 +1948,7 @@ Commands related to key bindings are as follows: .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 ) @@ -1938,16 +1956,40 @@ Bind key .Ar key to .Ar command . -By default (without -.Fl t ) -the primary key bindings are modified (those normally activated with the prefix -key); in this case, if -.Fl n -is specified, it is not necessary to use the prefix key, -.Ar command +Keys are bound in a key table. +By default (without -T), the key is bound in +the +.Em prefix +key table. +This table is used for keys pressed after the prefix key (for example, +by default +.Ql c is bound to -.Ar key -alone. +.Ic new-window +in the +.Em prefix +table, so +.Ql C-b c +creates a new window). +The +.Em root +table is used for keys pressed without the prefix key: binding +.Ql c +to +.Ic new-window +in the +.Em root +table (not recommended) means a plain +.Ql c +will create a new window. +.Fl n +is an alias +for +.Fl T Ar root . +Keys may also be bound in custom key tables and the +.Ic switch-client +.Fl T +command used to switch to them from a key binding. The .Fl r flag indicates this key may repeat, see the @@ -1962,22 +2004,33 @@ is bound in .Ar mode-table : the binding for command mode with .Fl c -or for normal mode without. +or for normal mode without. See the +.Sx WINDOWS AND PANES +section and the +.Ic list-keys +command for information on mode key bindings. +.Pp To view the default bindings and possible commands, see the .Ic list-keys command. -.It Ic list-keys Op Fl t Ar key-table +.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. +.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 , @@ -2022,31 +2075,22 @@ the secondary prefix key, to a window as if it was pressed. .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 ) Unbind the command bound to .Ar key . -Without +.Fl c , +.Fl n , +.Fl T +and .Fl t -the primary key bindings are modified; in this case, if -.Fl n -is specified, the command bound to -.Ar key -without a prefix (if any) is removed. +are the same as for +.Ic bind-key . If .Fl a is present, all key bindings are removed. -.Pp -If -.Fl t -is present, -.Ar key -in -.Ar mode-table -is unbound: the binding for command mode with -.Fl c -or for normal mode without. .El .Sh OPTIONS The appearance and behaviour of diff --git a/tmux.h b/tmux.h index 477fd43..1af4d07 100644 --- a/tmux.h +++ b/tmux.h @@ -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) /* Is this a mouse key? */ @@ -1301,7 +1300,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 @@ -1320,6 +1319,7 @@ struct client { #define CLIENT_256COLOURS 0x20000 #define CLIENT_IDENTIFIED 0x40000 int flags; + struct key_table *keytable; struct event identify_timer; @@ -1440,15 +1440,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 @@ -1876,12 +1885,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 *, struct mouse_event *); commit 3497843f0272e573d0a63cb6e94948591ae07667 Author: nicm <nicm> Commit: nicm <nicm> Style nit - unnecessary brackets. --- utf8.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utf8.c b/utf8.c index 2940ebb..12a0b29 100644 --- a/utf8.c +++ b/utf8.c @@ -290,9 +290,9 @@ utf8_build(void) while (*ptr != NULL) { node = *ptr; if (item->last < node->first) - ptr = &(node->left); + ptr = &node->left; else if (item->first > node->last) - ptr = &(node->right); + ptr = &node->right; } *ptr = item; } ----------------------------------------------------------------------- Summary of changes: client.c | 9 ++- cmd-bind-key.c | 16 ++++-- cmd-copy-mode.c | 5 +- cmd-if-shell.c | 33 +++++++---- cmd-list-keys.c | 86 ++++++++++++++++------------ cmd-move-window.c | 12 ++++- cmd-switch-client.c | 19 +++++- cmd-unbind-key.c | 37 +++++++++---- cmd.c | 8 +- format.c | 13 ++++- input-keys.c | 1 + key-bindings.c | 114 ++++++++++++++++++++++++++++--------- layout-custom.c | 4 +- server-client.c | 156 +++++++++++++++++++++++++++++++-------------------- server-fn.c | 1 - server.c | 22 +++++--- tmux.1 | 108 +++++++++++++++++++++++++---------- tmux.h | 41 +++++++++----- utf8.c | 4 +- window-copy.c | 16 ++--- window.c | 1 + 21 files changed, 469 insertions(+), 237 deletions(-) hooks/post-receive -- tmux ------------------------------------------------------------------------------ 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-cvs mailing list tmux-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-cvs