diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-05-03 20:44:25 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-05-03 20:44:25 +0000 |
commit | 56ea0a7498e53a198c5dd1916a62bafc3df0e2a8 (patch) | |
tree | f95540670b620bfd8c4399d7229de83ce40c8185 /usr.bin/tmux | |
parent | 25c1b5674b97d6ab3908886553e803d83bf9f948 (diff) |
Allow panes to be empty (no command), output can be piped to them with
split-window or display-message -I.
Diffstat (limited to 'usr.bin/tmux')
-rw-r--r-- | usr.bin/tmux/cmd-display-message.c | 17 | ||||
-rw-r--r-- | usr.bin/tmux/cmd-split-window.c | 24 | ||||
-rw-r--r-- | usr.bin/tmux/format.c | 7 | ||||
-rw-r--r-- | usr.bin/tmux/input.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/server-client.c | 5 | ||||
-rw-r--r-- | usr.bin/tmux/server-fn.c | 5 | ||||
-rw-r--r-- | usr.bin/tmux/spawn.c | 50 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 32 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 7 | ||||
-rw-r--r-- | usr.bin/tmux/window.c | 49 |
10 files changed, 155 insertions, 45 deletions
diff --git a/usr.bin/tmux/cmd-display-message.c b/usr.bin/tmux/cmd-display-message.c index b5a741143b0..eb910c48a0a 100644 --- a/usr.bin/tmux/cmd-display-message.c +++ b/usr.bin/tmux/cmd-display-message.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-display-message.c,v 1.48 2019/03/18 14:10:25 nicm Exp $ */ +/* $OpenBSD: cmd-display-message.c,v 1.49 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> @@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = { .name = "display-message", .alias = "display", - .args = { "ac:pt:F:v", 0, 1 }, - .usage = "[-apv] [-c target-client] [-F format] " + .args = { "ac:Ipt:F:v", 0, 1 }, + .usage = "[-aIpv] [-c target-client] [-F format] " CMD_TARGET_PANE_USAGE " [message]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -66,10 +66,19 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) struct winlink *wl = item->target.wl; struct window_pane *wp = item->target.wp; const char *template; - char *msg; + char *msg, *cause; struct format_tree *ft; int flags; + if (args_has(args, 'I')) { + if (window_pane_start_input(wp, item, &cause) != 0) { + cmdq_error(item, "%s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + return (CMD_RETURN_WAIT); + } + if (args_has(args, 'F') && args->argc != 0) { cmdq_error(item, "only one of -F or argument must be given"); return (CMD_RETURN_ERROR); diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c index 25ee7bd1a69..ca590d10869 100644 --- a/usr.bin/tmux/cmd-split-window.c +++ b/usr.bin/tmux/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-split-window.c,v 1.94 2019/04/28 20:05:50 nicm Exp $ */ +/* $OpenBSD: cmd-split-window.c,v 1.95 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -40,9 +40,10 @@ const struct cmd_entry cmd_split_window_entry = { .name = "split-window", .alias = "splitw", - .args = { "bc:de:fF:l:hp:Pt:v", 0, -1 }, - .usage = "[-bdefhvP] [-c start-directory] [-e environment] [-F format] " - "[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", + .args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 }, + .usage = "[-bdefhIPv] [-c start-directory] [-e environment] " + "[-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE + " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -63,7 +64,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) enum layout_type type; struct layout_cell *lc; struct cmd_find_state fs; - int size, percentage, flags; + int size, percentage, flags, input; const char *template, *add; char *cause, *cp; struct args_value *value; @@ -94,12 +95,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) size = -1; server_unzoom_window(wp->window); + input = (args_has(args, 'I') && args->argc == 0); flags = 0; if (args_has(args, 'b')) flags |= SPAWN_BEFORE; if (args_has(args, 'f')) flags |= SPAWN_FULLSIZE; + if (input || (args->argc == 1 && *args->argv[0] == '\0')) + flags |= SPAWN_EMPTY; lc = layout_split_pane(wp, type, size, flags); if (lc == NULL) { @@ -134,10 +138,18 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) sc.flags |= SPAWN_DETACHED; if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { + layout_close_pane(new_wp); cmdq_error(item, "create pane failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } + if (input && window_pane_start_input(new_wp, item, &cause) != 0) { + layout_close_pane(new_wp); + window_remove_pane(wp->window, new_wp); + cmdq_error(item, "%s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } if (!args_has(args, 'd')) cmd_find_from_winlink_pane(current, wl, new_wp, 0); server_redraw_window(wp->window); @@ -155,5 +167,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmdq_insert_hook(s, item, &fs, "after-split-window"); environ_free(sc.environ); + if (input) + return (CMD_RETURN_WAIT); return (CMD_RETURN_NORMAL); } diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c index b5e9829b9bd..d5f8257773a 100644 --- a/usr.bin/tmux/format.c +++ b/usr.bin/tmux/format.c @@ -1,4 +1,4 @@ -/* $OpenBSD: format.c,v 1.189 2019/04/25 18:18:55 nicm Exp $ */ +/* $OpenBSD: format.c,v 1.190 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -2031,7 +2031,10 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status)) format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); - format_add(ft, "pane_dead", "%d", wp->fd == -1); + if (~wp->flags & PANE_EMPTY) + format_add(ft, "pane_dead", "%d", wp->fd == -1); + else + format_add(ft, "pane_dead", "0"); format_add(ft, "pane_left", "%u", wp->xoff); format_add(ft, "pane_top", "%u", wp->yoff); diff --git a/usr.bin/tmux/input.c b/usr.bin/tmux/input.c index 272729c9c6f..27123b74a49 100644 --- a/usr.bin/tmux/input.c +++ b/usr.bin/tmux/input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: input.c,v 1.150 2019/04/02 09:03:39 nicm Exp $ */ +/* $OpenBSD: input.c,v 1.151 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1185,6 +1185,8 @@ input_c0_dispatch(struct input_ctx *ictx) case '\013': /* VT */ case '\014': /* FF */ screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); + if (s->mode & MODE_CRLF) + screen_write_carriagereturn(sctx); break; case '\015': /* CR */ screen_write_carriagereturn(sctx); diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c index 87ae28da0dc..23231eb6e69 100644 --- a/usr.bin/tmux/server-client.c +++ b/usr.bin/tmux/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.278 2019/05/03 18:42:40 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.279 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1671,8 +1671,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) evbuffer_add(c->stdin_data, stdindata.data, stdindata.size); } - c->stdin_callback(c, c->stdin_closed, - c->stdin_callback_data); + c->stdin_callback(c, c->stdin_closed, c->stdin_callback_data); break; case MSG_RESIZE: if (datalen != 0) diff --git a/usr.bin/tmux/server-fn.c b/usr.bin/tmux/server-fn.c index f22e0419ed4..1795c5c03ef 100644 --- a/usr.bin/tmux/server-fn.c +++ b/usr.bin/tmux/server-fn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-fn.c,v 1.120 2019/04/17 14:37:48 nicm Exp $ */ +/* $OpenBSD: server-fn.c,v 1.121 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -439,7 +439,6 @@ server_check_unattached(void) } } -/* Set stdin callback. */ int server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, void *), void *cb_data, char **cause) @@ -453,7 +452,7 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int, return (-1); } if (c->stdin_callback != NULL) { - *cause = xstrdup("stdin in use"); + *cause = xstrdup("stdin is in use"); return (-1); } diff --git a/usr.bin/tmux/spawn.c b/usr.bin/tmux/spawn.c index 0bdf061f976..f74625cb66c 100644 --- a/usr.bin/tmux/spawn.c +++ b/usr.bin/tmux/spawn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: spawn.c,v 1.2 2019/04/28 20:05:50 nicm Exp $ */ +/* $OpenBSD: spawn.c,v 1.3 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -332,6 +332,14 @@ spawn_pane(struct spawn_context *sc, char **cause) cmd_log_argv(new_wp->argc, new_wp->argv, __func__); environ_log(child, "%s: environment ", __func__); + /* If the command is empty, don't fork a child process. */ + if (sc->flags & SPAWN_EMPTY) { + new_wp->flags |= PANE_EMPTY; + new_wp->base.mode &= ~MODE_CURSOR; + new_wp->base.mode |= MODE_CRLF; + goto complete; + } + /* Initialize the window size. */ memset(&ws, 0, sizeof ws); ws.ws_col = screen_size_x(&new_wp->base); @@ -355,25 +363,8 @@ spawn_pane(struct spawn_context *sc, char **cause) } /* In the parent process, everything is done now. */ - if (new_wp->pid != 0) { - new_wp->pipe_off = 0; - new_wp->flags &= ~PANE_EXITED; - - sigprocmask(SIG_SETMASK, &oldset, NULL); - window_pane_set_event(new_wp); - - if (sc->flags & SPAWN_RESPAWN) - return (new_wp); - if ((~sc->flags & SPAWN_DETACHED) || w->active == NULL) { - if (sc->flags & SPAWN_NONOTIFY) - window_set_active_pane(w, new_wp, 0); - else - window_set_active_pane(w, new_wp, 1); - } - if (~sc->flags & SPAWN_NONOTIFY) - notify_window("window-layout-changed", w); - return (new_wp); - } + if (new_wp->pid != 0) + goto complete; /* * Child process. Change to the working directory or home if that @@ -433,4 +424,23 @@ spawn_pane(struct spawn_context *sc, char **cause) xasprintf(&argv0, "-%s", new_wp->shell); execl(new_wp->shell, argv0, (char *)NULL); _exit(1); + +complete: + new_wp->pipe_off = 0; + new_wp->flags &= ~PANE_EXITED; + + sigprocmask(SIG_SETMASK, &oldset, NULL); + window_pane_set_event(new_wp); + + if (sc->flags & SPAWN_RESPAWN) + return (new_wp); + if ((~sc->flags & SPAWN_DETACHED) || w->active == NULL) { + if (sc->flags & SPAWN_NONOTIFY) + window_set_active_pane(w, new_wp, 0); + else + window_set_active_pane(w, new_wp, 1); + } + if (~sc->flags & SPAWN_NONOTIFY) + notify_window("window-layout-changed", w); + return (new_wp); } diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index aebbad832e8..7fc5c73d58b 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.642 2019/05/02 20:12:40 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.643 2019/05/03 20:44:24 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 2 2019 $ +.Dd $Mdocdate: May 3 2019 $ .Dt TMUX 1 .Os .Sh NAME @@ -2204,7 +2204,7 @@ is given and the selected window is already the current window, the command behaves like .Ic last-window . .It Xo Ic split-window -.Op Fl bdfhvP +.Op Fl bdfhIvP .Op Fl c Ar start-directory .Op Fl e Ar environment .Oo Fl l @@ -2240,6 +2240,24 @@ option creates a new pane spanning the full window height (with or full window width (with .Fl v ) , instead of splitting the active pane. +.Pp +An empty +.Ar shell-command +('') will create a pane with no command running in it. +Output can be sent to such a pane with the +.Ic display-message +command. +The +.Fl I +flag (if +.Ar shell-command +is not specified or empty) +will create an empty pane and forward any output from stdin to it. +For example: +.Bd -literal -offset indent +$ make 2>&1|tmux splitw -dI & +.Ed +.Pp All other options have the same meaning as for the .Ic new-window command. @@ -2822,7 +2840,7 @@ This option should be configured when is used as a login shell. .It Ic default-size Ar XxY Set the default size of new windows when the -.Ar window-size +.Ic window-size option is set to manual or when a session is created with .Ic new-session .Fl d . @@ -4428,7 +4446,7 @@ option. This command works only from inside .Nm . .It Xo Ic display-message -.Op Fl apv +.Op Fl aIpv .Op Fl c Ar target-client .Op Fl t Ar target-pane .Op Ar message @@ -4455,6 +4473,10 @@ is given, otherwise the active pane for the session attached to prints verbose logging as the format is parsed and .Fl a lists the format variables and their values. +.Pp +.Fl I +forwards any input read from stdin to the empty pane given by +.Ar target-pane . .El .Sh BUFFERS .Nm diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index f02d444b9a9..69815d6673a 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.886 2019/05/03 15:43:01 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.887 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -522,6 +522,7 @@ struct msg_stderr_data { #define MODE_FOCUSON 0x800 #define MODE_MOUSE_ALL 0x1000 #define MODE_ORIGIN 0x2000 +#define MODE_CRLF 0x4000 #define ALL_MODES 0xffffff #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) @@ -802,6 +803,7 @@ struct window_pane { #define PANE_EXITED 0x100 #define PANE_STATUSREADY 0x200 #define PANE_STATUSDRAWN 0x400 +#define PANE_EMPTY 0x800 int argc; char **argv; @@ -1598,6 +1600,7 @@ struct spawn_context { #define SPAWN_BEFORE 0x8 #define SPAWN_NONOTIFY 0x10 #define SPAWN_FULLSIZE 0x20 +#define SPAWN_EMPTY 0x40 }; /* tmux.c */ @@ -2317,6 +2320,8 @@ void window_add_ref(struct window *, const char *); void window_remove_ref(struct window *, const char *); void winlink_clear_flags(struct winlink *); int winlink_shuffle_up(struct session *, struct winlink *); +int window_pane_start_input(struct window_pane *, + struct cmdq_item *, char **); /* layout.c */ u_int layout_count_cells(struct layout_cell *); diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c index 1a05fe6ba72..00559a93039 100644 --- a/usr.bin/tmux/window.c +++ b/usr.bin/tmux/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.227 2019/04/26 10:24:26 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.228 2019/05/03 20:44:24 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -72,6 +72,11 @@ const struct window_mode *all_window_modes[] = { NULL }; +struct window_pane_input_data { + struct cmdq_item *item; + u_int wp; +}; + static struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); static void window_pane_destroy(struct window_pane *); @@ -1466,3 +1471,45 @@ winlink_shuffle_up(struct session *s, struct winlink *wl) return (idx); } + +static void +window_pane_input_callback(struct client *c, int closed, void *data) +{ + struct window_pane_input_data *cdata = data; + struct window_pane *wp; + + wp = window_pane_find_by_id(cdata->wp); + if (wp == NULL || closed || c->flags & CLIENT_DEAD) { + c->stdin_callback = NULL; + server_client_unref(c); + + cdata->item->flags &= ~CMDQ_WAITING; + free(cdata); + + return; + } + + if (evbuffer_add_buffer(wp->event->input, c->stdin_data) != 0) + evbuffer_drain(c->stdin_data, EVBUFFER_LENGTH(c->stdin_data)); + input_parse(wp); +} + +int +window_pane_start_input(struct window_pane *wp, struct cmdq_item *item, + char **cause) +{ + struct client *c = item->client; + struct window_pane_input_data *cdata; + + if (~wp->flags & PANE_EMPTY) { + *cause = xstrdup("pane is not empty"); + return (-1); + } + + cdata = xmalloc(sizeof *cdata); + cdata->item = item; + cdata->wp = wp->id; + + return (server_set_stdin_callback(c, window_pane_input_callback, cdata, + cause)); +} |