diff options
author | nicm <nicm> | 2019-05-03 20:44:24 +0000 |
---|---|---|
committer | nicm <nicm> | 2019-05-03 20:44:24 +0000 |
commit | 9f75635596d0a01282156eb9e17fde6f4205c05c (patch) | |
tree | c2992361a46c5ed7a17c2f273d3e8aba5bc16480 | |
parent | e8e4f4ec3e4de0bd0e4eb2a7ee995fb6f5f7f937 (diff) | |
download | rtmux-9f75635596d0a01282156eb9e17fde6f4205c05c.tar.gz rtmux-9f75635596d0a01282156eb9e17fde6f4205c05c.tar.bz2 rtmux-9f75635596d0a01282156eb9e17fde6f4205c05c.zip |
Allow panes to be empty (no command), output can be piped to them with
split-window or display-message -I.
-rw-r--r-- | cmd-display-message.c | 15 | ||||
-rw-r--r-- | cmd-split-window.c | 22 | ||||
-rw-r--r-- | format.c | 5 | ||||
-rw-r--r-- | input.c | 2 | ||||
-rw-r--r-- | server-client.c | 3 | ||||
-rw-r--r-- | server-fn.c | 3 | ||||
-rw-r--r-- | spawn.c | 48 | ||||
-rw-r--r-- | tmux.1 | 28 | ||||
-rw-r--r-- | tmux.h | 5 | ||||
-rw-r--r-- | window.c | 47 |
10 files changed, 144 insertions, 34 deletions
diff --git a/cmd-display-message.c b/cmd-display-message.c index 2e935908..8c1ad5f6 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -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/cmd-split-window.c b/cmd-split-window.c index 3b9040dc..d004aa95 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -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); } @@ -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); @@ -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/server-client.c b/server-client.c index 78e12b19..13a589ef 100644 --- a/server-client.c +++ b/server-client.c @@ -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/server-fn.c b/server-fn.c index c4ff4aa9..372bf21d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -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); } @@ -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); } @@ -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 @@ -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 *); @@ -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)); +} |