aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES16
-rw-r--r--COPYING7
-rw-r--r--Makefile.am1
-rw-r--r--TODO4
-rw-r--r--cfg.c33
-rw-r--r--cmd-attach-session.c2
-rw-r--r--cmd-join-pane.c10
-rw-r--r--cmd-kill-session.c4
-rw-r--r--cmd-new-session.c105
-rw-r--r--cmd-new-window.c109
-rw-r--r--cmd-queue.c2
-rw-r--r--cmd-respawn-pane.c60
-rw-r--r--cmd-respawn-window.c72
-rw-r--r--cmd-rotate-window.c4
-rw-r--r--cmd-select-pane.c4
-rw-r--r--cmd-show-options.c132
-rw-r--r--cmd-split-window.c139
-rw-r--r--cmd-swap-pane.c10
-rw-r--r--cmd-switch-client.c4
-rw-r--r--compat.h1
-rw-r--r--configure.ac2
-rw-r--r--format.c17
-rw-r--r--input.c2
-rw-r--r--layout.c16
-rw-r--r--osdep-darwin.c3
-rw-r--r--paste.c9
-rw-r--r--screen-write.c2
-rw-r--r--server-client.c1
-rw-r--r--server-fn.c4
-rw-r--r--server.c2
-rw-r--r--session.c68
-rw-r--r--spawn.c432
-rw-r--r--style.c2
-rw-r--r--tmux.147
-rw-r--r--tmux.h60
-rw-r--r--tty-keys.c2
-rw-r--r--window-buffer.c16
-rw-r--r--window-copy.c1555
-rw-r--r--window-tree.c2
-rw-r--r--window.c227
40 files changed, 2036 insertions, 1152 deletions
diff --git a/CHANGES b/CHANGES
index e78921fe..87097f9e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,19 @@
+CHANGES FROM 2.9 to X.X
+
+* Add an argument to copy commands to set the prefix for the buffer name, this
+ (for example) allows buffers for different sessions to be named separately.
+
+* Update session activity on focus event.
+
+* Pass target from source-file into the config file parser so formats in %if
+ and %endif have access to more useful variables.
+
+* Add the ability to infer an option type (server, session, window) from its
+ name to show-options (it was already present in set-option).
+
+* Allow the prefix used for new buffer names to be given as an argument to the
+ copy commands in copy mode.
+
CHANGES FROM 2.8 to 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
diff --git a/COPYING b/COPYING
index 9d96b3e6..fd02a999 100644
--- a/COPYING
+++ b/COPYING
@@ -1,10 +1,7 @@
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
-The README, CHANGES, FAQ and TODO files are licensed under the ISC
-license. Files under examples/ remain copyright their authors unless otherwise
-stated in the file but permission has been received to distribute them with
-tmux. All other files have a license and copyright notice at their start,
-typically:
+The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
+other files have a license and copyright notice at their start, typically:
Copyright (c) <author>
diff --git a/Makefile.am b/Makefile.am
index 16c842c8..942a9e28 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -160,6 +160,7 @@ dist_tmux_SOURCES = \
server-fn.c \
server.c \
session.c \
+ spawn.c \
status.c \
style.c \
tmux.c \
diff --git a/TODO b/TODO
index 4e252b5f..220e4eb9 100644
--- a/TODO
+++ b/TODO
@@ -52,7 +52,6 @@
need to be suspended
* allow the prefix for automatic buffers to be specified as part of the
key binding to allow session buffers or similar (GitHub issue 1501)
- * copy-pipe should be synchronous (GitHub issue 1517)
- layout stuff
* way to tag a layout as a number/name
@@ -149,8 +148,6 @@
TODO soonish maybe:
- Store hooks as options, issue 1619.
-- Support buffer prefixes, issue 1501.
-- copy-pipe should be synchronous, issue 1517.
- -E flag to pass environment to new-*, issue 1498.
- Copy mode searching is slow when there is a big history, issue 1545.
- Grid "block" stuff, issue 1269. Can be used potentially for compression of
@@ -159,3 +156,4 @@ TODO soonish maybe:
collected LRU.
- Command aliases should be able to override builtin commands in order to add
default flags (some mechanism needed to avoid recursion). GitHub issue 1630.
+- Merge alternate and normal screen modes: https://gitlab.freedesktop.org/terminal-wg/specifications/issues/5#note_112220
diff --git a/cfg.c b/cfg.c
index 84db9fb3..60735046 100644
--- a/cfg.c
+++ b/cfg.c
@@ -101,7 +101,8 @@ start_cfg(void)
cmdq_append(c, cfg_item);
}
- load_cfg(TMUX_CONF, NULL, NULL, 1);
+ if (cfg_file == NULL)
+ load_cfg(TMUX_CONF, NULL, NULL, 1);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
@@ -114,7 +115,8 @@ start_cfg(void)
}
static int
-cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
+cfg_check_cond(const char *path, size_t line, const char *p, int *skip,
+ struct client *c, struct cmd_find_state *fs)
{
struct format_tree *ft;
char *s;
@@ -129,6 +131,10 @@ cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
}
ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS);
+ if (fs != NULL)
+ format_defaults(ft, c, fs->s, fs->wl, fs->wp);
+ else
+ format_defaults(ft, c, NULL, NULL, NULL);
s = format_expand(ft, p);
result = format_true(s);
free(s);
@@ -140,7 +146,7 @@ cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
static void
cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
- const char *p)
+ const char *p, struct client *c, struct cmd_find_state *fs)
{
struct cfg_cond *cond;
struct cfg_cond *parent = TAILQ_FIRST(conds);
@@ -152,7 +158,7 @@ cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
cond = xcalloc(1, sizeof *cond);
cond->line = line;
if (parent == NULL || parent->met)
- cond->met = cfg_check_condition(path, line, p, &cond->skip);
+ cond->met = cfg_check_cond(path, line, p, &cond->skip, c, fs);
else
cond->skip = 1;
cond->saw_else = 0;
@@ -161,7 +167,7 @@ cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
static void
cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
- const char *p)
+ const char *p, struct client *c, struct cmd_find_state *fs)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
@@ -172,7 +178,7 @@ cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
if (cond == NULL || cond->saw_else)
cfg_add_cause("%s:%zu: unexpected %%elif", path, line);
else if (!cond->skip)
- cond->met = cfg_check_condition(path, line, p, &cond->skip);
+ cond->met = cfg_check_cond(path, line, p, &cond->skip, c, fs);
else
cond->met = 0;
}
@@ -213,16 +219,16 @@ cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds)
static void
cfg_handle_directive(const char *p, const char *path, size_t line,
- struct cfg_conds *conds)
+ struct cfg_conds *conds, struct client *c, struct cmd_find_state *fs)
{
int n = 0;
while (p[n] != '\0' && !isspace((u_char)p[n]))
n++;
if (strncmp(p, "%if", n) == 0)
- cfg_handle_if(path, line, conds, p + n);
+ cfg_handle_if(path, line, conds, p + n, c, fs);
else if (strncmp(p, "%elif", n) == 0)
- cfg_handle_elif(path, line, conds, p + n);
+ cfg_handle_elif(path, line, conds, p + n, c, fs);
else if (strcmp(p, "%else") == 0)
cfg_handle_else(path, line, conds);
else if (strcmp(p, "%endif") == 0)
@@ -243,6 +249,13 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
struct cmdq_item *new_item;
struct cfg_cond *cond, *cond1;
struct cfg_conds conds;
+ struct cmd_find_state *fs = NULL;
+ struct client *fc = NULL;
+
+ if (item != NULL) {
+ fs = &item->target;
+ fc = cmd_find_client(item, NULL, 1);
+ }
TAILQ_INIT(&conds);
@@ -269,7 +282,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
*q-- = '\0';
if (*p == '%') {
- cfg_handle_directive(p, path, line, &conds);
+ cfg_handle_directive(p, path, line, &conds, fc, fs);
continue;
}
cond = TAILQ_FIRST(&conds);
diff --git a/cmd-attach-session.c b/cmd-attach-session.c
index 73ff530d..bcd6d895 100644
--- a/cmd-attach-session.c
+++ b/cmd-attach-session.c
@@ -87,7 +87,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (wl != NULL) {
if (wp != NULL)
- window_set_active_pane(wp->window, wp);
+ window_set_active_pane(wp->window, wp, 1);
session_set_current(s, wl);
if (wp != NULL)
cmd_find_from_winlink_pane(current, wl, wp, 0);
diff --git a/cmd-join-pane.c b/cmd-join-pane.c
index 947b2499..3d798e09 100644
--- a/cmd-join-pane.c
+++ b/cmd-join-pane.c
@@ -71,7 +71,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
int size, percentage, dst_idx;
enum layout_type type;
struct layout_cell *lc;
- int not_same_window;
+ int not_same_window, flags;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
@@ -123,7 +123,11 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
size = (dst_wp->sx * percentage) / 100;
}
- lc = layout_split_pane(dst_wp, type, size, args_has(args, 'b'), 0);
+ if (args_has(args, 'b'))
+ flags = SPAWN_BEFORE;
+ else
+ flags = 0;
+ lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");
return (CMD_RETURN_ERROR);
@@ -144,7 +148,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(dst_w);
if (!args_has(args, 'd')) {
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(dst_w, src_wp, 1);
session_select(dst_s, dst_idx);
cmd_find_from_session(current, dst_s, 0);
server_redraw_session(dst_s);
diff --git a/cmd-kill-session.c b/cmd-kill-session.c
index 00ea7789..dcef8097 100644
--- a/cmd-kill-session.c
+++ b/cmd-kill-session.c
@@ -61,12 +61,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
if (sloop != s) {
server_destroy_session(sloop);
- session_destroy(sloop, __func__);
+ session_destroy(sloop, 1, __func__);
}
}
} else {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-new-session.c b/cmd-new-session.c
index e1be350b..f0a353d8 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -69,20 +69,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = self->args;
struct client *c = item->client;
struct session *s, *as, *groupwith;
- struct window *w;
struct environ *env;
struct options *oo;
struct termios tio, *tiop;
struct session_group *sg;
- const char *errstr, *template, *group, *prefix;
- const char *path, *cmd, *tmp, *value;
- char **argv, *cause, *cp, *newname, *cwd = NULL;
- int detached, already_attached, idx, argc;
- int is_control = 0;
- u_int sx, sy, dsx = 80, dsy = 24;
- struct environ_entry *envent;
- struct cmd_find_state fs;
+ const char *errstr, *template, *group, *prefix, *tmp;
+ char *cause, *cwd = NULL, *cp, *newname = NULL;
+ int detached, already_attached, is_control = 0;
+ u_int sx, sy, dsx, dsy;
+ struct spawn_context sc;
enum cmd_retval retval;
+ struct cmd_find_state fs;
if (self->entry == &cmd_has_session_entry) {
/*
@@ -97,13 +94,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
- newname = NULL;
if (args_has(args, 's')) {
newname = format_single(item, args_get(args, 's'), c, NULL,
NULL, NULL);
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
- goto error;
+ goto fail;
}
if ((as = session_find(newname)) != NULL) {
if (args_has(args, 'A')) {
@@ -114,7 +110,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (retval);
}
cmdq_error(item, "duplicate session: %s", newname);
- goto error;
+ goto fail;
}
}
@@ -125,7 +121,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (groupwith == NULL) {
if (!session_check_name(group)) {
cmdq_error(item, "bad group name: %s", group);
- goto error;
+ goto fail;
}
sg = session_group_find(group);
} else
@@ -173,7 +169,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_check_nested(item->client)) {
cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force");
- return (CMD_RETURN_ERROR);
+ goto fail;
}
if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed");
@@ -186,7 +182,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause);
free(cause);
- goto error;
+ goto fail;
}
}
@@ -200,7 +196,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
dsx = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
- goto error;
+ goto fail;
}
}
}
@@ -213,7 +209,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
dsy = strtonum(tmp, 1, USHRT_MAX, &errstr);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
- goto error;
+ goto fail;
}
}
}
@@ -225,8 +221,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (sy > 0 && options_get_number(global_s_options, "status"))
sy--;
} else {
- value = options_get_string(global_s_options, "default-size");
- if (sscanf(value, "%ux%u", &sx, &sy) != 2) {
+ tmp = options_get_string(global_s_options, "default-size");
+ if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = 80;
sy = 24;
}
@@ -240,59 +236,34 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (sy == 0)
sy = 1;
- /* Figure out the command for the new window. */
- argc = -1;
- argv = NULL;
- if (!args_has(args, 't') && args->argc != 0) {
- argc = args->argc;
- argv = args->argv;
- } else if (sg == NULL && groupwith == NULL) {
- cmd = options_get_string(global_s_options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- }
-
- path = NULL;
- if (c != NULL && c->session == NULL)
- envent = environ_find(c->environ, "PATH");
- else
- envent = environ_find(global_environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- /* Construct the environment. */
+ /* Create the new session. */
+ oo = options_create(global_s_options);
+ if (args_has(args, 'x') || args_has(args, 'y'))
+ options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
env = environ_create();
if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env);
+ s = session_create(prefix, newname, cwd, env, oo, tiop);
- /* Set up the options. */
- oo = options_create(global_s_options);
- if (args_has(args, 'x') || args_has(args, 'y'))
- options_set_string(oo, "default-size", 0, "%ux%u", dsx, dsy);
+ /* Spawn the initial window. */
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
- /* Create the new session. */
- idx = -1 - options_get_number(global_s_options, "base-index");
- s = session_create(prefix, newname, argc, argv, path, cwd, env, oo,
- tiop, idx, &cause);
- environ_free(env);
- if (s == NULL) {
- cmdq_error(item, "create session failed: %s", cause);
- free(cause);
- goto error;
- }
+ sc.name = args_get(args, 'n');
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- /* Set the initial window name if one given. */
- if (argc >= 0 && (tmp = args_get(args, 'n')) != NULL) {
- cp = format_single(item, tmp, c, s, NULL, NULL);
- w = s->curw->window;
- window_set_name(w, cp);
- options_set_number(w->options, "automatic-rename", 0);
- free(cp);
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = 0;
+
+ if (spawn_window(&sc, &cause) == NULL) {
+ session_destroy(s, 0, __func__);
+ cmdq_error(item, "create window failed: %s", cause);
+ free(cause);
+ goto fail;
}
/*
@@ -364,7 +335,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(newname);
return (CMD_RETURN_NORMAL);
-error:
+fail:
free(cwd);
free(newname);
return (CMD_RETURN_ERROR);
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 5baeff65..e3bacff8 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -53,87 +53,45 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *current = &item->shared->current;
+ struct spawn_context sc;
+ struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct client *c = cmd_find_client(item, NULL, 1);
int idx = item->target.idx;
- const char *cmd, *path, *template, *tmp;
- char **argv, *cause, *cp, *cwd, *name;
- int argc, detached;
- struct environ_entry *envent;
+ struct winlink *new_wl;
+ char *cause = NULL, *cp;
+ const char *template;
struct cmd_find_state fs;
- if (args_has(args, 'a') && wl != NULL) {
- if ((idx = winlink_shuffle_up(s, wl)) == -1) {
- cmdq_error(item, "no free window indexes");
- return (CMD_RETURN_ERROR);
- }
- }
- detached = args_has(args, 'd');
-
- if (args->argc == 0) {
- cmd = options_get_string(s->options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- } else {
- argc = args->argc;
- argv = args->argv;
+ if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
+ cmdq_error(item, "couldn't get a window index");
+ return (CMD_RETURN_ERROR);
}
- path = NULL;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- if ((tmp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, tmp, c, s, NULL, NULL);
- else
- cwd = xstrdup(server_client_get_cwd(item->client, s));
-
- if ((tmp = args_get(args, 'n')) != NULL)
- name = format_single(item, tmp, c, s, NULL, NULL);
- else
- name = NULL;
-
- if (idx != -1)
- wl = winlink_find_by_index(&s->windows, idx);
- if (wl != NULL && args_has(args, 'k')) {
- /*
- * Can't use session_detach as it will destroy session if this
- * makes it empty.
- */
- notify_session_window("window-unlinked", s, wl->window);
- wl->flags &= ~WINLINK_ALERTFLAGS;
- winlink_stack_remove(&s->lastw, wl);
- winlink_remove(&s->windows, wl);
-
- /* Force select/redraw if current. */
- if (wl == s->curw) {
- detached = 0;
- s->curw = NULL;
- }
- }
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
- if (idx == -1)
- idx = -1 - options_get_number(s->options, "base-index");
- wl = session_new(s, name, argc, argv, path, cwd, idx,
- &cause);
- if (wl == NULL) {
+ sc.name = args_get(args, 'n');
+ sc.argc = args->argc;
+ sc.argv = args->argv;
+
+ sc.idx = idx;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = 0;
+ if (args_has(args, 'd'))
+ sc.flags |= SPAWN_DETACHED;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
+
+ if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause);
free(cause);
- goto error;
+ return (CMD_RETURN_ERROR);
}
- if (!detached) {
- session_select(s, wl->idx);
- cmd_find_from_winlink(current, wl, 0);
+ if (!args_has(args, 'd') || new_wl == s->curw) {
+ cmd_find_from_winlink(current, new_wl, 0);
server_redraw_session_group(s);
} else
server_status_session_group(s);
@@ -141,20 +99,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE;
- cp = format_single(item, template, c, s, wl, NULL);
+ cp = format_single(item, template, c, s, new_wl, NULL);
cmdq_print(item, "%s", cp);
free(cp);
}
- cmd_find_from_winlink(&fs, wl, 0);
+ cmd_find_from_winlink(&fs, new_wl, 0);
hooks_insert(s->hooks, item, &fs, "after-new-window");
- free(name);
- free(cwd);
return (CMD_RETURN_NORMAL);
-
-error:
- free(name);
- free(cwd);
- return (CMD_RETURN_ERROR);
}
diff --git a/cmd-queue.c b/cmd-queue.c
index 97b3c1c9..03fd5f10 100644
--- a/cmd-queue.c
+++ b/cmd-queue.c
@@ -111,7 +111,7 @@ cmdq_remove(struct cmdq_item *item)
if (item->client != NULL)
server_client_unref(item->client);
- if (item->type == CMDQ_COMMAND)
+ if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist);
TAILQ_REMOVE(item->queue, item, entry);
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index eb4a7e09..44234315 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -20,7 +20,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include "tmux.h"
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.args = { "c:kt:", 0, -1 },
.usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
- " [command]",
+ " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -48,53 +48,39 @@ static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
+ struct spawn_context sc;
+ struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
struct window_pane *wp = item->target.wp;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct environ *env;
- const char *path = NULL, *cp;
- char *cause, *cwd = NULL;
- u_int idx;
- struct environ_entry *envent;
-
- if (!args_has(self->args, 'k') && wp->fd != -1) {
- if (window_pane_index(wp, &idx) != 0)
- fatalx("index not found");
- cmdq_error(item, "pane still active: %s:%d.%u",
- s->name, wl->idx, idx);
- return (CMD_RETURN_ERROR);
- }
+ char *cause = NULL;
+
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
+
+ sc.wp0 = wp;
+ sc.lc = NULL;
- window_pane_reset_mode_all(wp);
- screen_reinit(&wp->base);
- input_init(wp);
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
- if ((cp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, cp, c, s, NULL, NULL);
+ sc.flags = SPAWN_RESPAWN;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
- env = environ_for_session(s, 0);
- if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
- s->tio, &cause) != 0) {
+ if (spawn_pane(&sc, &cause) == NULL) {
cmdq_error(item, "respawn pane failed: %s", cause);
free(cause);
- environ_free(env);
- free(cwd);
return (CMD_RETURN_ERROR);
}
- environ_free(env);
- free(cwd);
wp->flags |= PANE_REDRAW;
- server_status_window(w);
+ server_status_window(wp->window);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index 68791990..2ccb2fde 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -19,7 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include "tmux.h"
@@ -48,64 +48,34 @@ static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
+ struct spawn_context sc;
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
- struct window_pane *wp;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct environ *env;
- const char *path = NULL, *cp;
- char *cause, *cwd = NULL;
- struct environ_entry *envent;
-
- if (!args_has(self->args, 'k')) {
- TAILQ_FOREACH(wp, &w->panes, entry) {
- if (wp->fd == -1)
- continue;
- cmdq_error(item, "window still active: %s:%d", s->name,
- wl->idx);
- return (CMD_RETURN_ERROR);
- }
- }
+ char *cause = NULL;
+
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
+
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
- wp = TAILQ_FIRST(&w->panes);
- TAILQ_REMOVE(&w->panes, wp, entry);
- layout_free(w);
- window_destroy_panes(w);
- TAILQ_INSERT_HEAD(&w->panes, wp, entry);
- window_pane_resize(wp, w->sx, w->sy);
-
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- if ((cp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, cp, c, s, NULL, NULL);
-
- env = environ_for_session(s, 0);
- if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, cwd, env,
- s->tio, &cause) != 0) {
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = SPAWN_RESPAWN;
+ if (args_has(args, 'k'))
+ sc.flags |= SPAWN_KILL;
+
+ if (spawn_window(&sc, &cause) == NULL) {
cmdq_error(item, "respawn window failed: %s", cause);
free(cause);
- environ_free(env);
- free(cwd);
- server_destroy_pane(wp, 0);
return (CMD_RETURN_ERROR);
}
- environ_free(env);
- free(cwd);
-
- layout_init(w, wp);
- window_pane_reset_mode_all(wp);
- screen_reinit(&wp->base);
- input_init(wp);
- window_set_active_pane(w, wp);
- recalculate_sizes();
- server_redraw_window(w);
+ server_redraw_window(wl->window);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c
index 5a900a13..6dc0f2a8 100644
--- a/cmd-rotate-window.c
+++ b/cmd-rotate-window.c
@@ -77,7 +77,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
@@ -105,7 +105,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index 2873737f..af0f033b 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -112,7 +112,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
else {
server_unzoom_window(w);
window_redraw_active_switch(w, lastwp);
- if (window_set_active_pane(w, lastwp)) {
+ if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
@@ -194,7 +194,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
window_redraw_active_switch(w, wp);
- if (window_set_active_pane(w, wp)) {
+ if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
hooks_insert(s->hooks, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
diff --git a/cmd-show-options.c b/cmd-show-options.c
index 5d480664..59d9f9f5 100644
--- a/cmd-show-options.c
+++ b/cmd-show-options.c
@@ -29,8 +29,8 @@
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
-static enum cmd_retval cmd_show_options_one(struct cmd *, struct cmdq_item *,
- struct options *);
+static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
+ struct options_entry *, int);
static enum cmd_retval cmd_show_options_all(struct cmd *, struct cmdq_item *,
struct options *);
@@ -65,23 +65,95 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_find_state *fs = &item->target;
+ struct client *c = cmd_find_client(item, NULL, 1);
+ struct session *s = item->target.s;
+ struct winlink *wl = item->target.wl;
struct options *oo;
enum options_table_scope scope;
- char *cause;
- int window;
+ char *argument, *name = NULL, *cause;
+ const char *target;
+ int window, idx, ambiguous;
+ struct options_entry *o;
window = (self->entry == &cmd_show_window_options_entry);
- scope = options_scope_from_flags(args, window, fs, &oo, &cause);
+ if (args->argc == 0) {
+ scope = options_scope_from_flags(args, window, fs, &oo, &cause);
+ return (cmd_show_options_all(self, item, oo));
+ }
+ argument = format_single(item, args->argv[0], c, s, wl, NULL);
+
+ name = options_match(argument, &idx, &ambiguous);
+ if (name == NULL) {
+ if (args_has(args, 'q'))
+ goto fail;
+ if (ambiguous)
+ cmdq_error(item, "ambiguous option: %s", argument);
+ else
+ cmdq_error(item, "invalid option: %s", argument);
+ goto fail;
+ }
+ if (*name == '@')
+ scope = options_scope_from_flags(args, window, fs, &oo, &cause);
+ else {
+ if (options_get_only(global_options, name) != NULL)
+ scope = OPTIONS_TABLE_SERVER;
+ else if (options_get_only(global_s_options, name) != NULL)
+ scope = OPTIONS_TABLE_SESSION;
+ else if (options_get_only(global_w_options, name) != NULL)
+ scope = OPTIONS_TABLE_WINDOW;
+ else {
+ scope = OPTIONS_TABLE_NONE;
+ xasprintf(&cause, "unknown option: %s", argument);
+ }
+ if (scope == OPTIONS_TABLE_SERVER)
+ oo = global_options;
+ else if (scope == OPTIONS_TABLE_SESSION) {
+ if (args_has(self->args, 'g'))
+ oo = global_s_options;
+ else if (s == NULL) {
+ target = args_get(args, 't');
+ if (target != NULL) {
+ cmdq_error(item, "no such session: %s",
+ target);
+ } else
+ cmdq_error(item, "no current session");
+ goto fail;
+ } else
+ oo = s->options;
+ } else if (scope == OPTIONS_TABLE_WINDOW) {
+ if (args_has(self->args, 'g'))
+ oo = global_w_options;
+ else if (wl == NULL) {
+ target = args_get(args, 't');
+ if (target != NULL) {
+ cmdq_error(item, "no such window: %s",
+ target);
+ } else
+ cmdq_error(item, "no current window");
+ goto fail;
+ } else
+ oo = wl->window->options;
+ }
+ }
if (scope == OPTIONS_TABLE_NONE) {
+ if (args_has(args, 'q'))
+ goto fail;
cmdq_error(item, "%s", cause);
free(cause);
- return (CMD_RETURN_ERROR);
+ goto fail;
}
+ o = options_get_only(oo, name);
+ if (o != NULL)
+ cmd_show_options_print(self, item, o, idx);
- if (args->argc == 0)
- return (cmd_show_options_all(self, item, oo));
- else
- return (cmd_show_options_one(self, item, oo));
+ free(name);
+ free(argument);
+ return (CMD_RETURN_NORMAL);
+
+fail:
+ free(name);
+ free(argument);
+ return (CMD_RETURN_ERROR);
}
static void
@@ -123,55 +195,15 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
}
static enum cmd_retval
-cmd_show_options_one(struct cmd *self, struct cmdq_item *item,
- struct options *oo)
-{
- struct args *args = self->args;
- struct client *c = cmd_find_client(item, NULL, 1);
- struct session *s = item->target.s;
- struct winlink *wl = item->target.wl;
- struct options_entry *o;
- int idx, ambiguous;
- char *name;
-
- name = format_single(item, args->argv[0], c, s, wl, NULL);
- o = options_match_get(oo, name, &idx, 1, &ambiguous);
- if (o == NULL) {
- if (args_has(args, 'q')) {
- free(name);
- return (CMD_RETURN_NORMAL);
- }
- if (ambiguous) {
- cmdq_error(item, "ambiguous option: %s", name);
- free(name);
- return (CMD_RETURN_ERROR);
- }
- if (*name != '@' &&
- options_match_get(oo, name, &idx, 0, &ambiguous) != NULL) {
- free(name);
- return (CMD_RETURN_NORMAL);
- }
- cmdq_error(item, "unknown option: %s", name);
- free(name);
- return (CMD_RETURN_ERROR);
- }
- cmd_show_options_print(self, item, o, idx);
- free(name);
- return (CMD_RETURN_NORMAL);
-}
-
-static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo)
{
struct options_entry *o;
- const struct options_table_entry *oe;
struct options_array_item *a;
u_int idx;
o = options_first(oo);
while (o != NULL) {
- oe = options_table_entry(o);
if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1);
else {
diff --git a/cmd-split-window.c b/cmd-split-window.c
index f5dde751..e64e9247 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -52,111 +52,87 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{
- struct cmd_find_state *current = &item->shared->current;
struct args *args = self->args;
+ struct cmd_find_state *current = &item->shared->current;
+ struct spawn_context sc;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
- struct window *w = wl->window;
- struct window_pane *wp = item->target.wp, *new_wp = NULL;
- struct environ *env;
- const char *cmd, *path, *shell, *template, *tmp;
- char **argv, *cause, *new_cause, *cp, *cwd;
- u_int hlimit;
- int argc, size, percentage, before;
+ struct window_pane *wp = item->target.wp, *new_wp;
enum layout_type type;
struct layout_cell *lc;
- struct environ_entry *envent;
- struct cmd_find_state fs;
-
- server_unzoom_window(w);
-
- if (args->argc == 0) {
- cmd = options_get_string(s->options, "default-command");
- if (cmd != NULL && *cmd != '\0') {
- argc = 1;
- argv = (char **)&cmd;
- } else {
- argc = 0;
- argv = NULL;
- }
- } else {
- argc = args->argc;
- argv = args->argv;
- }
-
- if ((tmp = args_get(args, 'c')) != NULL)
- cwd = format_single(item, tmp, c, s, NULL, NULL);
- else
- cwd = xstrdup(server_client_get_cwd(item->client, s));
+ struct cmd_find_state fs;
+ int size, percentage, flags;
+ const char *template;
+ char *cause, *cp;
- type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
- before = args_has(args, 'b');
-
- size = -1;
+ else
+ type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
- xasprintf(&new_cause, "size %s", cause);
+ cmdq_error(item, "create pane failed: -l %s", cause);
free(cause);
- cause = new_cause;
- goto error;
+ return (CMD_RETURN_ERROR);
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
- xasprintf(&new_cause, "percentage %s", cause);
+ cmdq_error(item, "create pane failed: -p %s", cause);
free(cause);
- cause = new_cause;
- goto error;
+ return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
- }
- hlimit = options_get_number(s->options, "history-limit");
+ } else
+ size = -1;
+
+ server_unzoom_window(wp->window);
- shell = options_get_string(s->options, "default-shell");
- if (*shell == '\0' || areshell(shell))
- shell = _PATH_BSHELL;
+ flags = 0;
+ if (args_has(args, 'b'))
+ flags |= SPAWN_BEFORE;
+ if (args_has(args, 'f'))
+ flags |= SPAWN_FULLSIZE;
- lc = layout_split_pane(wp, type, size, before, args_has(args, 'f'));
+ lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) {
- cause = xstrdup("pane too small");
- goto error;
+ cmdq_error(item, "no space for new pane");
+ return (CMD_RETURN_ERROR);
}
- new_wp = window_add_pane(w, wp, before, args_has(args, 'f'), hlimit);
- layout_make_leaf(lc, new_wp);
- path = NULL;
- if (item->client != NULL && item->client->session == NULL)
- envent = environ_find(item->client->environ, "PATH");
- else
- envent = environ_find(s->environ, "PATH");
- if (envent != NULL)
- path = envent->value;
-
- env = environ_for_session(s, 0);
- if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, env,
- s->tio, &cause) != 0) {
- environ_free(env);
- goto error;
- }
- environ_free(env);
+ memset(&sc, 0, sizeof sc);
+ sc.item = item;
+ sc.s = s;
+ sc.wl = wl;
- layout_fix_panes(w);
- server_redraw_window(w);
+ sc.wp0 = wp;
+ sc.lc = lc;
- if (!args_has(args, 'd')) {
- window_set_active_pane(w, new_wp);
- session_select(s, wl->idx);
- cmd_find_from_session(current, s, 0);
- server_redraw_session(s);
- } else
- server_status_session(s);
+ sc.name = NULL;
+ sc.argc = args->argc;
+ sc.argv = args->argv;
+
+ sc.idx = -1;
+ sc.cwd = args_get(args, 'c');
+
+ sc.flags = flags;
+ if (args_has(args, 'd'))
+ sc.flags |= SPAWN_DETACHED;
+
+ if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
+ cmdq_error(item, "create pane failed: %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);
+ server_status_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)
@@ -165,22 +141,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmdq_print(item, "%s", cp);
free(cp);
}
- notify_window("window-layout-changed", w);
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
hooks_insert(s->hooks, item, &fs, "after-split-window");
- free(cwd);
return (CMD_RETURN_NORMAL);
-
-error:
- if (new_wp != NULL) {
- layout_close_pane(new_wp);
- window_remove_pane(w, new_wp);
- }
- cmdq_error(item, "create pane failed: %s", cause);
- free(cause);
-
- free(cwd);
- return (CMD_RETURN_ERROR);
}
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index 1de272c4..2ad05561 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -101,17 +101,17 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
if (!args_has(self->args, 'd')) {
if (src_w != dst_w) {
- window_set_active_pane(src_w, dst_wp);
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(src_w, dst_wp, 1);
+ window_set_active_pane(dst_w, src_wp, 1);
} else {
tmp_wp = dst_wp;
- window_set_active_pane(src_w, tmp_wp);
+ window_set_active_pane(src_w, tmp_wp, 1);
}
} else {
if (src_w->active == src_wp)
- window_set_active_pane(src_w, dst_wp);
+ window_set_active_pane(src_w, dst_wp, 1);
if (dst_w->active == dst_wp)
- window_set_active_pane(dst_w, src_wp);
+ window_set_active_pane(dst_w, src_wp, 1);
}
if (src_w != dst_w) {
if (src_w->last == src_wp)
diff --git a/cmd-switch-client.c b/cmd-switch-client.c
index 3e19346e..8f51d0fe 100644
--- a/cmd-switch-client.c
+++ b/cmd-switch-client.c
@@ -61,7 +61,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
return (CMD_RETURN_ERROR);
- if (tflag != NULL && tflag[strcspn(tflag, ":.")] != '\0') {
+ if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE;
flags = 0;
} else {
@@ -116,7 +116,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
- window_set_active_pane(wp->window, wp);
+ window_set_active_pane(wp->window, wp, 1);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
diff --git a/compat.h b/compat.h
index b83e6189..402ffb90 100644
--- a/compat.h
+++ b/compat.h
@@ -67,6 +67,7 @@ void warnx(const char *, ...);
#define _PATH_DEVNULL "/dev/null"
#define _PATH_TTY "/dev/tty"
#define _PATH_DEV "/dev/"
+#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifndef __OpenBSD__
diff --git a/configure.ac b/configure.ac
index f04ae14d..1e7578ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 2.9-rc3)
+AC_INIT([tmux], next-3.0)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
diff --git a/format.c b/format.c
index 485a3bc7..a5c61d68 100644
--- a/format.c
+++ b/format.c
@@ -1822,6 +1822,23 @@ void
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp)
{
+ if (c != NULL)
+ log_debug("%s: c=%s", __func__, c->name);
+ else
+ log_debug("%s: s=none", __func__);
+ if (s != NULL)
+ log_debug("%s: s=$%u", __func__, s->id);
+ else
+ log_debug("%s: s=none", __func__);
+ if (wl != NULL)
+ log_debug("%s: wl=%u w=@%u", __func__, wl->idx, wl->window->id);
+ else
+ log_debug("%s: wl=none", __func__);
+ if (wp != NULL)
+ log_debug("%s: wp=%%%u", __func__, wp->id);
+ else
+ log_debug("%s: wp=none", __func__);
+
if (c != NULL && s != NULL && c->session != s)
log_debug("%s: session does not match", __func__);
diff --git a/input.c b/input.c
index 96793674..07341403 100644
--- a/input.c
+++ b/input.c
@@ -2432,7 +2432,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
- paste_add(out, outlen);
+ paste_add(NULL, out, outlen);
}
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
diff --git a/layout.c b/layout.c
index fa6f0613..f974e10d 100644
--- a/layout.c
+++ b/layout.c
@@ -831,12 +831,12 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
*/
struct layout_cell *
layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
- int insert_before, int full_size)
+ int flags)
{
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
u_int sx, sy, xoff, yoff, size1, size2, minimum;
u_int new_size, saved_size, resize_first = 0;
- int status;
+ int full_size = (flags & SPAWN_FULLSIZE), status;
/*
* If full_size is specified, add a new cell at the top of the window
@@ -881,7 +881,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
saved_size = sy;
if (size < 0)
size2 = ((saved_size + 1) / 2) - 1;
- else if (insert_before)
+ else if (flags & SPAWN_BEFORE)
size2 = saved_size - size - 1;
else
size2 = size;
@@ -892,7 +892,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
size1 = saved_size - 1 - size2;
/* Which size are we using? */
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
new_size = size2;
else
new_size = size1;
@@ -908,7 +908,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
*/
lcparent = lc->parent;
lcnew = layout_create_cell(lcparent);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(lc, lcnew, entry);
else
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
@@ -937,7 +937,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
layout_set_size(lcnew, size, sy, 0, 0);
else if (lc->type == LAYOUT_TOPBOTTOM)
layout_set_size(lcnew, sx, size, 0, 0);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
else
TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
@@ -961,12 +961,12 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
/* Create the new child cell. */
lcnew = layout_create_cell(lcparent);
- if (insert_before)
+ if (flags & SPAWN_BEFORE)
TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
else
TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
}
- if (insert_before) {
+ if (flags & SPAWN_BEFORE) {
lc1 = lcnew;
lc2 = lc;
} else {
diff --git a/osdep-darwin.c b/osdep-darwin.c
index 5d69cdda..d4a88028 100644
--- a/osdep-darwin.c
+++ b/osdep-darwin.c
@@ -30,7 +30,9 @@ char *osdep_get_name(int, char *);
char *osdep_get_cwd(int);
struct event_base *osdep_event_init(void);
+#ifndef __unused
#define __unused __attribute__ ((__unused__))
+#endif
char *
osdep_get_name(int fd, __unused char *tty)
@@ -47,6 +49,7 @@ osdep_get_name(int fd, __unused char *tty)
&bsdinfo, sizeof bsdinfo);
if (ret == sizeof bsdinfo && *bsdinfo.pbsi_comm != '\0')
return (strdup(bsdinfo.pbsi_comm));
+ return (NULL);
#else
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
size_t size;
diff --git a/paste.c b/paste.c
index 2f2c043b..c1036ad9 100644
--- a/paste.c
+++ b/paste.c
@@ -157,11 +157,14 @@ paste_free(struct paste_buffer *pb)
* that the caller is responsible for allocating data.
*/
void
-paste_add(char *data, size_t size)
+paste_add(const char *prefix, char *data, size_t size)
{
struct paste_buffer *pb, *pb1;
u_int limit;
+ if (prefix == NULL)
+ prefix = "buffer";
+
if (size == 0) {
free(data);
return;
@@ -180,7 +183,7 @@ paste_add(char *data, size_t size)
pb->name = NULL;
do {
free(pb->name);
- xasprintf(&pb->name, "buffer%04u", paste_next_index);
+ xasprintf(&pb->name, "%s%u", prefix, paste_next_index);
paste_next_index++;
} while (paste_get_name(pb->name) != NULL);
@@ -262,7 +265,7 @@ paste_set(char *data, size_t size, const char *name, char **cause)
return (0);
}
if (name == NULL) {
- paste_add(data, size);
+ paste_add(NULL, data, size);
return (0);
}
diff --git a/screen-write.c b/screen-write.c
index 566d4d14..237b6359 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -1139,7 +1139,7 @@ screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
u_int i;
size_t size;
- for (i = y ; i < y + n; i++) {
+ for (i = y; i < y + n; i++) {
if (TAILQ_EMPTY(&ctx->list[i].items))
continue;
size = 0;
diff --git a/server-client.c b/server-client.c
index aea090c7..bf7da577 100644
--- a/server-client.c
+++ b/server-client.c
@@ -1379,6 +1379,7 @@ focused:
if (wp->base.mode & MODE_FOCUSON)
bufferevent_write(wp->event, "\033[I", 3);
notify_pane("pane-focus-in", wp);
+ session_update_activity(c->session, NULL);
}
wp->flags |= PANE_FOCUSED;
}
diff --git a/server-fn.c b/server-fn.c
index 90db7d51..8051fe4f 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -369,7 +369,7 @@ server_destroy_session_group(struct session *s)
else {
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
}
}
@@ -436,7 +436,7 @@ server_check_unattached(void)
if (s->attached != 0)
continue;
if (options_get_number (s->options, "destroy-unattached"))
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
}
diff --git a/server.c b/server.c
index 04f907f3..41bc492e 100644
--- a/server.c
+++ b/server.c
@@ -296,7 +296,7 @@ server_send_exit(void)
}
RB_FOREACH_SAFE(s, sessions, &sessions, s1)
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
/* Update socket execute permissions based on whether sessions are attached. */
diff --git a/session.c b/session.c
index fe4a8875..9a32990e 100644
--- a/session.c
+++ b/session.c
@@ -111,12 +111,10 @@ session_find_by_id(u_int id)
/* Create a new session. */
struct session *
-session_create(const char *prefix, const char *name, int argc, char **argv,
- const char *path, const char *cwd, struct environ *env, struct options *oo,
- struct termios *tio, int idx, char **cause)
+session_create(const char *prefix, const char *name, const char *cwd,
+ struct environ *env, struct options *oo, struct termios *tio)
{
struct session *s;
- struct winlink *wl;
s = xcalloc(1, sizeof *s);
s->references = 1;
@@ -128,10 +126,7 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
TAILQ_INIT(&s->lastw);
RB_INIT(&s->windows);
- s->environ = environ_create();
- if (env != NULL)
- environ_copy(env, s->environ);
-
+ s->environ = env;
s->options = oo;
s->hooks = hooks_create(global_hooks);
@@ -165,17 +160,6 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
fatal("gettimeofday failed");
session_update_activity(s, &s->creation_time);
- if (argc >= 0) {
- wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause);
- if (wl == NULL) {
- session_destroy(s, __func__);
- return (NULL);
- }
- session_select(s, RB_ROOT(&s->windows)->idx);
- }
-
- log_debug("session %s created", s->name);
-
return (s);
}
@@ -219,7 +203,7 @@ session_free(__unused int fd, __unused short events, void *arg)
/* Destroy a session. */
void
-session_destroy(struct session *s, const char *from)
+session_destroy(struct session *s, int notify, const char *from)
{
struct winlink *wl;
@@ -227,7 +211,8 @@ session_destroy(struct session *s, const char *from)
s->curw = NULL;
RB_REMOVE(sessions, &sessions, s);
- notify_session("session-closed", s);
+ if (notify)
+ notify_session("session-closed", s);
free(s->tio);
@@ -337,45 +322,6 @@ session_previous_session(struct session *s)
return (s2);
}
-/* Create a new window on a session. */
-struct winlink *
-session_new(struct session *s, const char *name, int argc, char **argv,
- const char *path, const char *cwd, int idx, char **cause)
-{
- struct window *w;
- struct winlink *wl;
- struct environ *env;
- const char *shell;
- u_int hlimit, sx, sy;
-
- if ((wl = winlink_add(&s->windows, idx)) == NULL) {
- xasprintf(cause, "index in use: %d", idx);
- return (NULL);
- }
- wl->session = s;
-
- shell = options_get_string(s->options, "default-shell");
- if (*shell == '\0' || areshell(shell))
- shell = _PATH_BSHELL;
-
- default_window_size(s, NULL, &sx, &sy, -1);
- hlimit = options_get_number(s->options, "history-limit");
- env = environ_for_session(s, 0);
- w = window_create_spawn(name, argc, argv, path, shell, cwd, env, s->tio,
- sx, sy, hlimit, cause);
- if (w == NULL) {
- winlink_remove(&s->windows, wl);
- environ_free(env);
- return (NULL);
- }
- winlink_set_window(wl, w);
- environ_free(env);
- notify_session_window("window-linked", s, w);
-
- session_group_synchronize_from(s);
- return (wl);
-}
-
/* Attach a window to a session. */
struct winlink *
session_attach(struct session *s, struct window *w, int idx, char **cause)
@@ -411,7 +357,7 @@ session_detach(struct session *s, struct winlink *wl)
session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) {
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
return (1);
}
return (0);
diff --git a/spawn.c b/spawn.c
new file mode 100644
index 00000000..1da3c857
--- /dev/null
+++ b/spawn.c
@@ -0,0 +1,432 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+/*
+ * Set up the environment and create a new window and pane or a new pane.
+ *
+ * We need to set up the following items:
+ *
+ * - history limit, comes from the session;
+ *
+ * - base index, comes from the session;
+ *
+ * - current working directory, may be specified - if it isn't it comes from
+ * either the client or the session;
+ *
+ * - PATH variable, comes from the client if any, otherwise from the session
+ * environment;
+ *
+ * - shell, comes from default-shell;
+ *
+ * - termios, comes from the session;
+ *
+ * - remaining environment, comes from the session.
+ */
+
+static void
+spawn_log(const char *from, struct spawn_context *sc)
+{
+ struct session *s = sc->s;
+ struct winlink *wl = sc->wl;
+ struct window_pane *wp0 = sc->wp0;
+ char tmp[128];
+ const char *name;
+
+ log_debug("%s: %s, flags=%#x", from, sc->item->name, sc->flags);
+
+ if (wl != NULL && wp0 != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=%d wp0=%%%u", wl->idx, wp0->id);
+ else if (wl != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=%d wp0=none", wl->idx);
+ else if (wp0 != NULL)
+ xsnprintf(tmp, sizeof tmp, "wl=none wp0=%%%u", wp0->id);
+ else
+ xsnprintf(tmp, sizeof tmp, "wl=none wp0=none");
+ log_debug("%s: s=$%u %s idx=%d", from, s->id, tmp, sc->idx);
+
+ name = sc->name;
+ if (name == NULL)
+ name = "none";
+ log_debug("%s: name=%s", from, name);
+}
+
+struct winlink *
+spawn_window(struct spawn_context *sc, char **cause)
+{
+ struct session *s = sc->s;
+ struct window *w;
+ struct window_pane *wp;
+ struct winlink *wl;
+ int idx = sc->idx;
+ u_int sx, sy;
+
+ spawn_log(__func__, sc);
+
+ /*
+ * If the window already exists, we are respawning, so destroy all the
+ * panes except one.
+ */
+ if (sc->flags & SPAWN_RESPAWN) {
+ w = sc->wl->window;
+ if (~sc->flags & SPAWN_KILL) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (wp->fd != -1)
+ break;
+ }
+ if (wp != NULL) {
+ xasprintf(cause, "window %s:%d still active",
+ s->name, sc->wl->idx);
+ return (NULL);
+ }
+ }
+
+ sc->wp0 = TAILQ_FIRST(&w->panes);
+ TAILQ_REMOVE(&w->panes, sc->wp0, entry);
+
+ layout_free(w);
+ window_destroy_panes(w);
+
+ TAILQ_INSERT_HEAD(&w->panes, sc->wp0, entry);
+ window_pane_resize(sc->wp0, w->sx, w->sy);
+
+ layout_init(w, sc->wp0);
+ window_set_active_pane(w, sc->wp0, 0);
+ }
+
+ /*
+ * Otherwise we have no window so we will need to create one. First
+ * check if the given index already exists and destroy it if so.
+ */
+ if ((~sc->flags & SPAWN_RESPAWN) && idx != -1) {
+ wl = winlink_find_by_index(&s->windows, idx);
+ if (wl != NULL && (~sc->flags & SPAWN_KILL)) {
+ xasprintf(cause, "index %d in use", idx);
+ return (NULL);
+ }
+ if (wl != NULL) {
+ /*
+ * Can't use session_detach as it will destroy session
+ * if this makes it empty.
+ */
+ wl->flags &= ~WINLINK_ALERTFLAGS;
+ notify_session_window("window-unlinked", s, wl->window);
+ winlink_stack_remove(&s->lastw, wl);
+ winlink_remove(&s->windows, wl);
+
+ if (s->curw == wl) {
+ s->curw = NULL;
+ sc->flags &= ~SPAWN_DETACHED;
+ }
+ }
+ }
+
+ /* Then create a window if needed. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ if (idx == -1)
+ idx = -1 - options_get_number(s->options, "base-index");
+ if ((sc->wl = winlink_add(&s->windows, idx)) == NULL) {
+ xasprintf(cause, "couldn't add window %d", idx);
+ return (NULL);
+ }
+ default_window_size(s, NULL, &sx, &sy, -1);
+ if ((w = window_create(sx, sy)) == NULL) {
+ winlink_remove(&s->windows, sc->wl);
+ xasprintf(cause, "couldn't create window %d", idx);
+ return (NULL);
+ }
+ sc->wl->session = s;
+ winlink_set_window(sc->wl, w);
+ } else
+ w = NULL;
+ sc->flags |= SPAWN_NONOTIFY;
+
+ /* Spawn the pane. */
+ wp = spawn_pane(sc, cause);
+ if (wp == NULL) {
+ if (~sc->flags & SPAWN_RESPAWN) {
+ window_destroy(w);
+ winlink_remove(&s->windows, sc->wl);
+ }
+ return (NULL);
+ }
+
+ /* Set the name of the new window. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ if (sc->name != NULL) {
+ w->name = xstrdup(sc->name);
+ options_set_number(w->options, "automatic-rename", 0);
+ } else
+ w->name = xstrdup(default_window_name(w));
+ }
+
+ /* Switch to the new window if required. */
+ if (~sc->flags & SPAWN_DETACHED)
+ session_select(s, sc->wl->idx);
+
+ /* Fire notification if new window. */
+ if (~sc->flags & SPAWN_RESPAWN)
+ notify_session_window("window-linked", s, w);
+
+ session_group_synchronize_from(s);
+ return (sc->wl);
+}
+
+struct window_pane *
+spawn_pane(struct spawn_context *sc, char **cause)
+{
+ struct cmdq_item *item = sc->item;
+ struct client *c = item->client;
+ struct session *s = sc->s;
+ struct window *w = sc->wl->window;
+ struct window_pane *new_wp;
+ struct environ *child;
+ struct environ_entry *ee;
+ char **argv, *cp, **argvp, *argv0, *cwd;
+ const char *cmd, *tmp;
+ int argc;
+ u_int idx;
+ struct termios now;
+ u_int hlimit;
+ struct winsize ws;
+ sigset_t set, oldset;
+
+ spawn_log(__func__, sc);
+
+ /*
+ * If we are respawning then get rid of the old process. Otherwise
+ * either create a new cell or assign to the one we are given.
+ */
+ hlimit = options_get_number(s->options, "history-limit");
+ if (sc->flags & SPAWN_RESPAWN) {
+ if (sc->wp0->fd != -1 && (~sc->flags & SPAWN_KILL)) {
+ window_pane_index(sc->wp0, &idx);
+ xasprintf(cause, "pane %s:%d.%u still active",
+ s->name, sc->wl->idx, idx);
+ return (NULL);
+ }
+ if (sc->wp0->fd != -1) {
+ bufferevent_free(sc->wp0->event);
+ close(sc->wp0->fd);
+ }
+ window_pane_reset_mode_all(sc->wp0);
+ screen_reinit(&sc->wp0->base);
+ input_init(sc->wp0);
+ new_wp = sc->wp0;
+ new_wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
+ } else if (sc->lc == NULL) {
+ new_wp = window_add_pane(w, NULL, hlimit, sc->flags);
+ layout_init(w, new_wp);
+ } else {
+ new_wp = window_add_pane(w, sc->wp0, hlimit, sc->flags);
+ layout_assign_pane(sc->lc, new_wp);
+ }
+
+ /*
+ * Now we have a pane with nothing running in it ready for the new
+ * process. Work out the command and arguments.
+ */
+ if (sc->argc == 0) {
+ cmd = options_get_string(s->options, "default-command");
+ if (cmd != NULL && *cmd != '\0') {
+ argc = 1;
+ argv = (char **)&cmd;
+ } else {
+ argc = 0;
+ argv = NULL;
+ }
+ } else {
+ argc = sc->argc;
+ argv = sc->argv;
+ }
+
+ /*
+ * Replace the stored arguments if there are new ones. If not, the
+ * existing ones will be used (they will only exist for respawn).
+ */
+ if (argc > 0) {
+ cmd_free_argv(new_wp->argc, new_wp->argv);
+ new_wp->argc = argc;
+ new_wp->argv = cmd_copy_argv(argc, argv);
+ }
+
+ /*
+ * Work out the current working directory. If respawning, use
+ * the pane's stored one unless specified.
+ */
+ if (sc->cwd != NULL)
+ cwd = format_single(item, sc->cwd, c, s, NULL, NULL);
+ else if (~sc->flags & SPAWN_RESPAWN)
+ cwd = xstrdup(server_client_get_cwd(c, s));
+ else
+ cwd = NULL;
+ if (cwd != NULL) {
+ free(new_wp->cwd);
+ new_wp->cwd = cwd;
+ }
+
+ /* Create an environment for this pane. */
+ child = environ_for_session(s, 0);
+ environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
+
+ /*
+ * Then the PATH environment variable. The session one is replaced from
+ * the client if there is one because otherwise running "tmux new
+ * myprogram" wouldn't work if myprogram isn't in the session's path.
+ */
+ if (c != NULL && c->session == NULL) { /* only unattached clients */
+ ee = environ_find(c->environ, "PATH");
+ if (ee != NULL)
+ environ_set(child, "PATH", "%s", ee->value);
+ }
+ if (environ_find(child, "PATH") == NULL)
+ environ_set(child, "%s", _PATH_DEFPATH);
+
+ /* Then the shell. If respawning, use the old one. */
+ if (~sc->flags & SPAWN_RESPAWN) {
+ tmp = options_get_string(s->options, "default-shell");
+ if (*tmp == '\0' || areshell(tmp))
+ tmp = _PATH_BSHELL;
+ free(new_wp->shell);
+ new_wp->shell = xstrdup(tmp);
+ }
+ environ_set(child, "SHELL", "%s", new_wp->shell);
+
+ /* Log the arguments we are going to use. */
+ log_debug("%s: shell=%s", __func__, new_wp->shell);
+ if (new_wp->argc != 0) {
+ cp = cmd_stringify_argv(new_wp->argc, new_wp->argv);
+ log_debug("%s: cmd=%s", __func__, cp);
+ free(cp);
+ }
+ if (cwd != NULL)
+ log_debug("%s: cwd=%s", __func__, cwd);
+ cmd_log_argv(new_wp->argc, new_wp->argv, __func__);
+ environ_log(child, "%s: environment ", __func__);
+
+ /* Initialize the window size. */
+ memset(&ws, 0, sizeof ws);
+ ws.ws_col = screen_size_x(&new_wp->base);
+ ws.ws_row = screen_size_y(&new_wp->base);
+
+ /* Block signals until fork has completed. */
+ sigfillset(&set);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+
+ /* Fork the new process. */
+ new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws);
+ if (new_wp->pid == -1) {
+ xasprintf(cause, "fork failed: %s", strerror(errno));
+ new_wp->fd = -1;
+ if (~sc->flags & SPAWN_RESPAWN) {
+ layout_close_pane(new_wp);
+ window_remove_pane(w, new_wp);
+ }
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (NULL);
+ }
+
+ /* 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);
+ }
+
+ /*
+ * Child process. Change to the working directory or home if that
+ * fails.
+ */
+ if (chdir(new_wp->cwd) != 0) {
+ if ((tmp = find_home()) == NULL || chdir(tmp) != 0)
+ chdir("/");
+ }
+
+ /*
+ * Update terminal escape characters from the session if available and
+ * force VERASE to tmux's \177.
+ */
+ if (tcgetattr(STDIN_FILENO, &now) != 0)
+ _exit(1);
+ if (s->tio != NULL)
+ memcpy(now.c_cc, s->tio->c_cc, sizeof now.c_cc);
+ now.c_cc[VERASE] = '\177';
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &now) != 0)
+ _exit(1);
+
+ /* Clean up file descriptors and signals and update the environment. */
+ closefrom(STDERR_FILENO + 1);
+ proc_clear_signals(server_proc, 1);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ log_close();
+ environ_push(child);
+
+ /*
+ * If given multiple arguments, use execvp(). Copy the arguments to
+ * ensure they end in a NULL.
+ */
+ if (new_wp->argc != 0 && new_wp->argc != 1) {
+ argvp = cmd_copy_argv(new_wp->argc, new_wp->argv);
+ execvp(argvp[0], argvp);
+ _exit(1);
+ }
+
+ /*
+ * If one argument, pass it to $SHELL -c. Otherwise create a login
+ * shell.
+ */
+ cp = strrchr(new_wp->shell, '/');
+ if (new_wp->argc == 1) {
+ tmp = new_wp->argv[0];
+ if (cp != NULL && cp[1] != '\0')
+ xasprintf(&argv0, "%s", cp + 1);
+ else
+ xasprintf(&argv0, "%s", new_wp->shell);
+ execl(new_wp->shell, argv0, "-c", tmp, (char *)NULL);
+ _exit(1);
+ }
+ if (cp != NULL && cp[1] != '\0')
+ xasprintf(&argv0, "-%s", cp + 1);
+ else
+ xasprintf(&argv0, "-%s", new_wp->shell);
+ execl(new_wp->shell, argv0, (char *)NULL);
+ _exit(1);
+}
diff --git a/style.c b/style.c
index c3d2960d..92941dbd 100644
--- a/style.c
+++ b/style.c
@@ -172,7 +172,7 @@ style_tostring(struct style *sy)
{
struct grid_cell *gc = &sy->gc;
int off = 0;
- const char *comma = "", *tmp;
+ const char *comma = "", *tmp = "";
static char s[256];
char b[16];
diff --git a/tmux.1 b/tmux.1
index 3ba70770..0d2339fd 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1096,6 +1096,14 @@ Switch the current session for client
.Ar target-client
to
.Ar target-session .
+As a special case,
+.Fl t
+may refer to a pane (a target that contains
+.Ql : ,
+.Ql .
+or
+.Ql % )
+in which case the session, window and pane are all changed.
If
.Fl l ,
.Fl n
@@ -1175,12 +1183,12 @@ The following commands are supported in copy mode:
.It Li "bottom-line" Ta "L" Ta ""
.It Li "cancel" Ta "q" Ta "Escape"
.It Li "clear-selection" Ta "Escape" Ta "C-g"
-.It Li "copy-end-of-line" Ta "D" Ta "C-k"
-.It Li "copy-line" Ta "" Ta ""
-.It Li "copy-pipe <command>" Ta "" Ta ""
-.It Li "copy-pipe-and-cancel <command>" Ta "" Ta ""
-.It Li "copy-selection" Ta "" Ta ""
-.It Li "copy-selection-and-cancel" Ta "Enter" Ta "M-w"
+.It Li "copy-end-of-line [<prefix>]" Ta "D" Ta "C-k"
+.It Li "copy-line [<prefix>]" Ta "" Ta ""
+.It Li "copy-pipe <command> [<prefix>]" Ta "" Ta ""
+.It Li "copy-pipe-and-cancel <command> [<prefix>]" Ta "" Ta ""
+.It Li "copy-selection [<prefix>]" Ta "" Ta ""
+.It Li "copy-selection-and-cancel [<prefix>]" Ta "Enter" Ta "M-w"
.It Li "cursor-down" Ta "j" Ta "Down"
.It Li "cursor-left" Ta "h" Ta "Left"
.It Li "cursor-right" Ta "l" Ta "Right"
@@ -1222,11 +1230,21 @@ The following commands are supported in copy mode:
.It Li "search-forward-incremental <for>" Ta "" Ta "C-s"
.It Li "search-reverse" Ta "N" Ta "N"
.It Li "select-line" Ta "V" Ta ""
+.It Li "select-word" Ta "" Ta ""
.It Li "start-of-line" Ta "0" Ta "C-a"
.It Li "stop-selection" Ta "" Ta ""
.It Li "top-line" Ta "H" Ta "M-R"
.El
.Pp
+Copy commands may take an optional buffer prefix argument which is used
+to generate the buffer name (the default is
+.Ql buffer
+so buffers are named
+.Ql buffer0 ,
+.Ql buffer1
+and so on).
+Pipe commands take a command argument which is the command to which the
+copied text is piped.
The
.Ql -and-cancel
variants of some commands exit copy mode after they have completed (for copy
@@ -2513,9 +2531,17 @@ command),
a server option with
.Fl s ,
otherwise a session option.
+If the option is not a user option,
+.Fl w
+and
+.Fl s
+are unnecessary -
+.Nm
+will infer the type from the option name.
If
.Fl g
is given, the global session or window option is set.
+.Pp
.Fl F
expands formats in the option value.
The
@@ -3444,6 +3470,15 @@ the server options with
.Fl s ,
otherwise the session options for
.Ar target session .
+If
+.Ar option
+is given and is not a user option,
+.Fl w
+and
+.Fl s
+are unnecessary -
+.Nm
+will infer the type from the option name.
Global session or window options are listed if
.Fl g
is used.
diff --git a/tmux.h b/tmux.h
index d7f38199..00fbc04e 100644
--- a/tmux.h
+++ b/tmux.h
@@ -235,8 +235,8 @@ enum {
/* Termcap codes. */
enum tty_code_code {
- TTYC_AX = 0,
TTYC_ACSC,
+ TTYC_AX,
TTYC_BCE,
TTYC_BEL,
TTYC_BLINK,
@@ -816,7 +816,7 @@ struct window_pane {
int argc;
char **argv;
char *shell;
- const char *cwd;
+ char *cwd;
pid_t pid;
char tty[TTY_NAME_MAX];
@@ -1563,6 +1563,32 @@ struct options_table_entry {
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
#define CMD_BUFFER_USAGE "[-b buffer-name]"
+/* Spawn common context. */
+struct spawn_context {
+ struct cmdq_item *item;
+
+ struct session *s;
+ struct winlink *wl;
+
+ struct window_pane *wp0;
+ struct layout_cell *lc;
+
+ const char *name;
+ char **argv;
+ int argc;
+
+ int idx;
+ const char *cwd;
+
+ int flags;
+#define SPAWN_KILL 0x1
+#define SPAWN_DETACHED 0x2
+#define SPAWN_RESPAWN 0x4
+#define SPAWN_BEFORE 0x8
+#define SPAWN_NONOTIFY 0x10
+#define SPAWN_FULLSIZE 0x20
+};
+
/* tmux.c */
extern struct hooks *global_hooks;
extern struct options *global_options;
@@ -1613,7 +1639,7 @@ struct paste_buffer *paste_walk(struct paste_buffer *);
struct paste_buffer *paste_get_top(const char **);
struct paste_buffer *paste_get_name(const char *);
void paste_free(struct paste_buffer *);
-void paste_add(char *, size_t);
+void paste_add(const char *, char *, size_t);
int paste_rename(const char *, const char *, char **);
int paste_set(char *, size_t, const char *, char **);
char *paste_make_sample(struct paste_buffer *);
@@ -2234,17 +2260,17 @@ struct window *window_find_by_id_str(const char *);
struct window *window_find_by_id(u_int);
void window_update_activity(struct window *);
struct window *window_create(u_int, u_int);
-struct window *window_create_spawn(const char *, int, char **, const char *,
- const char *, const char *, struct environ *,
- struct termios *, u_int, u_int, u_int, char **);
+void window_destroy(struct window *);
+void window_pane_set_event(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_pane(struct window *, struct window_pane *);
-int window_set_active_pane(struct window *, struct window_pane *);
+int window_set_active_pane(struct window *, struct window_pane *,
+ int);
void window_redraw_active_switch(struct window *,
struct window_pane *);
-struct window_pane *window_add_pane(struct window *, struct window_pane *, int,
- int, u_int);
+struct window_pane *window_add_pane(struct window *, struct window_pane *,
+ u_int, int);
void window_resize(struct window *, u_int, u_int);
int window_zoom(struct window_pane *);
int window_unzoom(struct window *);
@@ -2261,9 +2287,6 @@ void window_destroy_panes(struct window *);
struct window_pane *window_pane_find_by_id_str(const char *);
struct window_pane *window_pane_find_by_id(u_int);
int window_pane_destroy_ready(struct window_pane *);
-int window_pane_spawn(struct window_pane *, int, char **,
- const char *, const char *, const char *, struct environ *,
- struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
void window_pane_alternate_on(struct window_pane *,
struct grid_cell *, int);
@@ -2321,7 +2344,7 @@ void layout_resize_pane_to(struct window_pane *, enum layout_type,
u_int);
void layout_assign_pane(struct layout_cell *, struct window_pane *);
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
- int, int, int);
+ int, int);
void layout_close_pane(struct window_pane *);
int layout_spread_cell(struct window *, struct layout_cell *);
void layout_spread_out(struct window_pane *);
@@ -2420,10 +2443,9 @@ int session_alive(struct session *);
struct session *session_find(const char *);
struct session *session_find_by_id_str(const char *);
struct session *session_find_by_id(u_int);
-struct session *session_create(const char *, const char *, int, char **,
- const char *, const char *, struct environ *,
- struct options *, struct termios *, int, char **);
-void session_destroy(struct session *, const char *);
+struct session *session_create(const char *, const char *, const char *,
+ struct environ *, struct options *, struct termios *);
+void session_destroy(struct session *, int, const char *);
void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *);
int session_check_name(const char *);
@@ -2497,4 +2519,8 @@ void style_set(struct style *, const struct grid_cell *);
void style_copy(struct style *, struct style *);
int style_is_default(struct style *);
+/* spawn.c */
+struct winlink *spawn_window(struct spawn_context *, char **);
+struct window_pane *spawn_pane(struct spawn_context *, char **);
+
#endif /* TMUX_H */
diff --git a/tty-keys.c b/tty-keys.c
index da84077b..7557eca0 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -976,7 +976,7 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len,
/* Create a new paste buffer. */
log_debug("%s: %.*s", __func__, outlen, out);
- paste_add(out, outlen);
+ paste_add(NULL, out, outlen);
return (0);
}
diff --git a/window-buffer.c b/window-buffer.c
index 79b02e9b..07cdd80d 100644
--- a/window-buffer.c
+++ b/window-buffer.c
@@ -66,6 +66,7 @@ struct window_buffer_itemdata {
};
struct window_buffer_modedata {
+ struct cmd_find_state fs;
struct mode_tree_data *data;
char *command;
char *format;
@@ -137,6 +138,9 @@ window_buffer_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
struct paste_buffer *pb;
char *text, *cp;
struct format_tree *ft;
+ struct session *s = NULL;
+ struct winlink *wl = NULL;
+ struct window_pane *wp = NULL;
for (i = 0; i < data->item_size; i++)
window_buffer_free_item(data->item_list[i]);
@@ -167,6 +171,12 @@ window_buffer_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
break;
}
+ if (cmd_find_valid_state(&data->fs)) {
+ s = data->fs.s;
+ wl = data->fs.wl;
+ wp = data->fs.wp;
+ }
+
for (i = 0; i < data->item_size; i++) {
item = data->item_list[i];
@@ -174,6 +184,7 @@ window_buffer_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
if (pb == NULL)
continue;
ft = format_create(NULL, NULL, FORMAT_NONE, 0);
+ format_defaults(ft, NULL, s, wl, wp);
format_defaults_paste_buffer(ft, pb);
if (filter != NULL) {
@@ -253,14 +264,15 @@ window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
}
static struct screen *
-window_buffer_init(struct window_mode_entry *wme,
- __unused struct cmd_find_state *fs, struct args *args)
+window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
+ struct args *args)
{
struct window_pane *wp = wme->wp;
struct window_buffer_modedata *data;
struct screen *s;
wme->data = data = xcalloc(1, sizeof *data);
+ cmd_find_copy_state(&data->fs, fs);
if (args == NULL || !args_has(args, 'F'))
data->format = xstrdup(WINDOW_BUFFER_DEFAULT_FORMAT);
diff --git a/window-copy.c b/window-copy.c
index 062d687f..aacea5c5 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -79,11 +79,12 @@ static int window_copy_set_selection(struct window_mode_entry *, int);
static int window_copy_update_selection(struct window_mode_entry *, int);
static void window_copy_synchronize_cursor(struct window_mode_entry *);
static void *window_copy_get_selection(struct window_mode_entry *, size_t *);
-static void window_copy_copy_buffer(struct window_mode_entry *, void *,
- size_t);
+static void window_copy_copy_buffer(struct window_mode_entry *,
+ const char *, void *, size_t);
static void window_copy_copy_pipe(struct window_mode_entry *,
- struct session *, const char *);
-static void window_copy_copy_selection(struct window_mode_entry *);
+ struct session *, const char *, const char *);
+static void window_copy_copy_selection(struct window_mode_entry *,
+ const char *);
static void window_copy_append_selection(struct window_mode_entry *);
static void window_copy_clear_selection(struct window_mode_entry *);
static void window_copy_copy_line(struct window_mode_entry *, char **,
@@ -154,6 +155,22 @@ enum {
WINDOW_COPY_REL_POS_BELOW,
};
+enum window_copy_cmd_action {
+ WINDOW_COPY_CMD_NOTHING,
+ WINDOW_COPY_CMD_REDRAW,
+ WINDOW_COPY_CMD_CANCEL,
+};
+
+struct window_copy_cmd_state {
+ struct window_mode_entry *wme;
+ struct args *args;
+ struct mouse_event *m;
+
+ struct client *c;
+ struct session *s;
+ struct winlink *wl;
+};
+
/*
* Copy mode's visible screen (the "screen" field) is filled from one of two
* sources: the original contents of the pane (used when we actually enter via
@@ -565,18 +582,1076 @@ window_copy_key_table(struct window_mode_entry *wme)
return ("copy-mode");
}
+static enum window_copy_cmd_action
+window_copy_cmd_append_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+
+ if (s != NULL)
+ window_copy_append_selection(wme);
+ window_copy_clear_selection(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_append_selection_and_cancel(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+
+ if (s != NULL)
+ window_copy_append_selection(wme);
+ window_copy_clear_selection(wme);
+ return (WINDOW_COPY_CMD_CANCEL);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_back_to_indentation(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_cursor_back_to_indentation(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_begin_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct mouse_event *m = cs->m;
+ struct window_copy_mode_data *data = wme->data;
+
+ if (m != NULL) {
+ window_copy_start_drag(c, m);
+ return (WINDOW_COPY_CMD_NOTHING);
+ }
+
+ data->lineflag = LINE_SEL_NONE;
+ window_copy_start_selection(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_stop_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cursordrag = CURSORDRAG_NONE;
+ data->lineflag = LINE_SEL_NONE;
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_bottom_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cx = 0;
+ data->cy = screen_size_y(&data->screen) - 1;
+
+ window_copy_update_selection(wme, 1);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_cancel(__unused struct window_copy_cmd_state *cs)
+{
+ return (WINDOW_COPY_CMD_CANCEL);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_clear_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_clear_selection(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_end_of_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ u_int np = wme->prefix;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 2)
+ prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+
+ window_copy_start_selection(wme);
+ for (; np > 1; np--)
+ window_copy_cursor_down(wme, 0);
+ window_copy_cursor_end_of_line(wme);
+
+ if (s != NULL) {
+ window_copy_copy_selection(wme, prefix);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ u_int np = wme->prefix;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 2)
+ prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+
+ window_copy_cursor_start_of_line(wme);
+ window_copy_start_selection(wme);
+ for (; np > 1; np--)
+ window_copy_cursor_down(wme, 0);
+ window_copy_cursor_end_of_line(wme);
+
+ if (s != NULL) {
+ window_copy_copy_selection(wme, prefix);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 2)
+ prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+
+ if (s != NULL)
+ window_copy_copy_selection(wme, prefix);
+ window_copy_clear_selection(wme);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_selection_and_cancel(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 2)
+ prefix = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+
+ if (s != NULL)
+ window_copy_copy_selection(wme, prefix);
+ window_copy_clear_selection(wme);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_CANCEL);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_cursor_down(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_down(wme, 0);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_cursor_left(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_left(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_right(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_up(wme, 0);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_end_of_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_cursor_end_of_line(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--) {
+ if (window_copy_pagedown(wme, 1, data->scroll_exit))
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
+{
+
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--) {
+ if (window_copy_pagedown(wme, 1, 1))
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_halfpage_up(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_pageup1(wme, 1);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cx = 0;
+ data->cy = screen_size_y(&data->screen) - 1;
+ data->oy = 0;
+
+ window_copy_update_selection(wme, 1);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cx = 0;
+ data->cy = 0;
+ data->oy = screen_hsize(data->backing);
+
+ window_copy_update_selection(wme, 1);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_again(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ switch (data->jumptype) {
+ case WINDOW_COPY_JUMPFORWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump(wme);
+ break;
+ case WINDOW_COPY_JUMPBACKWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_back(wme);
+ break;
+ case WINDOW_COPY_JUMPTOFORWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to(wme);
+ break;
+ case WINDOW_COPY_JUMPTOBACKWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to_back(wme);
+ break;
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_reverse(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ switch (data->jumptype) {
+ case WINDOW_COPY_JUMPFORWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_back(wme);
+ break;
+ case WINDOW_COPY_JUMPBACKWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump(wme);
+ break;
+ case WINDOW_COPY_JUMPTOFORWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to_back(wme);
+ break;
+ case WINDOW_COPY_JUMPTOBACKWARD:
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to(wme);
+ break;
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cx = 0;
+ data->cy = (screen_size_y(&data->screen) - 1) / 2;
+
+ window_copy_update_selection(wme, 1);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_next_paragraph(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_next_word(wme, " ");
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_next_word_end(wme, " ");
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+ u_int np = wme->prefix;
+ const char *ws;
+
+ ws = options_get_string(s->options, "word-separators");
+ for (; np != 0; np--)
+ window_copy_cursor_next_word(wme, ws);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+ u_int np = wme->prefix;
+ const char *ws;
+
+ ws = options_get_string(s->options, "word-separators");
+ for (; np != 0; np--)
+ window_copy_cursor_next_word_end(wme, ws);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_other_end(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ if ((np % 2) != 0)
+ window_copy_other_end(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--) {
+ if (window_copy_pagedown(wme, 0, data->scroll_exit))
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--) {
+ if (window_copy_pagedown(wme, 0, 1))
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_page_up(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_pageup1(wme, 0);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_previous_paragraph(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_previous_paragraph(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_previous_word(wme, " ");
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+ u_int np = wme->prefix;
+ const char *ws;
+
+ ws = options_get_string(s->options, "word-separators");
+ for (; np != 0; np--)
+ window_copy_cursor_previous_word(wme, ws);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_rectangle_toggle(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->lineflag = LINE_SEL_NONE;
+ window_copy_rectangle_toggle(wme);
+
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_down(wme, 1);
+ if (data->scroll_exit && data->oy == 0)
+ return (WINDOW_COPY_CMD_CANCEL);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_scroll_down_and_cancel(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_down(wme, 1);
+ if (data->oy == 0)
+ return (WINDOW_COPY_CMD_CANCEL);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ u_int np = wme->prefix;
+
+ for (; np != 0; np--)
+ window_copy_cursor_up(wme, 1);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ if (data->searchtype == WINDOW_COPY_SEARCHUP) {
+ for (; np != 0; np--)
+ window_copy_search_up(wme);
+ } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
+ for (; np != 0; np--)
+ window_copy_search_down(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ if (data->searchtype == WINDOW_COPY_SEARCHUP) {
+ for (; np != 0; np--)
+ window_copy_search_down(wme);
+ } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
+ for (; np != 0; np--)
+ window_copy_search_up(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_select_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+
+ data->lineflag = LINE_SEL_LEFT_RIGHT;
+ data->rectflag = 0;
+
+ window_copy_cursor_start_of_line(wme);
+ window_copy_start_selection(wme);
+ for (; np > 1; np--)
+ window_copy_cursor_down(wme, 0);
+ window_copy_cursor_end_of_line(wme);
+
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct session *s = cs->s;
+ struct window_copy_mode_data *data = wme->data;
+ const char *ws;
+
+ data->lineflag = LINE_SEL_LEFT_RIGHT;
+ data->rectflag = 0;
+
+ ws = options_get_string(s->options, "word-separators");
+ window_copy_cursor_previous_word(wme, ws);
+ window_copy_start_selection(wme);
+ window_copy_cursor_next_word_end(wme, ws);
+
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_cursor_start_of_line(wme);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_top_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+
+ data->cx = 0;
+ data->cy = 0;
+
+ window_copy_update_selection(wme, 1);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_pipe(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ char *command = NULL;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 3)
+ prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
+
+ if (s != NULL && *cs->args->argv[1] != '\0') {
+ command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+ window_copy_copy_pipe(wme, s, prefix, command);
+ free(command);
+ }
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_pipe_and_cancel(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct client *c = cs->c;
+ struct session *s = cs->s;
+ struct winlink *wl = cs->wl;
+ struct window_pane *wp = wme->wp;
+ char *command = NULL;
+ char *prefix = NULL;
+
+ if (cs->args->argc == 3)
+ prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp);
+
+ if (s != NULL && *cs->args->argv[1] != '\0') {
+ command = format_single(NULL, cs->args->argv[1], c, s, wl, wp);
+ window_copy_copy_pipe(wme, s, prefix, command);
+ free(command);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_CANCEL);
+ }
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_goto_line(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0')
+ window_copy_goto_line(wme, argument);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->jumptype = WINDOW_COPY_JUMPBACKWARD;
+ data->jumpchar = *argument;
+ for (; np != 0; np--)
+ window_copy_cursor_jump_back(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->jumptype = WINDOW_COPY_JUMPFORWARD;
+ data->jumpchar = *argument;
+ for (; np != 0; np--)
+ window_copy_cursor_jump(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
+ data->jumpchar = *argument;
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to_back(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
+ data->jumpchar = *argument;
+ for (; np != 0; np--)
+ window_copy_cursor_jump_to(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->searchtype = WINDOW_COPY_SEARCHUP;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ for (; np != 0; np--)
+ window_copy_search_up(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ u_int np = wme->prefix;
+ const char *argument = cs->args->argv[1];
+
+ if (*argument != '\0') {
+ data->searchtype = WINDOW_COPY_SEARCHDOWN;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ for (; np != 0; np--)
+ window_copy_search_down(wme);
+ }
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ const char *argument = cs->args->argv[1];
+ enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
+ const char *ss = data->searchstr;
+
+ if (data->searchx == -1 || data->searchy == -1) {
+ data->searchx = data->cx;
+ data->searchy = data->cy;
+ data->searcho = data->oy;
+ } else if (ss != NULL && strcmp(argument, ss) != 0) {
+ data->cx = data->searchx;
+ data->cy = data->searchy;
+ data->oy = data->searcho;
+ action = WINDOW_COPY_CMD_REDRAW;
+ }
+
+ if (*argument == '\0') {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+
+ switch (*argument++) {
+ case '=':
+ case '-':
+ data->searchtype = WINDOW_COPY_SEARCHUP;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ if (!window_copy_search_up(wme)) {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+ break;
+ case '+':
+ data->searchtype = WINDOW_COPY_SEARCHDOWN;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ if (!window_copy_search_down(wme)) {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+ break;
+ }
+ return (action);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+ struct window_copy_mode_data *data = wme->data;
+ const char *argument = cs->args->argv[1];
+ enum window_copy_cmd_action action = WINDOW_COPY_CMD_NOTHING;
+ const char *ss = data->searchstr;
+
+ if (data->searchx == -1 || data->searchy == -1) {
+ data->searchx = data->cx;
+ data->searchy = data->cy;
+ data->searcho = data->oy;
+ } else if (ss != NULL && strcmp(argument, ss) != 0) {
+ data->cx = data->searchx;
+ data->cy = data->searchy;
+ data->oy = data->searcho;
+ action = WINDOW_COPY_CMD_REDRAW;
+ }
+
+ if (*argument == '\0') {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+
+ switch (*argument++) {
+ case '=':
+ case '+':
+ data->searchtype = WINDOW_COPY_SEARCHDOWN;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ if (!window_copy_search_down(wme)) {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+ break;
+ case '-':
+ data->searchtype = WINDOW_COPY_SEARCHUP;
+ free(data->searchstr);
+ data->searchstr = xstrdup(argument);
+ if (!window_copy_search_up(wme)) {
+ window_copy_clear_marks(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+ }
+ }
+ return (action);
+}
+
+static const struct {
+ const char *command;
+ int minargs;
+ int maxargs;
+ enum window_copy_cmd_action (*f)(struct window_copy_cmd_state *);
+} window_copy_cmd_table[] = {
+ { "append-selection", 0, 0,
+ window_copy_cmd_append_selection },
+ { "append-selection-and-cancel", 0, 0,
+ window_copy_cmd_append_selection_and_cancel },
+ { "back-to-indentation", 0, 0,
+ window_copy_cmd_back_to_indentation },
+ { "begin-selection", 0, 0,
+ window_copy_cmd_begin_selection },
+ { "bottom-line", 0, 0,
+ window_copy_cmd_bottom_line },
+ { "cancel", 0, 0,
+ window_copy_cmd_cancel },
+ { "clear-selection", 0, 0,
+ window_copy_cmd_clear_selection },
+ { "copy-end-of-line", 0, 1,
+ window_copy_cmd_copy_end_of_line },
+ { "copy-line", 0, 1,
+ window_copy_cmd_copy_line },
+ { "copy-pipe", 1, 2,
+ window_copy_cmd_copy_pipe },
+ { "copy-pipe-and-cancel", 1, 2,
+ window_copy_cmd_copy_pipe_and_cancel },
+ { "copy-selection", 0, 1,
+ window_copy_cmd_copy_selection },
+ { "copy-selection-and-cancel", 0, 1,
+ window_copy_cmd_copy_selection_and_cancel },
+ { "cursor-down", 0, 0,
+ window_copy_cmd_cursor_down },
+ { "cursor-left", 0, 0,
+ window_copy_cmd_cursor_left },
+ { "cursor-right", 0, 0,
+ window_copy_cmd_cursor_right },
+ { "cursor-up", 0, 0,
+ window_copy_cmd_cursor_up },
+ { "end-of-line", 0, 0,
+ window_copy_cmd_end_of_line },
+ { "goto-line", 1, 1,
+ window_copy_cmd_goto_line },
+ { "halfpage-down", 0, 0,
+ window_copy_cmd_halfpage_down },
+ { "halfpage-down-and-cancel", 0, 0,
+ window_copy_cmd_halfpage_down_and_cancel },
+ { "halfpage-up", 0, 0,
+ window_copy_cmd_halfpage_up },
+ { "history-bottom", 0, 0,
+ window_copy_cmd_history_bottom },
+ { "history-top", 0, 0,
+ window_copy_cmd_history_top },
+ { "jump-again", 0, 0,
+ window_copy_cmd_jump_again },
+ { "jump-backward", 1, 1,
+ window_copy_cmd_jump_backward },
+ { "jump-forward", 1, 1,
+ window_copy_cmd_jump_forward },
+ { "jump-reverse", 0, 0,
+ window_copy_cmd_jump_reverse },
+ { "jump-to-backward", 1, 1,
+ window_copy_cmd_jump_to_backward },
+ { "jump-to-forward", 1, 1,
+ window_copy_cmd_jump_to_forward },
+ { "middle-line", 0, 0,
+ window_copy_cmd_middle_line },
+ { "next-paragraph", 0, 0,
+ window_copy_cmd_next_paragraph },
+ { "next-space", 0, 0,
+ window_copy_cmd_next_space },
+ { "next-space-end", 0, 0,
+ window_copy_cmd_next_space_end },
+ { "next-word", 0, 0,
+ window_copy_cmd_next_word },
+ { "next-word-end", 0, 0,
+ window_copy_cmd_next_word_end },
+ { "other-end", 0, 0,
+ window_copy_cmd_other_end },
+ { "page-down", 0, 0,
+ window_copy_cmd_page_down },
+ { "page-down-and-cancel", 0, 0,
+ window_copy_cmd_page_down_and_cancel },
+ { "page-up", 0, 0,
+ window_copy_cmd_page_up },
+ { "previous-paragraph", 0, 0,
+ window_copy_cmd_previous_paragraph },
+ { "previous-space", 0, 0,
+ window_copy_cmd_previous_space },
+ { "previous-word", 0, 0,
+ window_copy_cmd_previous_word },
+ { "rectangle-toggle", 0, 0,
+ window_copy_cmd_rectangle_toggle },
+ { "scroll-down", 0, 0,
+ window_copy_cmd_scroll_down },
+ { "scroll-down-and-cancel", 0, 0,
+ window_copy_cmd_scroll_down_and_cancel },
+ { "scroll-up", 0, 0,
+ window_copy_cmd_scroll_up },
+ { "search-again", 0, 0,
+ window_copy_cmd_search_again },
+ { "search-backward", 1, 1,
+ window_copy_cmd_search_backward },
+ { "search-backward-incremental", 1, 1,
+ window_copy_cmd_search_backward_incremental },
+ { "search-forward", 1, 1,
+ window_copy_cmd_search_forward },
+ { "search-forward-incremental", 1, 1,
+ window_copy_cmd_search_forward_incremental },
+ { "search-reverse", 0, 0,
+ window_copy_cmd_search_reverse },
+ { "select-line", 0, 0,
+ window_copy_cmd_select_line },
+ { "select-word", 0, 0,
+ window_copy_cmd_select_word },
+ { "start-of-line", 0, 0,
+ window_copy_cmd_start_of_line },
+ { "stop-selection", 0, 0,
+ window_copy_cmd_stop_selection },
+ { "top-line", 0, 0,
+ window_copy_cmd_top_line },
+};
+
static void
window_copy_command(struct window_mode_entry *wme, struct client *c,
- struct session *s, __unused struct winlink *wl, struct args *args,
+ struct session *s, struct winlink *wl, struct args *args,
struct mouse_event *m)
{
- struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
- struct screen *sn = &data->screen;
- const char *command, *argument, *ws;
- u_int np = wme->prefix;
- int cancel = 0, redraw = 0, scroll_exit;
- char prefix;
+ struct window_copy_cmd_state cs;
+ enum window_copy_cmd_action action;
+ const char *command;
+ u_int i;
if (args->argc == 0)
return;
@@ -585,431 +1660,36 @@ window_copy_command(struct window_mode_entry *wme, struct client *c,
if (m != NULL && m->valid && !MOUSE_WHEEL(m->b))
window_copy_move_mouse(m);
- if (args->argc == 1) {
- if (strcmp(command, "append-selection") == 0) {
- if (s != NULL)
- window_copy_append_selection(wme);
- window_copy_clear_selection(wme);
- redraw = 1;
- }
- if (strcmp(command, "append-selection-and-cancel") == 0) {
- if (s != NULL)
- window_copy_append_selection(wme);
- window_copy_clear_selection(wme);
- redraw = 1;
- cancel = 1;
- }
- if (strcmp(command, "back-to-indentation") == 0)
- window_copy_cursor_back_to_indentation(wme);
- if (strcmp(command, "begin-selection") == 0) {
- if (m != NULL)
- window_copy_start_drag(c, m);
- else {
- data->lineflag = LINE_SEL_NONE;
- window_copy_start_selection(wme);
- redraw = 1;
- }
- }
- if (strcmp(command, "stop-selection") == 0)
- data->cursordrag = CURSORDRAG_NONE;
- if (strcmp(command, "bottom-line") == 0) {
- data->cx = 0;
- data->cy = screen_size_y(sn) - 1;
- window_copy_update_selection(wme, 1);
- redraw = 1;
- }
- if (strcmp(command, "cancel") == 0)
- cancel = 1;
- if (strcmp(command, "clear-selection") == 0) {
- window_copy_clear_selection(wme);
- redraw = 1;
- }
- if (strcmp(command, "copy-end-of-line") == 0) {
- window_copy_start_selection(wme);
- for (; np > 1; np--)
- window_copy_cursor_down(wme, 0);
- window_copy_cursor_end_of_line(wme);
- redraw = 1;
+ cs.wme = wme;
+ cs.args = args;
+ cs.m = m;
- if (s != NULL) {
- window_copy_copy_selection(wme);
- cancel = 1;
- }
- }
- if (strcmp(command, "copy-line") == 0) {
- window_copy_cursor_start_of_line(wme);
- window_copy_start_selection(wme);
- for (; np > 1; np--)
- window_copy_cursor_down(wme, 0);
- window_copy_cursor_end_of_line(wme);
- redraw = 1;
+ cs.c = c;
+ cs.s = s;
+ cs.wl = wl;
- if (s != NULL) {
- window_copy_copy_selection(wme);
- cancel = 1;
- }
- }
- if (strcmp(command, "copy-selection") == 0) {
- if (s != NULL)
- window_copy_copy_selection(wme);
- window_copy_clear_selection(wme);
- redraw = 1;
- }
- if (strcmp(command, "copy-selection-and-cancel") == 0) {
- if (s != NULL)
- window_copy_copy_selection(wme);
- window_copy_clear_selection(wme);
- redraw = 1;
- cancel = 1;
- }
- if (strcmp(command, "cursor-down") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_down(wme, 0);
- }
- if (strcmp(command, "cursor-left") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_left(wme);
- }
- if (strcmp(command, "cursor-right") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_right(wme);
- }
- if (strcmp(command, "cursor-up") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_up(wme, 0);
- }
- if (strcmp(command, "end-of-line") == 0)
- window_copy_cursor_end_of_line(wme);
- if (strcmp(command, "halfpage-down") == 0 ||
- strcmp(command, "halfpage-down-and-cancel") == 0) {
- if (strcmp(command, "halfpage-down-and-cancel") == 0)
- scroll_exit = 1;
- else
- scroll_exit = data->scroll_exit;
- for (; np != 0; np--) {
- if (window_copy_pagedown(wme, 1, scroll_exit)) {
- cancel = 1;
- break;
- }
- }
- }
- if (strcmp(command, "halfpage-up") == 0) {
- for (; np != 0; np--)
- window_copy_pageup1(wme, 1);
- }
- if (strcmp(command, "history-bottom") == 0) {
- data->cx = 0;
- data->cy = screen_size_y(sn) - 1;
- data->oy = 0;
- window_copy_update_selection(wme, 1);
- redraw = 1;
- }
- if (strcmp(command, "history-top") == 0) {
- data->cx = 0;
- data->cy = 0;
- data->oy = screen_hsize(data->backing);
- window_copy_update_selection(wme, 1);
- redraw = 1;
- }
- if (strcmp(command, "jump-again") == 0) {
- switch (data->jumptype) {
- case WINDOW_COPY_JUMPFORWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump(wme);
- break;
- case WINDOW_COPY_JUMPBACKWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_back(wme);
+ action = WINDOW_COPY_CMD_NOTHING;
+ for (i = 0; i < nitems(window_copy_cmd_table); i++) {
+ if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
+ if (args->argc - 1 < window_copy_cmd_table[i].minargs ||
+ args->argc - 1 > window_copy_cmd_table[i].maxargs)
break;
- case WINDOW_COPY_JUMPTOFORWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_to(wme);
- break;
- case WINDOW_COPY_JUMPTOBACKWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_to_back(wme);
- break;
- }
- }
- if (strcmp(command, "jump-reverse") == 0) {
- switch (data->jumptype) {
- case WINDOW_COPY_JUMPFORWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_back(wme);
- break;
- case WINDOW_COPY_JUMPBACKWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump(wme);
- break;
- case WINDOW_COPY_JUMPTOFORWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_to_back(wme);
- break;
- case WINDOW_COPY_JUMPTOBACKWARD:
- for (; np != 0; np--)
- window_copy_cursor_jump_to(wme);
- break;
- }
- }
- if (strcmp(command, "middle-line") == 0) {
- data->cx = 0;
- data->cy = (screen_size_y(sn) - 1) / 2;
- window_copy_update_selection(wme, 1);
- redraw = 1;
- }
- if (strcmp(command, "next-paragraph") == 0) {
- for (; np != 0; np--)
- window_copy_next_paragraph(wme);
- }
- if (strcmp(command, "next-space") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_next_word(wme, " ");
- }
- if (strcmp(command, "next-space-end") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_next_word_end(wme, " ");
- }
- if (strcmp(command, "next-word") == 0) {
- ws = options_get_string(s->options, "word-separators");
- for (; np != 0; np--)
- window_copy_cursor_next_word(wme, ws);
- }
- if (strcmp(command, "next-word-end") == 0) {
- ws = options_get_string(s->options, "word-separators");
- for (; np != 0; np--)
- window_copy_cursor_next_word_end(wme, ws);
- }
- if (strcmp(command, "other-end") == 0) {
- if ((np % 2) != 0)
- window_copy_other_end(wme);
- }
- if (strcmp(command, "page-down") == 0 ||
- strcmp(command, "page-down-and-cancel") == 0) {
- if (strcmp(command, "page-down-and-cancel") == 0)
- scroll_exit = 1;
- else
- scroll_exit = data->scroll_exit;
- for (; np != 0; np--) {
- if (window_copy_pagedown(wme, 0, scroll_exit)) {
- cancel = 1;
- break;
- }
- }
- }
- if (strcmp(command, "page-up") == 0) {
- for (; np != 0; np--)
- window_copy_pageup1(wme, 0);
- }
- if (strcmp(command, "previous-paragraph") == 0) {
- for (; np != 0; np--)
- window_copy_previous_paragraph(wme);
- }
- if (strcmp(command, "previous-space") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_previous_word(wme, " ");
- }
- if (strcmp(command, "previous-word") == 0) {
- ws = options_get_string(s->options, "word-separators");
- for (; np != 0; np--)
- window_copy_cursor_previous_word(wme, ws);
- }
- if (strcmp(command, "rectangle-toggle") == 0) {
- data->lineflag = LINE_SEL_NONE;
- window_copy_rectangle_toggle(wme);
- }
- if (strcmp(command, "scroll-down") == 0 ||
- strcmp(command, "scroll-down-and-cancel") == 0) {
- if (strcmp(command, "scroll-down-and-cancel") == 0)
- scroll_exit = 1;
- else
- scroll_exit = data->scroll_exit;
- for (; np != 0; np--)
- window_copy_cursor_down(wme, 1);
- if (scroll_exit && data->oy == 0)
- cancel = 1;
- }
- if (strcmp(command, "scroll-up") == 0) {
- for (; np != 0; np--)
- window_copy_cursor_up(wme, 1);
- }
- if (strcmp(command, "search-again") == 0) {
- if (data->searchtype == WINDOW_COPY_SEARCHUP) {
- for (; np != 0; np--)
- window_copy_search_up(wme);
- } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
- for (; np != 0; np--)
- window_copy_search_down(wme);
- }
- }
- if (strcmp(command, "search-reverse") == 0) {
- if (data->searchtype == WINDOW_COPY_SEARCHUP) {
- for (; np != 0; np--)
- window_copy_search_down(wme);
- } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
- for (; np != 0; np--)
- window_copy_search_up(wme);
- }
- }
- if (strcmp(command, "select-line") == 0) {
- data->lineflag = LINE_SEL_LEFT_RIGHT;
- data->rectflag = 0;
- window_copy_cursor_start_of_line(wme);
- window_copy_start_selection(wme);
- for (; np > 1; np--)
- window_copy_cursor_down(wme, 0);
- window_copy_cursor_end_of_line(wme);
- redraw = 1;
- }
- if (strcmp(command, "select-word") == 0) {
- data->lineflag = LINE_SEL_LEFT_RIGHT;
- data->rectflag = 0;
- ws = options_get_string(s->options, "word-separators");
- window_copy_cursor_previous_word(wme, ws);
- window_copy_start_selection(wme);
- window_copy_cursor_next_word_end(wme, ws);
- redraw = 1;
- }
- if (strcmp(command, "start-of-line") == 0)
- window_copy_cursor_start_of_line(wme);
- if (strcmp(command, "top-line") == 0) {
- data->cx = 0;
- data->cy = 0;
- window_copy_update_selection(wme, 1);
- redraw = 1;
- }
- } else if (args->argc == 2 && *args->argv[1] != '\0') {
- argument = args->argv[1];
- if (strcmp(command, "copy-pipe") == 0) {
- if (s != NULL)
- window_copy_copy_pipe(wme, s, argument);
- }
- if (strcmp(command, "copy-pipe-and-cancel") == 0) {
- if (s != NULL) {
- window_copy_copy_pipe(wme, s, argument);
- cancel = 1;
- }
- }
- if (strcmp(command, "goto-line") == 0)
- window_copy_goto_line(wme, argument);
- if (strcmp(command, "jump-backward") == 0) {
- data->jumptype = WINDOW_COPY_JUMPBACKWARD;
- data->jumpchar = *argument;
- for (; np != 0; np--)
- window_copy_cursor_jump_back(wme);
- }
- if (strcmp(command, "jump-forward") == 0) {
- data->jumptype = WINDOW_COPY_JUMPFORWARD;
- data->jumpchar = *argument;
- for (; np != 0; np--)
- window_copy_cursor_jump(wme);
- }
- if (strcmp(command, "jump-to-backward") == 0) {
- data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
- data->jumpchar = *argument;
- for (; np != 0; np--)
- window_copy_cursor_jump_to_back(wme);
- }
- if (strcmp(command, "jump-to-forward") == 0) {
- data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
- data->jumpchar = *argument;
- for (; np != 0; np--)
- window_copy_cursor_jump_to(wme);
- }
- if (strcmp(command, "search-backward") == 0) {
- data->searchtype = WINDOW_COPY_SEARCHUP;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- for (; np != 0; np--)
- window_copy_search_up(wme);
- }
- if (strcmp(command, "search-forward") == 0) {
- data->searchtype = WINDOW_COPY_SEARCHDOWN;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- for (; np != 0; np--)
- window_copy_search_down(wme);
- }
- if (strcmp(command, "search-backward-incremental") == 0) {
- prefix = *argument++;
- if (data->searchx == -1 || data->searchy == -1) {
- data->searchx = data->cx;
- data->searchy = data->cy;
- data->searcho = data->oy;
- } else if (data->searchstr != NULL &&
- strcmp(argument, data->searchstr) != 0) {
- data->cx = data->searchx;
- data->cy = data->searchy;
- data->oy = data->searcho;
- redraw = 1;
- }
- if (*argument == '\0') {
- window_copy_clear_marks(wme);
- redraw = 1;
- } else if (prefix == '=' || prefix == '-') {
- data->searchtype = WINDOW_COPY_SEARCHUP;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme)) {
- window_copy_clear_marks(wme);
- redraw = 1;
- }
- } else if (prefix == '+') {
- data->searchtype = WINDOW_COPY_SEARCHDOWN;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme)) {
- window_copy_clear_marks(wme);
- redraw = 1;
- }
- }
- }
- if (strcmp(command, "search-forward-incremental") == 0) {
- prefix = *argument++;
- if (data->searchx == -1 || data->searchy == -1) {
- data->searchx = data->cx;
- data->searchy = data->cy;
- data->searcho = data->oy;
- } else if (data->searchstr != NULL &&
- strcmp(argument, data->searchstr) != 0) {
- data->cx = data->searchx;
- data->cy = data->searchy;
- data->oy = data->searcho;
- redraw = 1;
- }
- if (*argument == '\0') {
- window_copy_clear_marks(wme);
- redraw = 1;
- } else if (prefix == '=' || prefix == '+') {
- data->searchtype = WINDOW_COPY_SEARCHDOWN;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme)) {
- window_copy_clear_marks(wme);
- redraw = 1;
- }
- } else if (prefix == '-') {
- data->searchtype = WINDOW_COPY_SEARCHUP;
- free(data->searchstr);
- data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme)) {
- window_copy_clear_marks(wme);
- redraw = 1;
- }
- }
+ action = window_copy_cmd_table[i].f (&cs);
+ break;
}
}
if (strncmp(command, "search-", 7) != 0 && data->searchmark != NULL) {
window_copy_clear_marks(wme);
- redraw = 1;
+ if (action == WINDOW_COPY_CMD_NOTHING)
+ action = WINDOW_COPY_CMD_REDRAW;
data->searchx = data->searchy = -1;
}
-
wme->prefix = 1;
- if (cancel)
- window_pane_reset_mode(wp);
- else if (redraw)
+ if (action == WINDOW_COPY_CMD_CANCEL)
+ window_pane_reset_mode(wme->wp);
+ else if (action == WINDOW_COPY_CMD_REDRAW)
window_copy_redraw_screen(wme);
}
@@ -1721,7 +2401,8 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
}
static void
-window_copy_copy_buffer(struct window_mode_entry *wme, void *buf, size_t len)
+window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
+ void *buf, size_t len)
{
struct window_pane *wp = wme->wp;
struct screen_write_ctx ctx;
@@ -1733,41 +2414,35 @@ window_copy_copy_buffer(struct window_mode_entry *wme, void *buf, size_t len)
notify_pane("pane-set-clipboard", wp);
}
- if (paste_set(buf, len, NULL, NULL) != 0)
- free(buf);
+ paste_add(prefix, buf, len);
}
static void
window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
- const char *fmt)
+ const char *prefix, const char *command)
{
- struct window_pane *wp = wme->wp;
- void *buf;
- size_t len;
- struct job *job;
- char *expanded;
+ void *buf;
+ size_t len;
+ struct job *job;
buf = window_copy_get_selection(wme, &len);
if (buf == NULL)
return;
- expanded = format_single(NULL, fmt, NULL, s, NULL, wp);
- job = job_run(expanded, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
+ job = job_run(command, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
bufferevent_write(job_get_event(job), buf, len);
-
- free(expanded);
- window_copy_copy_buffer(wme, buf, len);
+ window_copy_copy_buffer(wme, prefix, buf, len);
}
static void
-window_copy_copy_selection(struct window_mode_entry *wme)
+window_copy_copy_selection(struct window_mode_entry *wme, const char *prefix)
{
char *buf;
size_t len;
buf = window_copy_get_selection(wme, &len);
if (buf != NULL)
- window_copy_copy_buffer(wme, buf, len);
+ window_copy_copy_buffer(wme, prefix, buf, len);
}
static void
diff --git a/window-tree.c b/window-tree.c
index 55dda694..4d73aeab 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -1006,7 +1006,7 @@ window_tree_kill_each(__unused void* modedata, void* itemdata,
case WINDOW_TREE_SESSION:
if (s != NULL) {
server_destroy_session(s);
- session_destroy(s, __func__);
+ session_destroy(s, 1, __func__);
}
break;
case WINDOW_TREE_WINDOW:
diff --git a/window.c b/window.c
index 4ed766ad..3c4a8c29 100644
--- a/window.c
+++ b/window.c
@@ -26,7 +26,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <termios.h>
#include <time.h>
#include <unistd.h>
@@ -71,20 +70,10 @@ const struct window_mode *all_window_modes[] = {
NULL
};
-static void window_destroy(struct window *);
-
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
u_int);
static void window_pane_destroy(struct window_pane *);
-static void window_pane_read_callback(struct bufferevent *, void *);
-static void window_pane_error_callback(struct bufferevent *, short, void *);
-
-static int winlink_next_index(struct winlinks *, int);
-
-static struct window_pane *window_pane_choose_best(struct window_pane **,
- u_int);
-
RB_GENERATE(windows, window, entry, window_cmp);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
@@ -340,37 +329,7 @@ window_create(u_int sx, u_int sy)
return (w);
}
-struct window *
-window_create_spawn(const char *name, int argc, char **argv, const char *path,
- const char *shell, const char *cwd, struct environ *env,
- struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause)
-{
- struct window *w;
- struct window_pane *wp;
-
- w = window_create(sx, sy);
- wp = window_add_pane(w, NULL, 0, 0, hlimit);
- layout_init(w, wp);
-
- if (window_pane_spawn(wp, argc, argv, path, shell, cwd,
- env, tio, cause) != 0) {
- window_destroy(w);
- return (NULL);
- }
-
- w->active = TAILQ_FIRST(&w->panes);
- if (name != NULL) {
- w->name = xstrdup(name);
- options_set_number(w->options, "automatic-rename", 0);
- } else
- w->name = default_window_name(w);
-
- notify_window("window-pane-changed", w);
-
- return (w);
-}
-
-static void
+void
window_destroy(struct window *w)
{
log_debug("window @%u destroyed (%d references)", w->id, w->references);
@@ -461,17 +420,22 @@ window_has_pane(struct window *w, struct window_pane *wp)
}
int
-window_set_active_pane(struct window *w, struct window_pane *wp)
+window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
{
- log_debug("%s: pane %%%u (was %%%u)", __func__, wp->id, w->active->id);
+ log_debug("%s: pane %%%u", __func__, wp->id);
+
if (wp == w->active)
return (0);
w->last = w->active;
+
w->active = wp;
w->active->active_point = next_active_point++;
w->active->flags |= PANE_CHANGED;
+
tty_update_window_offset(w);
- notify_window("window-pane-changed", w);
+
+ if (notify)
+ notify_window("window-pane-changed", w);
return (1);
}
@@ -569,7 +533,7 @@ window_zoom(struct window_pane *wp)
return (-1);
if (w->active != wp)
- window_set_active_pane(w, wp);
+ window_set_active_pane(w, wp, 1);
TAILQ_FOREACH(wp1, &w->panes, entry) {
wp1->saved_layout_cell = wp1->layout_cell;
@@ -608,8 +572,8 @@ window_unzoom(struct window *w)
}
struct window_pane *
-window_add_pane(struct window *w, struct window_pane *other, int before,
- int full_size, u_int hlimit)
+window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
+ int flags)
{
struct window_pane *wp;
@@ -620,15 +584,15 @@ window_add_pane(struct window *w, struct window_pane *other, int before,
if (TAILQ_EMPTY(&w->panes)) {
log_debug("%s: @%u at start", __func__, w->id);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
- } else if (before) {
+ } else if (flags & SPAWN_BEFORE) {
log_debug("%s: @%u before %%%u", __func__, w->id, wp->id);
- if (full_size)
+ if (flags & SPAWN_FULLSIZE)
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
else
TAILQ_INSERT_BEFORE(other, wp, entry);
} else {
log_debug("%s: @%u after %%%u", __func__, w->id, wp->id);
- if (full_size)
+ if (flags & SPAWN_FULLSIZE)
TAILQ_INSERT_TAIL(&w->panes, wp, entry);
else
TAILQ_INSERT_AFTER(&w->panes, other, wp, entry);
@@ -888,153 +852,6 @@ window_pane_destroy(struct window_pane *wp)
free(wp);
}
-int
-window_pane_spawn(struct window_pane *wp, int argc, char **argv,
- const char *path, const char *shell, const char *cwd, struct environ *env,
- struct termios *tio, char **cause)
-{
- struct winsize ws;
- char *argv0, *cmd, **argvp;
- const char *ptr, *first, *home;
- struct termios tio2;
-#ifdef HAVE_UTEMPTER
- char s[32];
-#endif
- sigset_t set, oldset;
-
- if (wp->fd != -1) {
- bufferevent_free(wp->event);
- close(wp->fd);
- }
- if (argc > 0) {
- cmd_free_argv(wp->argc, wp->argv);
- wp->argc = argc;
- wp->argv = cmd_copy_argv(argc, argv);
- }
- if (shell != NULL) {
- free(wp->shell);
- wp->shell = xstrdup(shell);
- }
- if (cwd != NULL) {
- free((void *)wp->cwd);
- wp->cwd = xstrdup(cwd);
- }
- wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN);
-
- cmd = cmd_stringify_argv(wp->argc, wp->argv);
- log_debug("%s: shell=%s", __func__, wp->shell);
- log_debug("%s: cmd=%s", __func__, cmd);
- log_debug("%s: cwd=%s", __func__, cwd);
- cmd_log_argv(wp->argc, wp->argv, __func__);
- environ_log(env, "%s: environment ", __func__);
-
- memset(&ws, 0, sizeof ws);
- ws.ws_col = screen_size_x(&wp->base);
- ws.ws_row = screen_size_y(&wp->base);
-
- sigfillset(&set);
- sigprocmask(SIG_BLOCK, &set, &oldset);
- switch (wp->pid = fdforkpty(ptm_fd, &wp->fd, wp->tty, NULL, &ws)) {
- case -1:
- wp->event = NULL;
- wp->fd = -1;
-
- xasprintf(cause, "%s: %s", cmd, strerror(errno));
- free(cmd);
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- return (-1);
- case 0:
- proc_clear_signals(server_proc, 1);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
-
- cwd = NULL;
- if (chdir(wp->cwd) == 0)
- cwd = wp->cwd;
- else if ((home = find_home()) != NULL && chdir(home) == 0)
- cwd = home;
- else
- chdir("/");
-
- if (tcgetattr(STDIN_FILENO, &tio2) != 0)
- fatal("tcgetattr failed");
- if (tio != NULL)
- memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
- tio2.c_cc[VERASE] = '\177';
-#ifdef IUTF8
- tio2.c_iflag |= IUTF8;
-#endif
- if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
- fatal("tcgetattr failed");
-
- log_close();
- closefrom(STDERR_FILENO + 1);
-
- if (path != NULL)
- environ_set(env, "PATH", "%s", path);
- if (cwd != NULL)
- environ_set(env, "PWD", "%s", cwd);
- environ_set(env, "TMUX_PANE", "%%%u", wp->id);
- environ_push(env);
-
- setenv("SHELL", wp->shell, 1);
- ptr = strrchr(wp->shell, '/');
-
- /*
- * If given one argument, assume it should be passed to sh -c;
- * with more than one argument, use execvp(). If there is no
- * arguments, create a login shell.
- */
- if (wp->argc > 0) {
- if (wp->argc != 1) {
- /* Copy to ensure argv ends in NULL. */
- argvp = cmd_copy_argv(wp->argc, wp->argv);
- execvp(argvp[0], argvp);
- fatal("execvp failed");
- }
- first = wp->argv[0];
-
- if (ptr != NULL && *(ptr + 1) != '\0')
- xasprintf(&argv0, "%s", ptr + 1);
- else
- xasprintf(&argv0, "%s", wp->shell);
- execl(wp->shell, argv0, "-c", first, (char *)NULL);
- fatal("execl failed");
- }
- if (ptr != NULL && *(ptr + 1) != '\0')
- xasprintf(&argv0, "-%s", ptr + 1);
- else
- xasprintf(&argv0, "-%s", wp->shell);
- execl(wp->shell, argv0, (char *)NULL);
- fatal("execl failed");
- }
- log_debug("%s: master=%s", __func__, ttyname(wp->fd));
- log_debug("%s: slave=%s", __func__, wp->tty);
-
-#ifdef HAVE_UTEMPTER
- xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id);
- utempter_add_record(wp->fd, s);
- kill(getpid(), SIGCHLD);
-#endif
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- setblocking(wp->fd, 0);
-
- wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
- window_pane_error_callback, wp);
- if (wp->event == NULL)
- fatalx("out of memory");
-
- wp->pipe_off = 0;
- wp->flags &= ~PANE_EXITED;
-
- bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
- bufferevent_enable(wp->event, EV_READ|EV_WRITE);
-
- free(cmd);
- return (0);
-}
-
static void
window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{
@@ -1070,6 +887,18 @@ window_pane_error_callback(__unused struct bufferevent *bufev,
}
void
+window_pane_set_event(struct window_pane *wp)
+{
+ setblocking(wp->fd, 0);
+
+ wp->event = bufferevent_new(wp->fd, window_pane_read_callback,
+ NULL, window_pane_error_callback, wp);
+
+ bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE);
+ bufferevent_enable(wp->event, EV_READ|EV_WRITE);
+}
+
+void
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
@@ -1617,6 +1446,8 @@ winlink_shuffle_up(struct session *s, struct winlink *wl)
{
int idx, last;
+ if (wl == NULL)
+ return (-1);
idx = wl->idx + 1;
/* Find the next free index. */