From 021c64310daa4ae4c4e8af08f17c994f21237758 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 16 Dec 2015 21:50:37 +0000 Subject: [PATCH 1/2] Add infrastructure to work out the best target given a pane or window alone and use it to add pane_died and pane_exited hooks. --- cmd-attach-session.c | 2 +- cmd-find.c | 53 ++++++++++++++++++++++++++++++++++++++++---- cmd-queue.c | 4 ++++ cmd-respawn-window.c | 2 +- hooks.c | 20 +++++++++++++++-- server-client.c | 4 ++-- server-fn.c | 9 +++++++- server.c | 2 +- tmux.1 | 6 +++++ window.c | 2 +- 10 files changed, 91 insertions(+), 13 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 586863aa..4d8a75f8 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -144,7 +144,7 @@ cmd_attach_session(struct cmd_q *cmdq, int dflag, int rflag, const char *cflag, if (~c->flags & CLIENT_CONTROL) proc_send(c->peer, MSG_READY, -1, NULL, 0); - hooks_run(c->session->hooks, c, "client-attached"); + hooks_run(c->session->hooks, c, NULL, "client-attached"); cmdq->client_exit = 0; } recalculate_sizes(); diff --git a/cmd-find.c b/cmd-find.c index cf39240a..15dfa596 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -190,7 +190,7 @@ cmd_find_best_session_with_window(struct cmd_find_state *fs) u_int ssize; struct session *s; - if (fs->cmdq->client != NULL) { + if (fs->cmdq != NULL && fs->cmdq->client != NULL) { fs->s = cmd_find_try_TMUX(fs->cmdq->client, fs->w); if (fs->s != NULL) return (cmd_find_best_winlink_with_window(fs)); @@ -254,7 +254,7 @@ cmd_find_current_session_with_client(struct cmd_find_state *fs) * sessions to those containing that pane (we still use the current * window in the best session). */ - if (fs->cmdq->client->tty.path != NULL) { + if (fs->cmdq != NULL && fs->cmdq->client->tty.path != NULL) { RB_FOREACH(wp, window_pane_tree, &all_window_panes) { if (strcmp(wp->tty, fs->cmdq->client->tty.path) == 0) break; @@ -289,7 +289,9 @@ cmd_find_current_session_with_client(struct cmd_find_state *fs) return (0); unknown_pane: - fs->s = cmd_find_try_TMUX(fs->cmdq->client, NULL); + fs->s = NULL; + if (fs->cmdq != NULL) + fs->s = cmd_find_try_TMUX(fs->cmdq->client, NULL); if (fs->s == NULL) fs->s = cmd_find_best_session(NULL, 0, fs->flags); if (fs->s == NULL) @@ -310,7 +312,7 @@ int cmd_find_current_session(struct cmd_find_state *fs) { /* If we know the current client, use it. */ - if (fs->cmdq->client != NULL) { + if (fs->cmdq != NULL && fs->cmdq->client != NULL) { log_debug("%s: have client %p%s", __func__, fs->cmdq->client, fs->cmdq->client->session == NULL ? "" : " (with session)"); if (fs->cmdq->client->session == NULL) @@ -862,6 +864,49 @@ cmd_find_log_state(const char *prefix, struct cmd_find_state *fs) log_debug("%s: idx=none", prefix); } +/* Find state from a session. */ +int +cmd_find_from_session(struct cmd_find_state *fs, struct session *s) +{ + cmd_find_clear_state(fs, NULL, 0); + + fs->s = s; + fs->wl = fs->s->curw; + fs->w = fs->wl->window; + fs->wp = fs->w->active; + + cmd_find_log_state(__func__, fs); + return (0); +} + +/* Find state from a window. */ +int +cmd_find_from_window(struct cmd_find_state *fs, struct window *w) +{ + cmd_find_clear_state(fs, NULL, 0); + + fs->w = w; + if (cmd_find_best_session_with_window(fs) != 0) + return (-1); + if (cmd_find_best_winlink_with_window(fs) != 0) + return (-1); + + cmd_find_log_state(__func__, fs); + return (0); +} + +/* Find state from a pane. */ +int +cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp) +{ + if (cmd_find_from_window(fs, wp->window) != 0) + return (-1); + fs->wp = wp; + + cmd_find_log_state(__func__, fs); + return (0); +} + /* * Split target into pieces and resolve for the given type. Fills in the given * state. Returns 0 on success or -1 on error. diff --git a/cmd-queue.c b/cmd-queue.c index c0fc26c6..5bc3226a 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -44,6 +44,9 @@ cmdq_new(struct client *c) cmdq->item = NULL; cmdq->cmd = NULL; + cmd_find_clear_state(&cmdq->current, NULL, 0); + cmdq->parent = NULL; + return (cmdq); } @@ -286,3 +289,4 @@ cmdq_flush(struct cmd_q *cmdq) } cmdq->item = NULL; } + diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index aa4e169b..da9a365a 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -90,7 +90,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); environ_free(env); - server_destroy_pane(wp); + server_destroy_pane(wp, 0); return (CMD_RETURN_ERROR); } layout_init(w, wp); diff --git a/hooks.c b/hooks.c index 424faf0c..c1a016ae 100644 --- a/hooks.c +++ b/hooks.c @@ -42,6 +42,14 @@ hooks_cmp(struct hook *hook1, struct hook *hook2) return (strcmp(hook1->name, hook2->name)); } +struct hooks * +hooks_get(struct session *s) +{ + if (s != NULL) + return (s->hooks); + return (global_hooks); +} + struct hooks * hooks_create(struct hooks *parent) { @@ -148,7 +156,8 @@ hooks_emptyfn(struct cmd_q *hooks_cmdq) } int -hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...) +hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs, + const char *fmt, ...) { struct hook *hook; struct cmd_q *hooks_cmdq; @@ -169,6 +178,9 @@ hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...) hooks_cmdq = cmdq_new(c); hooks_cmdq->flags |= CMD_Q_NOHOOKS; + + if (fs != NULL) + cmd_find_copy_state(&hooks_cmdq->current, fs); hooks_cmdq->parent = NULL; cmdq_run(hooks_cmdq, hook->cmdlist, NULL); @@ -177,7 +189,8 @@ hooks_run(struct hooks *hooks, struct client *c, const char *fmt, ...) } int -hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, const char *fmt, ...) +hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs, + const char *fmt, ...) { struct hook *hook; struct cmd_q *hooks_cmdq; @@ -198,6 +211,9 @@ hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, const char *fmt, ...) hooks_cmdq = cmdq_new(cmdq->client); hooks_cmdq->flags |= CMD_Q_NOHOOKS; + + if (fs != NULL) + cmd_find_copy_state(&hooks_cmdq->current, fs); hooks_cmdq->parent = cmdq; hooks_cmdq->emptyfn = hooks_emptyfn; diff --git a/server-client.c b/server-client.c index ec16340b..9b88a165 100644 --- a/server-client.c +++ b/server-client.c @@ -283,7 +283,7 @@ server_client_detach(struct client *c, enum msgtype msgtype) if (s == NULL) return; - hooks_run(c->session->hooks, c, "client-detached"); + hooks_run(c->session->hooks, c, NULL, "client-detached"); proc_send_s(c->peer, msgtype, s->name); } @@ -1027,7 +1027,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) server_redraw_client(c); } if (c->session != NULL) - hooks_run(c->session->hooks, c, "client-resized"); + hooks_run(c->session->hooks, c, NULL, "client-resized"); break; case MSG_EXITING: if (datalen != 0) diff --git a/server-fn.c b/server-fn.c index a4c2dfea..0f35aaaf 100644 --- a/server-fn.c +++ b/server-fn.c @@ -293,12 +293,13 @@ server_unlink_window(struct session *s, struct winlink *wl) } void -server_destroy_pane(struct window_pane *wp) +server_destroy_pane(struct window_pane *wp, int hooks) { struct window *w = wp->window; int old_fd; struct screen_write_ctx ctx; struct grid_cell gc; + struct cmd_find_state fs; old_fd = wp->fd; if (wp->fd != -1) { @@ -319,6 +320,9 @@ server_destroy_pane(struct window_pane *wp) screen_write_puts(&ctx, &gc, "Pane is dead"); screen_write_stop(&ctx); wp->flags |= PANE_REDRAW; + + if (hooks && cmd_find_from_pane(&fs, wp) == 0) + hooks_run(hooks_get(fs.s), NULL, &fs, "pane-died"); return; } @@ -326,6 +330,9 @@ server_destroy_pane(struct window_pane *wp) layout_close_pane(wp); window_remove_pane(w, wp); + if (hooks && cmd_find_from_window(&fs, w) == 0) + hooks_run(hooks_get(fs.s), NULL, &fs, "pane-exited"); + if (TAILQ_EMPTY(&w->panes)) server_kill_window(w); else diff --git a/server.c b/server.c index 0a1146f3..170244c7 100644 --- a/server.c +++ b/server.c @@ -387,7 +387,7 @@ server_child_exited(pid_t pid, int status) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->pid == pid) { wp->status = status; - server_destroy_pane(wp); + server_destroy_pane(wp, 1); break; } } diff --git a/tmux.1 b/tmux.1 index 39e9bd4b..9017b4e7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3230,6 +3230,12 @@ Run when a client is attached. Run when a client is detached .It client-resized Run when a client is resized. +.It pane-died +Run when the program running in a pane exits, but +.Ic remain-on-exit +is on so the pane has not closed. +.It pane-exited +Run when the program running in a pane exits. .El .Pp Hooks are managed with these commands: diff --git a/window.c b/window.c index f0e57190..01d5f973 100644 --- a/window.c +++ b/window.c @@ -974,7 +974,7 @@ window_pane_error_callback(__unused struct bufferevent *bufev, { struct window_pane *wp = data; - server_destroy_pane(wp); + server_destroy_pane(wp, 1); } void From 99e9a4c7864c188857fe57b411312ee669f16b54 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 16 Dec 2015 22:05:35 +0000 Subject: [PATCH 2/2] send-keys -R should reset the input parser to ground state (so it can be used to escape from, for example, printf '\033]2;'). --- cmd-send-keys.c | 2 +- input.c | 44 +++++++++++++++++++++++--------------------- tmux.h | 19 +++++++++++++------ 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 377453b0..7b0b952c 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -86,7 +86,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) } if (args_has(args, 'R')) - input_reset(wp); + input_reset(wp, 1); for (i = 0; i < args->argc; i++) { literal = args_has(args, 'l'); diff --git a/input.c b/input.c index d8e80afb..ed1ebffc 100644 --- a/input.c +++ b/input.c @@ -762,24 +762,12 @@ input_init(struct window_pane *wp) ictx = wp->ictx = xcalloc(1, sizeof *ictx); - input_reset_cell(ictx); - - *ictx->interm_buf = '\0'; - ictx->interm_len = 0; - - *ictx->param_buf = '\0'; - ictx->param_len = 0; - ictx->input_space = INPUT_BUF_START; ictx->input_buf = xmalloc(INPUT_BUF_START); - *ictx->input_buf = '\0'; - ictx->input_len = 0; - - ictx->state = &input_state_ground; - ictx->flags = 0; - ictx->since_ground = evbuffer_new(); + + input_reset(wp, 0); } /* Destroy input parser. */ @@ -797,18 +785,32 @@ input_free(struct window_pane *wp) /* Reset input state and clear screen. */ void -input_reset(struct window_pane *wp) +input_reset(struct window_pane *wp, int clear) { struct input_ctx *ictx = wp->ictx; input_reset_cell(ictx); - if (wp->mode == NULL) - screen_write_start(&ictx->ctx, wp, &wp->base); - else - screen_write_start(&ictx->ctx, NULL, &wp->base); - screen_write_reset(&ictx->ctx); - screen_write_stop(&ictx->ctx); + if (clear) { + if (wp->mode == NULL) + screen_write_start(&ictx->ctx, wp, &wp->base); + else + screen_write_start(&ictx->ctx, NULL, &wp->base); + screen_write_reset(&ictx->ctx); + screen_write_stop(&ictx->ctx); + } + + *ictx->interm_buf = '\0'; + ictx->interm_len = 0; + + *ictx->param_buf = '\0'; + ictx->param_len = 0; + + *ictx->input_buf = '\0'; + ictx->input_len = 0; + + ictx->state = &input_state_ground; + ictx->flags = 0; } /* Return pending data. */ diff --git a/tmux.h b/tmux.h index 2b1b29b0..194d01d8 100644 --- a/tmux.h +++ b/tmux.h @@ -1379,6 +1379,7 @@ struct cmd_q { struct cmd *cmd; struct cmd_q *parent; + struct cmd_find_state current; struct cmd_state state; time_t time; @@ -1576,6 +1577,7 @@ void format_defaults_paste_buffer(struct format_tree *, /* hooks.c */ struct hook; +struct hooks *hooks_get(struct session *); struct hooks *hooks_create(struct hooks *); void hooks_free(struct hooks *); struct hook *hooks_first(struct hooks *); @@ -1584,10 +1586,10 @@ void hooks_add(struct hooks *, const char *, struct cmd_list *); void hooks_copy(struct hooks *, struct hooks *); void hooks_remove(struct hooks *, const char *); struct hook *hooks_find(struct hooks *, const char *); -int printflike(3, 4) hooks_run(struct hooks *, struct client *, const char *, - ...); -int printflike(3, 4) hooks_wait(struct hooks *, struct cmd_q *, const char *, - ...); +int printflike(4, 5) hooks_run(struct hooks *, struct client *, + struct cmd_find_state *, const char *, ...); +int printflike(4, 5) hooks_wait(struct hooks *, struct cmd_q *, + struct cmd_find_state *, const char *, ...); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; @@ -1776,6 +1778,11 @@ int cmd_find_valid_state(struct cmd_find_state *); void cmd_find_copy_state(struct cmd_find_state *, struct cmd_find_state *); void cmd_find_log_state(const char *, struct cmd_find_state *); +int cmd_find_from_session(struct cmd_find_state *, + struct session *); +int cmd_find_from_window(struct cmd_find_state *, struct window *); +int cmd_find_from_pane(struct cmd_find_state *, + struct window_pane *); /* cmd.c */ int cmd_pack_argv(int, char **, char *, size_t); @@ -1896,7 +1903,7 @@ void server_kill_window(struct window *); int server_link_window(struct session *, struct winlink *, struct session *, int, int, int, char **); void server_unlink_window(struct session *, struct winlink *); -void server_destroy_pane(struct window_pane *); +void server_destroy_pane(struct window_pane *, int); void server_destroy_session_group(struct session *); void server_destroy_session(struct session *); void server_check_unattached(void); @@ -1930,7 +1937,7 @@ void recalculate_sizes(void); /* input.c */ void input_init(struct window_pane *); void input_free(struct window_pane *); -void input_reset(struct window_pane *); +void input_reset(struct window_pane *, int); struct evbuffer *input_pending(struct window_pane *); void input_parse(struct window_pane *);