diff --git a/cmd-split-window.c b/cmd-split-window.c index cc6427b5..98a4072d 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -39,7 +39,7 @@ const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vx:X:y:Y:Z", 0, -1, NULL }, + .args = { "bBc:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vx:X:y:Y:Z", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-l size] [-m message] [-p percentage] " "[-s style] [-S active-border-style] " @@ -57,7 +57,7 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:T:vZ", 0, -1, NULL }, + .args = { "bBc:de:EfF:hIkl:m:p:PR:s:S:t:T:vZ", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-l size] [-m message] [-p percentage] " "[-s style] [-S active-border-style] " @@ -245,5 +245,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) environ_free(sc.environ); if (input) return (CMD_RETURN_WAIT); + + if (args_has(args, 'B')) { + /* + * With -B, block this command queue item until the pane's + * command exits; window_pane_block_finish will be called to + * continue it. + */ + new_wp->block_item = item; + return (CMD_RETURN_WAIT); + } return (CMD_RETURN_NORMAL); } diff --git a/server.c b/server.c index b50bb0b6..ff4d165a 100644 --- a/server.c +++ b/server.c @@ -491,6 +491,8 @@ server_child_exited(pid_t pid, int status) log_debug("%%%u exited", wp->id); wp->flags |= PANE_EXITED; + window_pane_block_finish(wp); + if (window_pane_destroy_ready(wp)) server_destroy_pane(wp, 1); break; diff --git a/tmux.1 b/tmux.1 index fa308e7e..d2163335 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3380,7 +3380,7 @@ but a different format may be specified with .Fl F . .Tg newp .It Xo Ic new\-pane -.Op Fl bdefhIkPvZ +.Op Fl bBdefhIkPvZ .Op Fl c Ar start\-directory .Op Fl e Ar environment .Op Fl F Ar format @@ -3456,6 +3456,17 @@ but also sets the option for this pane to .Ar message . .Pp +.Fl B +blocks until +.Ar shell\-command +exits, then returns its exit status. +For example: +.Bd -literal -offset indent +$ tmux new-pane -B 'vi afile' +$ echo $? +0 +.Ed +.Pp .Fl E , or an empty .Ar shell\-command , diff --git a/tmux.h b/tmux.h index 7cd6262e..e80047dc 100644 --- a/tmux.h +++ b/tmux.h @@ -1262,6 +1262,7 @@ struct window_pane { char tty[TTY_NAME_MAX]; int status; struct timeval dead_time; + struct cmdq_item *block_item; /* new-pane -B: waiting for pane exit */ int fd; struct bufferevent *event; @@ -3372,6 +3373,7 @@ struct window *window_find_by_id(u_int); void window_update_activity(struct window *); struct window *window_create(u_int, u_int, u_int, u_int); void window_pane_set_event(struct window_pane *); +void window_pane_block_finish(struct window_pane *); struct window_pane *window_get_active_at(struct window *, u_int, u_int); struct window_pane *window_find_string(struct window *, const char *); int window_has_floating_panes(struct window *); diff --git a/window.c b/window.c index eb895b9f..914c34d7 100644 --- a/window.c +++ b/window.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -382,6 +383,13 @@ window_pane_destroy_ready(struct window_pane *wp) if (~wp->flags & PANE_EXITED) return (0); + + /* + * If a command queue item is blocked on this pane, wait for the + * child's exit status before destroying it. + */ + if (wp->block_item != NULL && (~wp->flags & PANE_STATUSREADY)) + return (0); return (1); } @@ -1077,12 +1085,38 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) return (wp); } +void +window_pane_block_finish(struct window_pane *wp) +{ + struct cmdq_item *item = wp->block_item; + struct client *c; + int retval = 0; + + if (item == NULL) + return; + wp->block_item = NULL; + + if (wp->flags & PANE_STATUSREADY) { + if (WIFEXITED(wp->status)) + retval = WEXITSTATUS(wp->status); + else if (WIFSIGNALED(wp->status)) + retval = WTERMSIG(wp->status) + 128; + } + + c = cmdq_get_client(item); + if (c != NULL && c->session == NULL) + c->retval = retval; + cmdq_continue(item); +} + static void window_pane_destroy(struct window_pane *wp) { struct window_pane_resize *r; struct window_pane_resize *r1; + window_pane_block_finish(wp); + window_pane_reset_mode_all(wp); free(wp->searchstr);