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-set-option.c2
-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--cmd.c19
-rw-r--r--compat.h1
-rw-r--r--configure.ac2
-rw-r--r--environ.c10
-rw-r--r--format.c17
-rw-r--r--input.c2
-rw-r--r--layout.c20
-rw-r--r--options-table.c15
-rw-r--r--options.c209
-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--status.c16
-rw-r--r--style.c2
-rw-r--r--tmux.151
-rw-r--r--tmux.h79
-rw-r--r--tty-keys.c11
-rw-r--r--tty-term.c7
-rw-r--r--tty.c8
-rw-r--r--window-buffer.c16
-rw-r--r--window-copy.c1550
-rw-r--r--window-tree.c2
-rw-r--r--window.c227
48 files changed, 2215 insertions, 1290 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-set-option.c b/cmd-set-option.c
index 96428d73..edeb8385 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -366,8 +366,6 @@ cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
return (-1);
}
return (0);
- case OPTIONS_TABLE_ARRAY:
- break;
}
return (-1);
}
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/cmd.c b/cmd.c
index 877cd10c..82dcae3d 100644
--- a/cmd.c
+++ b/cmd.c
@@ -320,10 +320,11 @@ cmd_try_alias(int *argc, char ***argv)
{
struct options_entry *o;
struct options_array_item *a;
+ union options_value *ov;
int old_argc = *argc, new_argc, i;
char **old_argv = *argv, **new_argv;
size_t wanted;
- const char *s, *cp = NULL;
+ const char *cp = NULL;
o = options_get_only(global_options, "command-alias");
if (o == NULL)
@@ -332,14 +333,16 @@ cmd_try_alias(int *argc, char ***argv)
a = options_array_first(o);
while (a != NULL) {
- s = options_array_item_value(a);
- if (s != NULL) {
- cp = strchr(s, '=');
- if (cp != NULL &&
- (size_t)(cp - s) == wanted &&
- strncmp(old_argv[0], s, wanted) == 0)
- break;
+ ov = options_array_item_value(a);
+ if (ov == NULL) {
+ a = options_array_next(a);
+ continue;
}
+ cp = strchr(ov->string, '=');
+ if (cp != NULL &&
+ (size_t)(cp - ov->string) == wanted &&
+ strncmp(old_argv[0], ov->string, wanted) == 0)
+ break;
a = options_array_next(a);
}
if (a == NULL)
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 89e62066..1e7578ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 2.9)
+AC_INIT([tmux], next-3.0)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
diff --git a/environ.c b/environ.c
index 2764e027..301c4f29 100644
--- a/environ.c
+++ b/environ.c
@@ -177,20 +177,20 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
struct environ_entry *envent;
struct options_entry *o;
struct options_array_item *a;
- const char *value;
+ union options_value *ov;
o = options_get(oo, "update-environment");
if (o == NULL)
return;
a = options_array_first(o);
while (a != NULL) {
- value = options_array_item_value(a);
- if (value == NULL) {
+ ov = options_array_item_value(a);
+ if (ov == NULL) {
a = options_array_next(a);
continue;
}
- if ((envent = environ_find(src, value)) == NULL)
- environ_clear(dst, value);
+ if ((envent = environ_find(src, ov->string)) == NULL)
+ environ_clear(dst, ov->string);
else
environ_set(dst, envent->name, "%s", envent->value);
a = options_array_next(a);
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..86d307ef 100644
--- a/layout.c
+++ b/layout.c
@@ -414,9 +414,9 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
- if (lcparent->type == LAYOUT_LEFTRIGHT)
+ if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
- else
+ else if (lcother != NULL)
layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
/* Remove this from the parent's list. */
@@ -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/options-table.c b/options-table.c
index 40639aff..a8beea06 100644
--- a/options-table.c
+++ b/options-table.c
@@ -140,8 +140,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "command-alias",
- .type = OPTIONS_TABLE_ARRAY,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "split-pane=split-window,"
"splitp=split-window,"
"server-info=show-messages -JT,"
@@ -205,8 +206,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "terminal-overrides",
- .type = OPTIONS_TABLE_ARRAY,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT",
@@ -214,8 +216,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "user-keys",
- .type = OPTIONS_TABLE_ARRAY,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "",
.separator = ","
},
@@ -420,8 +423,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "status-format",
- .type = OPTIONS_TABLE_ARRAY,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
.default_arr = options_table_status_format_default,
},
@@ -503,8 +507,9 @@ const struct options_table_entry options_table[] = {
},
{ .name = "update-environment",
- .type = OPTIONS_TABLE_ARRAY,
+ .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
+ .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
},
diff --git a/options.c b/options.c
index 369776e3..0b13bca0 100644
--- a/options.c
+++ b/options.c
@@ -32,10 +32,9 @@
struct options_array_item {
u_int index;
- char *value;
+ union options_value value;
RB_ENTRY(options_array_item) entry;
};
-RB_HEAD(options_array, options_array_item);
static int
options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
{
@@ -48,19 +47,13 @@ options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
struct options_entry {
- struct options *owner;
+ struct options *owner;
- const char *name;
- const struct options_table_entry *tableentry;
+ const char *name;
+ const struct options_table_entry *tableentry;
+ union options_value value;
- union {
- char *string;
- long long number;
- struct style style;
- struct options_array array;
- };
-
- RB_ENTRY(options_entry) entry;
+ RB_ENTRY(options_entry) entry;
};
struct options {
@@ -83,9 +76,10 @@ static struct options_entry *options_add(struct options *, const char *);
#define OPTIONS_IS_STYLE(o) \
((o)->tableentry != NULL && \
(o)->tableentry->type == OPTIONS_TABLE_STYLE)
-#define OPTIONS_IS_ARRAY(o) \
+
+#define OPTIONS_IS_ARRAY(o) \
((o)->tableentry != NULL && \
- (o)->tableentry->type == OPTIONS_TABLE_ARRAY)
+ ((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY))
static int options_cmp(struct options_entry *, struct options_entry *);
RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);
@@ -109,6 +103,56 @@ options_parent_table_entry(struct options *oo, const char *s)
return (o->tableentry);
}
+static void
+options_value_free(struct options_entry *o, union options_value *ov)
+{
+ if (OPTIONS_IS_STRING(o))
+ free(ov->string);
+}
+
+static const char *
+options_value_tostring(struct options_entry *o, union options_value *ov,
+ int numeric)
+{
+ static char s[1024];
+ const char *tmp;
+
+ if (OPTIONS_IS_STYLE(o))
+ return (style_tostring(&ov->style));
+ if (OPTIONS_IS_NUMBER(o)) {
+ tmp = NULL;
+ switch (o->tableentry->type) {
+ case OPTIONS_TABLE_NUMBER:
+ xsnprintf(s, sizeof s, "%lld", ov->number);
+ break;
+ case OPTIONS_TABLE_KEY:
+ tmp = key_string_lookup_key(ov->number);
+ break;
+ case OPTIONS_TABLE_COLOUR:
+ tmp = colour_tostring(ov->number);
+ break;
+ case OPTIONS_TABLE_FLAG:
+ if (numeric)
+ xsnprintf(s, sizeof s, "%lld", ov->number);
+ else
+ tmp = (ov->number ? "on" : "off");
+ break;
+ case OPTIONS_TABLE_CHOICE:
+ tmp = o->tableentry->choices[ov->number];
+ break;
+ case OPTIONS_TABLE_STRING:
+ case OPTIONS_TABLE_STYLE:
+ break;
+ }
+ if (tmp != NULL)
+ xsnprintf(s, sizeof s, "%s", tmp);
+ return (s);
+ }
+ if (OPTIONS_IS_STRING(o))
+ return (ov->string);
+ return ("");
+}
+
struct options *
options_create(struct options *parent)
{
@@ -174,8 +218,11 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
o = options_add(oo, oe->name);
o->tableentry = oe;
- if (oe->type == OPTIONS_TABLE_ARRAY)
- RB_INIT(&o->array);
+ if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
+ if (oe->type != OPTIONS_TABLE_STRING)
+ fatalx("arrays can only be strings");
+ RB_INIT(&o->value.array);
+ }
return (o);
}
@@ -183,23 +230,34 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
struct options_entry *
options_default(struct options *oo, const struct options_table_entry *oe)
{
- struct options_entry *o;
- u_int i;
+ struct options_entry *o;
+ union options_value *ov;
+ u_int i;
o = options_empty(oo, oe);
- if (oe->type == OPTIONS_TABLE_ARRAY) {
+ ov = &o->value;
+
+ if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
if (oe->default_arr != NULL) {
for (i = 0; oe->default_arr[i] != NULL; i++)
options_array_set(o, i, oe->default_arr[i], 0);
} else
options_array_assign(o, oe->default_str);
- } else if (oe->type == OPTIONS_TABLE_STRING)
- o->string = xstrdup(oe->default_str);
- else if (oe->type == OPTIONS_TABLE_STYLE) {
- style_set(&o->style, &grid_default_cell);
- style_parse(&o->style, &grid_default_cell, oe->default_str);
- } else
- o->number = oe->default_num;
+ return (o);
+ }
+
+ switch (oe->type) {
+ case OPTIONS_TABLE_STRING:
+ ov->string = xstrdup(oe->default_str);
+ break;
+ case OPTIONS_TABLE_STYLE:
+ style_set(&ov->style, &grid_default_cell);
+ style_parse(&ov->style, &grid_default_cell, oe->default_str);
+ break;
+ default:
+ ov->number = oe->default_num;
+ break;
+ }
return (o);
}
@@ -225,11 +283,10 @@ options_remove(struct options_entry *o)
{
struct options *oo = o->owner;
- if (OPTIONS_IS_STRING(o))
- free(o->string);
- else if (OPTIONS_IS_ARRAY(o))
+ if (OPTIONS_IS_ARRAY(o))
options_array_clear(o);
-
+ else
+ options_value_free(o, &o->value);
RB_REMOVE(options_tree, &oo->tree, o);
free(o);
}
@@ -252,14 +309,14 @@ options_array_item(struct options_entry *o, u_int idx)
struct options_array_item a;
a.index = idx;
- return (RB_FIND(options_array, &o->array, &a));
+ return (RB_FIND(options_array, &o->value.array, &a));
}
static void
options_array_free(struct options_entry *o, struct options_array_item *a)
{
- free(a->value);
- RB_REMOVE(options_array, &o->array, a);
+ options_value_free(o, &a->value);
+ RB_REMOVE(options_array, &o->value.array, a);
free(a);
}
@@ -271,11 +328,11 @@ options_array_clear(struct options_entry *o)
if (!OPTIONS_IS_ARRAY(o))
return;
- RB_FOREACH_SAFE(a, options_array, &o->array, a1)
+ RB_FOREACH_SAFE(a, options_array, &o->value.array, a1)
options_array_free(o, a);
}
-const char *
+union options_value *
options_array_get(struct options_entry *o, u_int idx)
{
struct options_array_item *a;
@@ -285,7 +342,7 @@ options_array_get(struct options_entry *o, u_int idx)
a = options_array_item(o, idx);
if (a == NULL)
return (NULL);
- return (a->value);
+ return (&a->value);
}
int
@@ -308,15 +365,15 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
if (a == NULL) {
a = xcalloc(1, sizeof *a);
a->index = idx;
- a->value = xstrdup(value);
- RB_INSERT(options_array, &o->array, a);
+ a->value.string = xstrdup(value);
+ RB_INSERT(options_array, &o->value.array, a);
} else {
- free(a->value);
+ options_value_free(o, &a->value);
if (a != NULL && append)
- xasprintf(&new, "%s%s", a->value, value);
+ xasprintf(&new, "%s%s", a->value.string, value);
else
new = xstrdup(value);
- a->value = new;
+ a->value.string = new;
}
return (0);
@@ -353,13 +410,13 @@ options_array_first(struct options_entry *o)
{
if (!OPTIONS_IS_ARRAY(o))
return (NULL);
- return (RB_MIN(options_array, &o->array));
+ return (RB_MIN(options_array, &o->value.array));
}
struct options_array_item *
options_array_next(struct options_array_item *a)
{
- return (RB_NEXT(options_array, &o->array, a));
+ return (RB_NEXT(options_array, &o->value.array, a));
}
u_int
@@ -368,10 +425,10 @@ options_array_item_index(struct options_array_item *a)
return (a->index);
}
-const char *
+union options_value *
options_array_item_value(struct options_array_item *a)
{
- return (a->value);
+ return (&a->value);
}
int
@@ -383,14 +440,12 @@ options_isarray(struct options_entry *o)
int
options_isstring(struct options_entry *o)
{
- return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o));
+ return (OPTIONS_IS_STRING(o));
}
const char *
options_tostring(struct options_entry *o, int idx, int numeric)
{
- static char s[1024];
- const char *tmp;
struct options_array_item *a;
if (OPTIONS_IS_ARRAY(o)) {
@@ -399,43 +454,9 @@ options_tostring(struct options_entry *o, int idx, int numeric)
a = options_array_item(o, idx);
if (a == NULL)
return ("");
- return (a->value);
- }
- if (OPTIONS_IS_STYLE(o))
- return (style_tostring(&o->style));
- if (OPTIONS_IS_NUMBER(o)) {
- tmp = NULL;
- switch (o->tableentry->type) {
- case OPTIONS_TABLE_NUMBER:
- xsnprintf(s, sizeof s, "%lld", o->number);
- break;
- case OPTIONS_TABLE_KEY:
- tmp = key_string_lookup_key(o->number);
- break;
- case OPTIONS_TABLE_COLOUR:
- tmp = colour_tostring(o->number);
- break;
- case OPTIONS_TABLE_FLAG:
- if (numeric)
- xsnprintf(s, sizeof s, "%lld", o->number);
- else
- tmp = (o->number ? "on" : "off");
- break;
- case OPTIONS_TABLE_CHOICE:
- tmp = o->tableentry->choices[o->number];
- break;
- case OPTIONS_TABLE_STRING:
- case OPTIONS_TABLE_STYLE:
- case OPTIONS_TABLE_ARRAY:
- break;
- }
- if (tmp != NULL)
- xsnprintf(s, sizeof s, "%s", tmp);
- return (s);
+ return (options_value_tostring(o, &a->value, numeric));
}
- if (OPTIONS_IS_STRING(o))
- return (o->string);
- return (NULL);
+ return (options_value_tostring(o, &o->value, numeric));
}
char *
@@ -549,7 +570,7 @@ options_get_string(struct options *oo, const char *name)
fatalx("missing option %s", name);
if (!OPTIONS_IS_STRING(o))
fatalx("option %s is not a string", name);
- return (o->string);
+ return (o->value.string);
}
long long
@@ -562,7 +583,7 @@ options_get_number(struct options *oo, const char *name)
fatalx("missing option %s", name);
if (!OPTIONS_IS_NUMBER(o))
fatalx("option %s is not a number", name);
- return (o->number);
+ return (o->value.number);
}
struct style *
@@ -575,7 +596,7 @@ options_get_style(struct options *oo, const char *name)
fatalx("missing option %s", name);
if (!OPTIONS_IS_STYLE(o))
fatalx("option %s is not a style", name);
- return (&o->style);
+ return (&o->value.style);
}
struct options_entry *
@@ -592,7 +613,7 @@ options_set_string(struct options *oo, const char *name, int append,
o = options_get_only(oo, name);
if (o != NULL && append && OPTIONS_IS_STRING(o)) {
- xasprintf(&value, "%s%s", o->string, s);
+ xasprintf(&value, "%s%s", o->value.string, s);
free(s);
} else
value = s;
@@ -606,8 +627,8 @@ options_set_string(struct options *oo, const char *name, int append,
if (!OPTIONS_IS_STRING(o))
fatalx("option %s is not a string", name);
- free(o->string);
- o->string = value;
+ free(o->value.string);
+ o->value.string = value;
return (o);
}
@@ -628,7 +649,7 @@ options_set_number(struct options *oo, const char *name, long long value)
if (!OPTIONS_IS_NUMBER(o))
fatalx("option %s is not a number", name);
- o->number = value;
+ o->value.number = value;
return (o);
}
@@ -644,7 +665,7 @@ options_set_style(struct options *oo, const char *name, int append,
o = options_get_only(oo, name);
if (o != NULL && append && OPTIONS_IS_STYLE(o))
- style_copy(&sy, &o->style);
+ style_copy(&sy, &o->value.style);
else
style_set(&sy, &grid_default_cell);
if (style_parse(&sy, &grid_default_cell, value) == -1)
@@ -657,7 +678,7 @@ options_set_style(struct options *oo, const char *name, int append,
if (!OPTIONS_IS_STYLE(o))
fatalx("option %s is not a style", name);
- style_copy(&o->style, &sy);
+ style_copy(&o->value.style, &sy);
return (o);
}
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/status.c b/status.c
index 467db6ad..1a11a564 100644
--- a/status.c
+++ b/status.c
@@ -323,8 +323,8 @@ status_redraw(struct client *c)
u_int lines, i, width = c->tty.sx;
int flags, force = 0, changed = 0;
struct options_entry *o;
+ union options_value *ov;
struct format_tree *ft;
- const char *fmt;
char *expanded;
log_debug("%s enter", __func__);
@@ -370,14 +370,14 @@ status_redraw(struct client *c)
for (i = 0; i < lines; i++) {
screen_write_cursormove(&ctx, 0, i, 0);
- fmt = options_array_get(o, i);
- if (fmt == NULL) {
+ ov = options_array_get(o, i);
+ if (ov == NULL) {
screen_write_clearline(&ctx, gc.bg);
continue;
}
sle = &sl->entries[i];
- expanded = format_expand_time(ft, fmt);
+ expanded = format_expand_time(ft, ov->string);
if (!force &&
sle->expanded != NULL &&
strcmp(expanded, sle->expanded) == 0) {
@@ -1293,6 +1293,7 @@ status_prompt_complete_list(u_int *size, const char *s)
size_t slen = strlen(s), valuelen;
struct options_entry *o;
struct options_array_item *a;
+ union options_value *ov;
const char *layouts[] = {
"even-horizontal", "even-vertical", "main-horizontal",
"main-vertical", "tiled", NULL
@@ -1321,10 +1322,13 @@ status_prompt_complete_list(u_int *size, const char *s)
if (o != NULL) {
a = options_array_first(o);
while (a != NULL) {
- value = options_array_item_value(a);;
- if (value == NULL || (cp = strchr(value, '=')) == NULL)
+ ov = options_array_item_value(a);
+ if (ov == NULL)
goto next;
+ value = ov->string;
+ if ((cp = strchr(value, '=')) == NULL)
+ goto next;
valuelen = cp - value;
if (slen > valuelen || strncmp(value, s, slen) != 0)
goto next;
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..396ed4a2 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,14 @@ 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-no-clear <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-no-clear [<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,15 +1232,27 @@ 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
commands) or when the cursor reaches the bottom (for scrolling commands).
+.Ql -no-clear
+variants do not clear the selection.
.Pp
The next and previous word keys use space and the
.Ql - ,
@@ -2513,9 +2535,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 +3474,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..0c317b8b 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];
@@ -1516,6 +1516,15 @@ struct key_table {
};
RB_HEAD(key_tables, key_table);
+/* Option data. */
+RB_HEAD(options_array, options_array_item);
+union options_value {
+ char *string;
+ long long number;
+ struct style style;
+ struct options_array array;
+};
+
/* Option table entries. */
enum options_table_type {
OPTIONS_TABLE_STRING,
@@ -1524,8 +1533,7 @@ enum options_table_type {
OPTIONS_TABLE_COLOUR,
OPTIONS_TABLE_FLAG,
OPTIONS_TABLE_CHOICE,
- OPTIONS_TABLE_STYLE,
- OPTIONS_TABLE_ARRAY,
+ OPTIONS_TABLE_STYLE
};
enum options_table_scope {
@@ -1535,10 +1543,13 @@ enum options_table_scope {
OPTIONS_TABLE_WINDOW,
};
+#define OPTIONS_TABLE_IS_ARRAY 0x1
+
struct options_table_entry {
const char *name;
enum options_table_type type;
enum options_table_scope scope;
+ int flags;
u_int minimum;
u_int maximum;
@@ -1563,6 +1574,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 +1650,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 *);
@@ -1697,14 +1734,14 @@ struct options_entry *options_get_only(struct options *, const char *);
struct options_entry *options_get(struct options *, const char *);
void options_remove(struct options_entry *);
void options_array_clear(struct options_entry *);
-const char *options_array_get(struct options_entry *, u_int);
+union options_value *options_array_get(struct options_entry *, u_int);
int options_array_set(struct options_entry *, u_int, const char *,
int);
void options_array_assign(struct options_entry *, const char *);
struct options_array_item *options_array_first(struct options_entry *);
struct options_array_item *options_array_next(struct options_array_item *);
u_int options_array_item_index(struct options_array_item *);
-const char *options_array_item_value(struct options_array_item *);
+union options_value *options_array_item_value(struct options_array_item *);
int options_isarray(struct options_entry *);
int options_isstring(struct options_entry *);
const char *options_tostring(struct options_entry *, int, int);
@@ -2234,17 +2271,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 +2298,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 +2355,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 +2454,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 +2530,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..c6dcbb56 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -399,9 +399,10 @@ tty_keys_build(struct tty *tty)
const struct tty_default_key_raw *tdkr;
const struct tty_default_key_code *tdkc;
u_int i;
- const char *s, *value;
+ const char *s;
struct options_entry *o;
struct options_array_item *a;
+ union options_value *ov;
if (tty->key_tree != NULL)
tty_keys_free(tty);
@@ -427,9 +428,9 @@ tty_keys_build(struct tty *tty)
if (o != NULL) {
a = options_array_first(o);
while (a != NULL) {
- value = options_array_item_value(a);
- if (value != NULL)
- tty_keys_add(tty, value, KEYC_USER + i);
+ ov = options_array_item_value(a);
+ if (ov != NULL)
+ tty_keys_add(tty, ov->string, KEYC_USER + i);
a = options_array_next(a);
}
}
@@ -976,7 +977,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/tty-term.c b/tty-term.c
index def0feec..89d3241c 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -420,6 +420,7 @@ tty_term_find(char *name, int fd, char **cause)
struct tty_code *code;
struct options_entry *o;
struct options_array_item *a;
+ union options_value *ov;
u_int i;
int n, error;
const char *s, *acs;
@@ -497,9 +498,9 @@ tty_term_find(char *name, int fd, char **cause)
o = options_get_only(global_options, "terminal-overrides");
a = options_array_first(o);
while (a != NULL) {
- s = options_array_item_value(a);
- if (s != NULL)
- tty_term_override(term, s);
+ ov = options_array_item_value(a);
+ if (ov != NULL)
+ tty_term_override(term, ov->string);
a = options_array_next(a);
}
diff --git a/tty.c b/tty.c
index 9ed2b3a9..ff72b7da 100644
--- a/tty.c
+++ b/tty.c
@@ -2361,7 +2361,7 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
if (gc->bg & 8) {
gc->bg &= 7;
if (colours >= 16)
- gc->fg += 90;
+ gc->bg += 90;
}
}
return;
@@ -2388,8 +2388,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
/* Is this an aixterm bright colour? */
if (gc->fg >= 90 && gc->fg <= 97) {
- xsnprintf(s, sizeof s, "\033[%dm", gc->fg);
- tty_puts(tty, s);
+ tty_putcode1(tty, TTYC_SETAF, gc->fg - 90 + 8);
goto save_fg;
}
@@ -2417,8 +2416,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
/* Is this an aixterm bright colour? */
if (gc->bg >= 90 && gc->bg <= 97) {
- xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10);
- tty_puts(tty, s);
+ tty_putcode1(tty, TTYC_SETAB, gc->bg - 90 + 8);
goto save_bg;
}
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..53dd97d3 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,1071 @@ 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_no_clear(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);
+
+ free(prefix);
+ return (WINDOW_COPY_CMD_NOTHING);
+}
+
+static enum window_copy_cmd_action
+window_copy_cmd_copy_selection(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_cmd_copy_selection_no_clear(cs);
+ window_copy_clear_selection(wme);
+ 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;
+
+ window_copy_cmd_copy_selection_no_clear(cs);
+ window_copy_clear_selection(wme);
+ 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_no_clear(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(struct window_copy_cmd_state *cs)
+{
+ struct window_mode_entry *wme = cs->wme;
+
+ window_copy_cmd_copy_pipe_no_clear(cs);
+ window_copy_clear_selection(wme);
+ return (WINDOW_COPY_CMD_REDRAW);
+}
+
+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;
+
+ window_copy_cmd_copy_pipe_no_clear(cs);
+ window_copy_clear_selection(wme);
+ return (WINDOW_COPY_CMD_CANCEL);
+}
+
+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-no-clear", 1, 2,
+ window_copy_cmd_copy_pipe_no_clear },
+ { "copy-pipe", 1, 2,
+ window_copy_cmd_copy_pipe },
+ { "copy-pipe-and-cancel", 1, 2,
+ window_copy_cmd_copy_pipe_and_cancel },
+ { "copy-selection-no-clear", 0, 1,
+ window_copy_cmd_copy_selection_no_clear },
+ { "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 +1655,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 +2396,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 +2409,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. */