summaryrefslogtreecommitdiff
path: root/usr.bin/tmux
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2019-05-03 20:44:25 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2019-05-03 20:44:25 +0000
commit56ea0a7498e53a198c5dd1916a62bafc3df0e2a8 (patch)
treef95540670b620bfd8c4399d7229de83ce40c8185 /usr.bin/tmux
parent25c1b5674b97d6ab3908886553e803d83bf9f948 (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.c17
-rw-r--r--usr.bin/tmux/cmd-split-window.c24
-rw-r--r--usr.bin/tmux/format.c7
-rw-r--r--usr.bin/tmux/input.c4
-rw-r--r--usr.bin/tmux/server-client.c5
-rw-r--r--usr.bin/tmux/server-fn.c5
-rw-r--r--usr.bin/tmux/spawn.c50
-rw-r--r--usr.bin/tmux/tmux.132
-rw-r--r--usr.bin/tmux/tmux.h7
-rw-r--r--usr.bin/tmux/window.c49
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));
+}