aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd-capture-pane.c25
-rw-r--r--cmd-choose-buffer.c9
-rw-r--r--cmd-delete-buffer.c15
-rw-r--r--cmd-find-window.c2
-rw-r--r--cmd-list-buffers.c6
-rw-r--r--cmd-load-buffer.c57
-rw-r--r--cmd-new-session.c34
-rw-r--r--cmd-new-window.c24
-rw-r--r--cmd-paste-buffer.c29
-rw-r--r--cmd-respawn-pane.c13
-rw-r--r--cmd-respawn-window.c12
-rw-r--r--cmd-save-buffer.c18
-rw-r--r--cmd-set-buffer.c67
-rw-r--r--cmd-split-window.c25
-rw-r--r--cmd.c30
-rw-r--r--format.c9
-rw-r--r--input-keys.c15
-rw-r--r--layout.c1
-rw-r--r--mode-key.c2
-rw-r--r--names.c12
-rw-r--r--paste.c202
-rw-r--r--session.c18
-rw-r--r--style.c8
-rw-r--r--tmux.193
-rw-r--r--tmux.h55
-rw-r--r--tty-keys.c6
-rw-r--r--window-choose.c19
-rw-r--r--window-copy.c86
-rw-r--r--window.c327
29 files changed, 740 insertions, 479 deletions
diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c
index 49614632..bbaf70cd 100644
--- a/cmd-capture-pane.c
+++ b/cmd-capture-pane.c
@@ -38,7 +38,7 @@ char *cmd_capture_pane_history(struct args *, struct cmd_q *,
const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep",
"ab:CeE:JpPqS:t:", 0, 0,
- "[-aCeJpPq] [-b buffer-index] [-E end-line] [-S start-line]"
+ "[-aCeJpPq] " CMD_BUFFER_USAGE " [-E end-line] [-S start-line]"
CMD_TARGET_PANE_USAGE,
0,
NULL,
@@ -165,8 +165,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c;
struct window_pane *wp;
char *buf, *cause;
- int buffer;
- u_int limit;
+ const char *bufname;
size_t len;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
@@ -192,23 +191,15 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c);
} else {
- limit = options_get_number(&global_options, "buffer-limit");
- if (!args_has(args, 'b')) {
- paste_add(buf, len, limit);
- return (CMD_RETURN_NORMAL);
- }
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(buf);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
+ bufname = NULL;
+ if (args_has(args, 'b'))
+ bufname = args_get(args, 'b');
- if (paste_replace(buffer, buf, len) != 0) {
- cmdq_error(cmdq, "no buffer %d", buffer);
+ if (paste_set(buf, len, bufname, &cause) != 0) {
+ cmdq_error(cmdq, "%s", cause);
free(buf);
+ free(cause);
return (CMD_RETURN_ERROR);
}
}
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 18d28345..6b146fad 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -75,19 +75,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
action = xstrdup("paste-buffer -b '%%'");
idx = 0;
- while ((pb = paste_walk_stack(&idx)) != NULL) {
+ pb = NULL;
+ while ((pb = paste_walk(pb)) != NULL) {
cdata = window_choose_data_create(TREE_OTHER, c, c->session);
- cdata->idx = idx - 1;
+ cdata->idx = idx;
cdata->ft_template = xstrdup(template);
- format_add(cdata->ft, "line", "%u", idx - 1);
format_paste_buffer(cdata->ft, pb, utf8flag);
- xasprintf(&action_data, "%u", idx - 1);
+ xasprintf(&action_data, "%s", pb->name);
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
window_choose_add(wl->window->active, cdata);
+ idx++;
}
free(action);
diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c
index e05fe090..9957de66 100644
--- a/cmd-delete-buffer.c
+++ b/cmd-delete-buffer.c
@@ -41,23 +41,16 @@ enum cmd_retval
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
- char *cause;
- int buffer;
+ const char *bufname;
if (!args_has(args, 'b')) {
paste_free_top();
return (CMD_RETURN_NORMAL);
}
+ bufname = args_get(args, 'b');
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
-
- if (paste_free_index(buffer) != 0) {
- cmdq_error(cmdq, "no buffer %d", buffer);
+ if (paste_free_name(bufname) != 0) {
+ cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-find-window.c b/cmd-find-window.c
index bef9afee..39a279b5 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -200,6 +200,8 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out:
+ for (i = 0; i < ARRAY_LENGTH(&find_list); i++)
+ free(ARRAY_ITEM(&find_list, i).list_ctx);
ARRAY_FREE(&find_list);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c
index f3987dda..c5a6e322 100644
--- a/cmd-list-buffers.c
+++ b/cmd-list-buffers.c
@@ -44,17 +44,15 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args;
struct paste_buffer *pb;
struct format_tree *ft;
- u_int idx;
char *line;
const char *template;
if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE;
- idx = 0;
- while ((pb = paste_walk_stack(&idx)) != NULL) {
+ pb = NULL;
+ while ((pb = paste_walk(pb)) != NULL) {
ft = format_create();
- format_add(ft, "line", "%u", idx - 1);
format_paste_buffer(ft, pb, 0);
line = format_expand(ft, template);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 16ff40d0..d2e1cc6b 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -50,30 +50,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client;
struct session *s;
FILE *f;
- const char *path;
+ const char *path, *bufname;
char *pdata, *new_pdata, *cause;
size_t psize;
- u_int limit;
- int ch, error, buffer, *buffer_ptr, cwd, fd;
-
- if (!args_has(args, 'b'))
- buffer = -1;
- else {
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
- }
+ int ch, error, cwd, fd;
+
+ bufname = NULL;
+ if (args_has(args, 'b'))
+ bufname = args_get(args, 'b');
path = args->argv[0];
if (strcmp(path, "-") == 0) {
- buffer_ptr = xmalloc(sizeof *buffer_ptr);
- *buffer_ptr = buffer;
-
error = server_set_stdin_callback(c, cmd_load_buffer_callback,
- buffer_ptr, &cause);
+ (void*)bufname, &cause);
if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause);
free(cause);
@@ -117,14 +106,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
fclose(f);
- limit = options_get_number(&global_options, "buffer-limit");
- if (buffer == -1) {
- paste_add(pdata, psize, limit);
- return (CMD_RETURN_NORMAL);
- }
- if (paste_replace(buffer, pdata, psize) != 0) {
- cmdq_error(cmdq, "no buffer %d", buffer);
+ if (paste_set(pdata, psize, bufname, &cause) != 0) {
+ cmdq_error(cmdq, "%s", cause);
free(pdata);
+ free(cause);
return (CMD_RETURN_ERROR);
}
@@ -140,10 +125,9 @@ error:
void
cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
- int *buffer = data;
- char *pdata;
- size_t psize;
- u_int limit;
+ const char *bufname = data;
+ char *pdata, *cause;
+ size_t psize;
if (!closed)
return;
@@ -154,26 +138,21 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
return;
psize = EVBUFFER_LENGTH(c->stdin_data);
- if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
- free(data);
+ if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
goto out;
- }
+
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize);
- limit = options_get_number(&global_options, "buffer-limit");
- if (*buffer == -1)
- paste_add(pdata, psize, limit);
- else if (paste_replace(*buffer, pdata, psize) != 0) {
+ if (paste_set(pdata, psize, bufname, &cause) != 0) {
/* No context so can't use server_client_msg_error. */
- evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer);
+ evbuffer_add_printf(c->stderr_data, "%s", cause);
server_push_stderr(c);
free(pdata);
+ free(cause);
}
- free(data);
-
out:
cmdq_continue(c->cmdq);
}
diff --git a/cmd-new-session.c b/cmd-new-session.c
index 3071bd64..b36de70a 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -35,10 +35,10 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_session_entry = {
"new-session", "new",
- "Ac:dDF:n:Ps:t:x:y:", 0, 1,
+ "Ac:dDF:n:Ps:t:x:y:", 0, -1,
"[-AdDP] [-c start-directory] [-F format] [-n window-name] "
- "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
- "[command]",
+ "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
+ "[-y height] [command]",
CMD_STARTSERVER|CMD_CANTNEST,
NULL,
cmd_new_session_exec
@@ -55,8 +55,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
struct termios tio, *tiop;
const char *newname, *target, *update, *errstr, *template;
const char *path;
- char *cmd, *cause, *cp;
+ char **argv, *cmd, *cause, *cp;
int detached, already_attached, idx, cwd, fd = -1;
+ int argc;
u_int sx, sy;
struct format_tree *ft;
struct environ_entry *envent;
@@ -183,12 +184,21 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
sy = 1;
/* Figure out the command for the new window. */
- if (target != NULL)
- cmd = NULL;
- else if (args->argc != 0)
- cmd = args->argv[0];
- else
+ argc = -1;
+ argv = NULL;
+ if (target == NULL && args->argc != 0) {
+ argc = args->argc;
+ argv = args->argv;
+ } else if (target == NULL) {
cmd = options_get_string(&global_s_options, "default-command");
+ if (cmd != NULL && *cmd != '\0') {
+ argc = 1;
+ argv = &cmd;
+ } else {
+ argc = 0;
+ argv = NULL;
+ }
+ }
path = NULL;
if (c != NULL && c->session == NULL)
@@ -206,8 +216,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
/* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index");
- s = session_create(newname, cmd, path, cwd, &env, tiop, idx, sx, sy,
- &cause);
+ s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx,
+ sy, &cause);
if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause);
free(cause);
@@ -216,7 +226,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
environ_free(&env);
/* Set the initial window name if one given. */
- if (cmd != NULL && args_has(args, 'n')) {
+ if (argc >= 0 && args_has(args, 'n')) {
w = s->curw->window;
window_set_name(w, args_get(args, 'n'));
options_set_number(&w->options, "automatic-rename", 0);
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 6e9fea50..cd0042ee 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -34,7 +34,7 @@ enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
- "ac:dF:kn:Pt:", 0, 1,
+ "ac:dF:kn:Pt:", 0, -1,
"[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]",
0,
@@ -50,8 +50,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct winlink *wl;
struct client *c;
const char *cmd, *path, *template;
- char *cause, *cp;
- int idx, last, detached, cwd, fd = -1;
+ char **argv, *cause, *cp;
+ int argc, idx, last, detached, cwd, fd = -1;
struct format_tree *ft;
struct environ_entry *envent;
@@ -84,10 +84,19 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
}
detached = args_has(args, 'd');
- if (args->argc == 0)
+ if (args->argc == 0) {
cmd = options_get_string(&s->options, "default-command");
- else
- cmd = args->argv[0];
+ if (cmd != NULL && *cmd != '\0') {
+ argc = 1;
+ argv = (char**)&cmd;
+ } else {
+ argc = 0;
+ argv = NULL;
+ }
+ } else {
+ argc = args->argc;
+ argv = args->argv;
+ }
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
@@ -145,7 +154,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");
- wl = session_new(s, args_get(args, 'n'), cmd, path, cwd, idx, &cause);
+ wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
+ &cause);
if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause);
free(cause);
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 4bc2cfda..f6c9d0ad 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -35,7 +35,7 @@ void cmd_paste_buffer_filter(struct window_pane *,
const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb",
"db:prs:t:", 0, 0,
- "[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE,
+ "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " CMD_TARGET_PANE_USAGE,
0,
NULL,
cmd_paste_buffer_exec
@@ -48,31 +48,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
- const char *sepstr;
- char *cause;
- int buffer;
+ const char *sepstr, *bufname;
int pflag;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR);
- if (!args_has(args, 'b'))
- buffer = -1;
- else {
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
- }
+ bufname = NULL;
+ if (args_has(args, 'b'))
+ bufname = args_get(args, 'b');
- if (buffer == -1)
+ if (bufname == NULL)
pb = paste_get_top();
else {
- pb = paste_get_index(buffer);
+ pb = paste_get_name(bufname);
if (pb == NULL) {
- cmdq_error(cmdq, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}
}
@@ -91,10 +82,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
/* Delete the buffer if -d. */
if (args_has(args, 'd')) {
- if (buffer == -1)
+ if (bufname == NULL)
paste_free_top();
else
- paste_free_index(buffer);
+ paste_free_name(bufname);
}
return (CMD_RETURN_NORMAL);
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index 9ac5b0b8..f951685c 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -32,7 +32,7 @@ enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp",
- "kt:", 0, 1,
+ "kt:", 0, -1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]",
0,
NULL,
@@ -48,7 +48,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;
struct session *s;
struct environ env;
- const char *cmd, *path;
+ const char *path;
char *cause;
u_int idx;
struct environ_entry *envent;
@@ -74,11 +74,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
screen_reinit(&wp->base);
input_init(wp);
- if (args->argc != 0)
- cmd = args->argv[0];
- else
- cmd = NULL;
-
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH");
@@ -87,8 +82,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
if (envent != NULL)
path = envent->value;
- if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio,
- &cause) != 0) {
+ if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
+ s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause);
environ_free(&env);
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index d891eff3..307560bb 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -31,7 +31,7 @@ enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw",
- "kt:", 0, 1,
+ "kt:", 0, -1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
0,
NULL,
@@ -47,7 +47,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;
struct session *s;
struct environ env;
- const char *cmd, *path;
+ const char *path;
char *cause;
struct environ_entry *envent;
@@ -76,10 +76,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy);
- if (args->argc != 0)
- cmd = args->argv[0];
- else
- cmd = NULL;
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
@@ -89,8 +85,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (envent != NULL)
path = envent->value;
- if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio,
- &cause) != 0) {
+ if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
+ s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause);
environ_free(&env);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index b5ca62ee..8dd52c96 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -58,10 +58,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client;
struct session *s;
struct paste_buffer *pb;
- const char *path;
- char *cause, *start, *end, *msg;
+ const char *path, *bufname;
+ char *start, *end, *msg;
size_t size, used, msglen;
- int cwd, fd, buffer;
+ int cwd, fd;
FILE *f;
if (!args_has(args, 'b')) {
@@ -70,16 +70,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
} else {
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
-
- pb = paste_get_index(buffer);
+ bufname = args_get(args, 'b');
+ pb = paste_get_name(bufname);
if (pb == NULL) {
- cmdq_error(cmdq, "no buffer %d", buffer);
+ cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR);
}
}
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index b0fc3fe4..82922279 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -31,8 +31,8 @@ enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb",
- "ab:", 1, 1,
- "[-a] " CMD_BUFFER_USAGE " data",
+ "ab:n:", 0, 1,
+ "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
0,
NULL,
cmd_set_buffer_exec
@@ -43,38 +43,59 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct paste_buffer *pb;
- u_int limit;
char *pdata, *cause;
+ const char *bufname;
size_t psize, newsize;
- int buffer;
- limit = options_get_number(&global_options, "buffer-limit");
+ bufname = NULL;
+
+ if (args_has(args, 'n')) {
+ if (args->argc > 0) {
+ cmdq_error(cmdq, "don't provide data with n flag");
+ return (CMD_RETURN_ERROR);
+ }
+
+ if (args_has(args, 'b'))
+ bufname = args_get(args, 'b');
+
+ if (bufname == NULL) {
+ pb = paste_get_top();
+ if (pb == NULL) {
+ cmdq_error(cmdq, "no buffer");
+ return (CMD_RETURN_ERROR);
+ }
+ bufname = pb->name;
+ }
+
+ if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
+ cmdq_error(cmdq, "%s", cause);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
+
+ return (CMD_RETURN_NORMAL);
+ }
+
+ if (args->argc != 1) {
+ cmdq_error(cmdq, "no data specified");
+ return (CMD_RETURN_ERROR);
+ }
psize = 0;
pdata = NULL;
pb = NULL;
- buffer = -1;
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'b')) {
- buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
- if (cause != NULL) {
- cmdq_error(cmdq, "buffer %s", cause);
- free(cause);
- return (CMD_RETURN_ERROR);
- }
- pb = paste_get_index(buffer);
- if (pb == NULL) {
- cmdq_error(cmdq, "no buffer %d", buffer);
- return (CMD_RETURN_ERROR);
- }
+ bufname = args_get(args, 'b');
+ pb = paste_get_name(bufname);
} else if (args_has(args, 'a')) {
pb = paste_get_top();
if (pb != NULL)
- buffer = 0;
+ bufname = pb->name;
}
if (args_has(args, 'a') && pb != NULL) {
@@ -87,10 +108,12 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
memcpy(pdata + psize, args->argv[0], newsize);
psize += newsize;
- if (buffer == -1)
- paste_add(pdata, psize, limit);
- else
- paste_replace(buffer, pdata, psize);
+ if (paste_set(pdata, psize, bufname, &cause) != 0) {
+ cmdq_error(cmdq, "%s", cause);
+ free(pdata);
+ free(cause);
+ return (CMD_RETURN_ERROR);
+ }
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-split-window.c b/cmd-split-window.c
index 9c4734be..ea047a3f 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -35,7 +35,7 @@ enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw",
- "c:dF:l:hp:Pt:v", 0, 1,
+ "c:dF:l:hp:Pt:v", 0, -1,
"[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
CMD_TARGET_PANE_USAGE " [command]",
0,
@@ -61,9 +61,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp, *new_wp = NULL;
struct environ env;
const char *cmd, *path, *shell, *template;
- char *cause, *new_cause, *cp;
+ char **argv, *cause, *new_cause, *cp;
u_int hlimit;
- int size, percentage, cwd, fd = -1;
+ int argc, size, percentage, cwd, fd = -1;
enum layout_type type;
struct layout_cell *lc;
struct client *c;
@@ -80,10 +80,19 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
- if (args->argc == 0)
+ if (args->argc == 0) {
cmd = options_get_string(&s->options, "default-command");
- else
- cmd = args->argv[0];
+ 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, 'c')) {
ft = format_create();
@@ -157,8 +166,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (envent != NULL)
path = envent->value;
- if (window_pane_spawn(
- new_wp, cmd, path, shell, cwd, &env, s->tio, &cause) != 0)
+ if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, &env,
+ s->tio, &cause) != 0)
goto error;
layout_assign_pane(lc, new_wp);
diff --git a/cmd.c b/cmd.c
index f2d88c05..3a948c80 100644
--- a/cmd.c
+++ b/cmd.c
@@ -179,14 +179,14 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
}
char **
-cmd_copy_argv(int argc, char *const *argv)
+cmd_copy_argv(int argc, char **argv)
{
char **new_argv;
int i;
if (argc == 0)
return (NULL);
- new_argv = xcalloc(argc, sizeof *new_argv);
+ new_argv = xcalloc(argc + 1, sizeof *new_argv);
for (i = 0; i < argc; i++) {
if (argv[i] != NULL)
new_argv[i] = xstrdup(argv[i]);
@@ -206,6 +206,32 @@ cmd_free_argv(int argc, char **argv)
free(argv);
}
+char *
+cmd_stringify_argv(int argc, char **argv)
+{
+ char *buf;
+ int i;
+ size_t len;
+
+ if (argc == 0)
+ return (xstrdup(""));
+
+ len = 0;
+ buf = NULL;
+
+ for (i = 0; i < argc; i++) {
+ len += strlen(argv[i]) + 1;
+ buf = xrealloc(buf, 1, len);
+
+ if (i == 0)
+ *buf = '\0';
+ else
+ strlcat(buf, " ", len);
+ strlcat(buf, argv[i], len);
+ }
+ return (buf);
+}
+
struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{
diff --git a/format.c b/format.c
index 6f988b9a..ecfda1be 100644
--- a/format.c
+++ b/format.c
@@ -368,7 +368,7 @@ format_get_command(struct window_pane *wp)
cmd = osdep_get_name(wp->fd, wp->tty);
if (cmd == NULL || *cmd == '\0') {
free(cmd);
- cmd = xstrdup(wp->cmd);
+ cmd = cmd_stringify_argv(wp->argc, wp->argv);
if (cmd == NULL || *cmd == '\0') {
free(cmd);
cmd = xstrdup(wp->shell);
@@ -559,10 +559,12 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
if (wp->tty != NULL)
format_add(ft, "pane_tty", "%s", wp->tty);
format_add(ft, "pane_pid", "%ld", (long) wp->pid);
- if (wp->cmd != NULL)
- format_add(ft, "pane_start_command", "%s", wp->cmd);
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
format_add(ft, "pane_current_path", "%s", cwd);
+ if ((cmd = cmd_stringify_argv(wp->argc, wp->argv)) != NULL) {
+ format_add(ft, "pane_start_command", "%s", cmd);
+ free(cmd);
+ }
if ((cmd = format_get_command(wp)) != NULL) {
format_add(ft, "pane_current_command", "%s", cmd);
free(cmd);
@@ -610,6 +612,7 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
char *s;
format_add(ft, "buffer_size", "%zu", pb->size);
+ format_add(ft, "buffer_name", "%s", pb->name);
s = paste_make_sample(pb, utf8flag);
format_add(ft, "buffer_sample", "%s", s);
diff --git a/input-keys.c b/input-keys.c
index 11126985..7531f22d 100644
--- a/input-keys.c
+++ b/input-keys.c
@@ -204,6 +204,21 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
char buf[40];
size_t len;
struct paste_buffer *pb;
+ u_int i;
+
+ /*
+ * If the alternate screen is active and hasn't enabled the mouse, send
+ * up and down key presses for the mouse wheel.
+ */
+ if (wp->saved_grid != NULL && !(wp->screen->mode & ALL_MOUSE_MODES)) {
+ for (i = 0; i < m->scroll; i++) {
+ if (m->wheel == MOUSE_WHEEL_UP)
+ input_key(wp, KEYC_UP);
+ else
+ input_key(wp, KEYC_DOWN);
+ }
+ return;
+ }
if (wp->screen->mode & ALL_MOUSE_MODES) {
/*
diff --git a/layout.c b/layout.c
index cfa34b9e..646d1bd9 100644
--- a/layout.c
+++ b/layout.c
@@ -53,7 +53,6 @@ layout_create_cell(struct layout_cell *lcparent)
lc->yoff = UINT_MAX;
lc->wp = NULL;
- lc->lastwp = NULL;
return (lc);
}
diff --git a/mode-key.c b/mode-key.c
index 57be2d81..8bb83cb9 100644
--- a/mode-key.c
+++ b/mode-key.c
@@ -141,6 +141,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_SEARCHREVERSE, "search-reverse" },
{ MODEKEYCOPY_SEARCHUP, "search-backward" },
{ MODEKEYCOPY_SELECTLINE, "select-line" },
+ { MODEKEYCOPY_STARTNAMEDBUFFER, "start-named-buffer" },
{ MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" },
{ MODEKEYCOPY_STARTOFLINE, "start-of-line" },
{ MODEKEYCOPY_STARTSELECTION, "begin-selection" },
@@ -257,6 +258,7 @@ struct mode_key_tree mode_key_tree_vi_choice;
/* vi copy mode keys. */
const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
+ { '"', 0, MODEKEYCOPY_STARTNAMEDBUFFER },
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
diff --git a/names.c b/names.c
index 7c02961c..5c956259 100644
--- a/names.c
+++ b/names.c
@@ -68,9 +68,15 @@ window_name_callback(unused int fd, unused short events, void *data)
char *
default_window_name(struct window *w)
{
- if (w->active->cmd != NULL && *w->active->cmd != '\0')
- return (parse_window_name(w->active->cmd));
- return (parse_window_name(w->active->shell));
+ char *cmd, *s;
+
+ cmd = cmd_stringify_argv(w->active->argc, w->active->argv);
+ if (cmd != NULL && *cmd != '\0')
+ s = parse_window_name(cmd);
+ else
+ s = parse_window_name(w->active->shell);
+ free(cmd);
+ return (s);
}
char *
diff --git a/paste.c b/paste.c
index 0f29b6b9..fdd4f5d6 100644
--- a/paste.c
+++ b/paste.c
@@ -25,127 +25,237 @@
#include "tmux.h"
/*
- * Stack of paste buffers. Note that paste buffer data is not necessarily a C
+ * Set of paste buffers. Note that paste buffer data is not necessarily a C
* string!
*/
-ARRAY_DECL(, struct paste_buffer *) paste_buffers = ARRAY_INITIALIZER;
+u_int paste_next_index;
+u_int paste_next_order;
+u_int paste_num_automatic;
+RB_HEAD(paste_name_tree, paste_buffer) paste_by_name;
+RB_HEAD(paste_time_tree, paste_buffer) paste_by_time;
-/* Return each item of the stack in turn. */
-struct paste_buffer *
-paste_walk_stack(u_int *idx)
+int paste_cmp_names(const struct paste_buffer *, const struct paste_buffer *);
+RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
+RB_GENERATE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
+
+int paste_cmp_times(const struct paste_buffer *, const struct paste_buffer *);
+RB_PROTOTYPE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
+RB_GENERATE(paste_time_tree, paste_buffer, time_entry, paste_cmp_times);
+
+int
+paste_cmp_names(const struct paste_buffer *a, const struct paste_buffer *b)
{
- struct paste_buffer *pb;
+ return (strcmp(a->name, b->name));
+}
- pb = paste_get_index(*idx);
- (*idx)++;
- return (pb);
+int
+paste_cmp_times(const struct paste_buffer *a, const struct paste_buffer *b)
+{
+ if (a->order > b->order)
+ return (-1);
+ if (a->order < b->order)
+ return (1);
+ return (0);
}
-/* Get the top item on the stack. */
+/* Walk paste buffers by name. */
struct paste_buffer *
-paste_get_top(void)
+paste_walk(struct paste_buffer *pb)
{
- if (ARRAY_LENGTH(&paste_buffers) == 0)
- return (NULL);
- return (ARRAY_FIRST(&paste_buffers));
+ if (pb == NULL)
+ return (RB_MIN(paste_time_tree, &paste_by_time));
+ return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
}
-/* Get an item by its index. */
+/* Get the most recent automatic buffer */
struct paste_buffer *
-paste_get_index(u_int idx)
+paste_get_top(void)
{
- if (idx >= ARRAY_LENGTH(&paste_buffers))
+ struct paste_buffer *pb;
+
+ pb = RB_MIN(paste_time_tree, &paste_by_time);
+ if (pb == NULL)
return (NULL);
- return (ARRAY_ITEM(&paste_buffers, idx));
+ return (pb);
}
-/* Free the top item on the stack. */
+/* Free the most recent buffer */
int
paste_free_top(void)
{
struct paste_buffer *pb;
- if (ARRAY_LENGTH(&paste_buffers) == 0)
+ pb = paste_get_top();
+ if (pb == NULL)
return (-1);
+ return (paste_free_name(pb->name));
+}
- pb = ARRAY_FIRST(&paste_buffers);
- ARRAY_REMOVE(&paste_buffers, 0);
+/* Get a paste buffer by name. */
+struct paste_buffer *
+paste_get_name(const char *name)
+{
+ struct paste_buffer pbfind;
- free(pb->data);
- free(pb);
+ if (name == NULL || *name == '\0')
+ return (NULL);
- return (0);
+ pbfind.name = (char*)name;
+ return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
}
-/* Free an item by index. */
+/* Free a paste buffer by name. */
int
-paste_free_index(u_int idx)
+paste_free_name(const char *name)
{
- struct paste_buffer *pb;
+ struct paste_buffer *pb, pbfind;
+
+ if (name == NULL || *name == '\0')
+ return (-1);
- if (idx >= ARRAY_LENGTH(&paste_buffers))
+ pbfind.name = (char*)name;
+ pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind);
+ if (pb == NULL)
return (-1);
- pb = ARRAY_ITEM(&paste_buffers, idx);
- ARRAY_REMOVE(&paste_buffers, idx);
+ RB_REMOVE(paste_name_tree, &paste_by_name, pb);
+ RB_REMOVE(paste_time_tree, &paste_by_time, pb);
+ if (pb->automatic)
+ paste_num_automatic--;
free(pb->data);
+ free(pb->name);
free(pb);
-
return (0);
}
/*
- * Add an item onto the top of the stack, freeing the bottom if at limit. Note
+ * Add an automatic buffer, freeing the oldest automatic item if at limit. Note
* that the caller is responsible for allocating data.
*/
void
-paste_add(char *data, size_t size, u_int limit)
+paste_add(char *data, size_t size)
{
- struct paste_buffer *pb;
+ struct paste_buffer *pb, *pb1;
+ u_int limit;
if (size == 0)
return;
- while (ARRAY_LENGTH(&paste_buffers) >= limit) {
- pb = ARRAY_LAST(&paste_buffers);
- free(pb->data);
- free(pb);
- ARRAY_TRUNC(&paste_buffers, 1);
+ limit = options_get_number(&global_options, "buffer-limit");
+ RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
+ if (paste_num_automatic < limit)
+ break;
+ if (pb->automatic)
+ paste_free_name(pb->name);
}
pb = xmalloc(sizeof *pb);
- ARRAY_INSERT(&paste_buffers, 0, pb);
+
+ pb->name = NULL;
+ do {
+ free(pb->name);
+ xasprintf(&pb->name, "buffer%04u", paste_next_index);
+ paste_next_index++;
+ } while (paste_get_name(pb->name) != NULL);
pb->data = data;
pb->size = size;
+
+ pb->automatic = 1;
+ paste_num_automatic++;
+
+ pb->order = paste_next_order++;
+ RB_INSERT(paste_name_tree, &paste_by_name, pb);
+ RB_INSERT(paste_time_tree, &paste_by_time, pb);
}
+/* Rename a paste buffer. */
+int
+paste_rename(const char *oldname, const char *newname, char **cause)
+{
+ struct paste_buffer *pb;
+
+ if (cause != NULL)
+ *cause = NULL;
+
+ if (oldname == NULL || *oldname == '\0') {
+ if (cause != NULL)
+ *cause = xstrdup("no buffer");
+ return (-1);
+ }
+ if (newname == NULL || *newname == '\0') {
+ if (cause != NULL)
+ *cause = xstrdup("new name is empty");
+ return (-1);
+ }
+
+ pb = paste_get_name(oldname);
+ if (pb == NULL) {
+ if (cause != NULL)
+ xasprintf(cause, "no buffer %s", oldname);
+ return (-1);
+ }
+
+ RB_REMOVE(paste_name_tree, &paste_by_name, pb);
+
+ free(pb->name);
+ pb->name = xstrdup(newname);
+
+ if (pb->automatic)
+ paste_num_automatic--;
+ pb->automatic = 0;
+
+ RB_INSERT(paste_name_tree, &paste_by_name, pb);
+
+ return (0);
+}
/*
- * Replace an item on the stack. Note that the caller is responsible for
+ * Add or replace an item in the store. Note that the caller is responsible for
* allocating data.
*/
int
-paste_replace(u_int idx, char *data, size_t size)
+paste_set(char *data, size_t size, const char *name, char **cause)
{
struct paste_buffer *pb;
+ if (cause != NULL)
+ *cause = NULL;
+
if (size == 0) {
free(data);
return (0);
}
+ if (name == NULL) {
+ paste_add(data, size);
+ return (0);
+ }
- if (idx >= ARRAY_LENGTH(&paste_buffers))
+ if (*name == '\0') {
+ if (cause != NULL)
+ *cause = xstrdup("empty buffer name");
return (-1);
+ }
- pb = ARRAY_ITEM(&paste_buffers, idx);
- free(pb->data);
+ pb = paste_get_name(name);
+ if (pb != NULL)
+ paste_free_name(name);
+
+ pb = xmalloc(sizeof *pb);
+
+ pb->name = xstrdup(name);
pb->data = data;
pb->size = size;
+ pb->automatic = 0;
+ pb->order = paste_next_order++;
+
+ RB_INSERT(paste_name_tree, &paste_by_name, pb);
+ RB_INSERT(paste_time_tree, &paste_by_time, pb);
+
return (0);
}
diff --git a/session.c b/session.c
index ae6f35c9..2bcb1b98 100644
--- a/session.c
+++ b/session.c
@@ -84,11 +84,12 @@ session_find_by_id(u_int id)
/* Create a new session. */
struct session *
-session_create(const char *name, const char *cmd, const char *path, int cwd,
- struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy,
- char **cause)
+session_create(const char *name, int argc, char **argv, const char *path,
+ int cwd, struct environ *env, struct termios *tio, int idx, u_int sx,
+ u_int sy, char **cause)
{
struct session *s;
+ struct winlink *wl;
s = xmalloc(sizeof *s);
s->references = 0;
@@ -131,8 +132,9 @@ session_create(const char *name, const char *cmd, const char *path, int cwd,
}
RB_INSERT(sessions, &sessions, s);
- if (cmd != NULL) {
- if (session_new(s, NULL, cmd, path, cwd, idx, cause) == NULL) {
+ if (argc >= 0) {
+ wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause);
+ if (wl == NULL) {
session_destroy(s);
return (NULL);
}
@@ -226,7 +228,7 @@ session_previous_session(struct session *s)
/* Create a new window on a session. */
struct winlink *
-session_new(struct session *s, const char *name, const char *cmd,
+session_new(struct session *s, const char *name, int argc, char **argv,
const char *path, int cwd, int idx, char **cause)
{
struct window *w;
@@ -250,8 +252,8 @@ session_new(struct session *s, const char *name, const char *cmd,
shell = _PATH_BSHELL;
hlimit = options_get_number(&s->options, "history-limit");
- w = window_create(name, cmd, path, shell, cwd, &env, s->tio, s->sx,
- s->sy, hlimit, cause);
+ w = window_create(name, argc, argv, path, shell, cwd, &env, s->tio,
+ s->sx, s->sy, hlimit, cause);
if (w == NULL) {
winlink_remove(&s->windows, wl);
environ_free(&env);
diff --git a/style.c b/style.c
index 99744086..2a049fb6 100644
--- a/style.c
+++ b/style.c
@@ -117,7 +117,7 @@ style_tostring(struct grid_cell *gc)
*s = '\0';
- if (gc->fg != 8) {
+ if (gc->fg != 8 || gc->flags & GRID_FLAG_FG256) {
if (gc->flags & GRID_FLAG_FG256)
c = gc->fg | 0x100;
else
@@ -126,7 +126,7 @@ style_tostring(struct grid_cell *gc)
comma = 1;
}
- if (gc->bg != 8) {
+ if (gc->bg != 8 || gc->flags & GRID_FLAG_BG256) {
if (gc->flags & GRID_FLAG_BG256)
c = gc->bg | 0x100;
else
@@ -221,13 +221,13 @@ style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
struct grid_cell *gcp;
gcp = options_get_style(oo, name);
- if (gcp->fg != 8) {
+ if (gcp->fg != 8 || gcp->flags & GRID_FLAG_FG256) {
if (gcp->flags & GRID_FLAG_FG256)
colour_set_fg(gc, gcp->fg | 0x100);
else
colour_set_fg(gc, gcp->fg);
}
- if (gcp->bg != 8) {
+ if (gcp->bg != 8 || gcp->flags & GRID_FLAG_BG256) {
if (gcp->flags & GRID_FLAG_BG256)
colour_set_bg(gc, gcp->bg | 0x100);
else
diff --git a/tmux.1 b/tmux.1
index c05eacfd..30447edb 100644
--- a/tmux.1
+++ b/tmux.1
@@ -482,12 +482,37 @@ It may be used alone to target a pane or the window containing it.
arguments are
.Xr sh 1
commands.
-These must be passed as a single item, which typically means quoting them, for
-example:
+This may be a single argument passed to the shell, for example:
.Bd -literal -offset indent
new-window 'vi /etc/passwd'
.Ed
.Pp
+Will run:
+.Bd -literal -offset indent
+/bin/sh -c 'vi /etc/passwd'
+.Ed
+.Pp
+Additionally, the
+.Ic new-window ,
+.Ic new-session ,
+.Ic split-window ,
+.Ic respawn-window
+and
+.Ic respawn-pane
+commands allow
+.Ar shell-command
+to be given as multiple arguments and executed directly (without
+.Ql sh -c ) .
+This can avoid issues with shell quoting.
+For example:
+.Bd -literal -offset indent
+$ tmux new-window vi /etc/passwd
+.Ed
+.Pp
+Will run
+.Xr vi 1
+directly without invoking the shell.
+.Pp
.Ar command
.Op Ar arguments
refers to a
@@ -853,6 +878,7 @@ The following keys are supported as appropriate for the mode:
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Append selection" Ta "A" Ta ""
.It Li "Back to indentation" Ta "^" Ta "M-m"
+.It Li "Copy to named buffer" Ta \&" Ta ""
.It Li "Bottom of history" Ta "G" Ta "M-<"
.It Li "Clear selection" Ta "Escape" Ta "C-g"
.It Li "Copy selection" Ta "Enter" Ta "M-w"
@@ -934,9 +960,6 @@ in emacs mode, and
.Ql 10w
in vi.
.Pp
-When copying the selection, the repeat count indicates the buffer index to
-replace, if used.
-.Pp
Mode key bindings are defined in a set of named tables:
.Em vi-edit
and
@@ -1094,7 +1117,7 @@ but a different format may be specified with
.Fl F .
.It Xo Ic capture-pane
.Op Fl aepPq
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
.Op Fl E Ar end-line
.Op Fl S Ar start-line
.Op Fl t Ar target-pane
@@ -3371,19 +3394,40 @@ is given, otherwise the active pane for the session attached to
.El
.Sh BUFFERS
.Nm
-maintains a stack of
+maintains a set of named
.Em paste buffers .
-Up to the value of the
+Each buffer may be either explicitly or automatically named.
+Explicitly named buffers are named when created with the
+.Ic set-buffer
+or
+.Ic load-buffer
+commands, or by renaming an automatically named buffer with
+.Ic set-buffer
+.Fl n .
+Automatically named buffers are given a name such as
+.Ql buffer0001 ,
+.Ql buffer0002
+and so on.
+When the
+.Ic buffer-limit
+option is reached, the oldest automatically named buffer is deleted.
+Explicitly named are not subject to
.Ic buffer-limit
-option are kept; when a new buffer is added, the buffer at the bottom of the
-stack is removed.
+and may be deleted with
+.Ic delete-buffer
+command.
+.Pp
Buffers may be added using
.Ic copy-mode
or the
.Ic set-buffer
-command, and pasted into a window using the
+and
+.Ic load-buffer
+commands, and pasted into a window using the
.Ic paste-buffer
command.
+If a buffer command is used and no buffer is specified, the most
+recently added automatically named buffer is assumed.
.Pp
A configurable history buffer is also maintained for each window.
By default, up to 2000 lines are kept; this can be altered with the
@@ -3404,7 +3448,7 @@ Put a window into buffer choice mode, where a buffer may be chosen
interactively from a list.
After a buffer is selected,
.Ql %%
-is replaced by the buffer index in
+is replaced by the buffer name in
.Ar template
and the result executed as a command.
If
@@ -3419,11 +3463,11 @@ This command works only if at least one client is attached.
.It Ic clear-history Op Fl t Ar target-pane
.D1 (alias: Ic clearhist )
Remove and free the history for the specified pane.
-.It Ic delete-buffer Op Fl b Ar buffer-index
+.It Ic delete-buffer Op Fl b Ar buffer-name
.D1 (alias: Ic deleteb )
-Delete the buffer at
-.Ar buffer-index ,
-or the top buffer if not specified.
+Delete the buffer named
+.Ar buffer-name ,
+or the most recently added automatically named buffer if not specified.
.It Xo Ic list-buffers
.Op Fl F Ar format
.Xc
@@ -3435,7 +3479,7 @@ flag, see the
.Sx FORMATS
section.
.It Xo Ic load-buffer
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
.Ar path
.Xc
.D1 (alias: Ic loadb )
@@ -3443,7 +3487,7 @@ Load the contents of the specified paste buffer from
.Ar path .
.It Xo Ic paste-buffer
.Op Fl dpr
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
.Op Fl s Ar separator
.Op Fl t Ar target-pane
.Xc
@@ -3452,7 +3496,7 @@ Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one.
With
.Fl d ,
-also delete the paste buffer from the stack.
+also delete the paste buffer.
When output, any linefeed (LF) characters in the paste buffer are replaced with
a separator, by default carriage return (CR).
A custom separator may be specified using the
@@ -3467,7 +3511,7 @@ is specified, paste bracket control codes are inserted around the
buffer if the application has requested bracketed paste mode.
.It Xo Ic save-buffer
.Op Fl a
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
.Ar path
.Xc
.D1 (alias: Ic saveb )
@@ -3478,7 +3522,8 @@ The
option appends to rather than overwriting the file.
.It Xo Ic set-buffer
.Op Fl a
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
+.Op Fl n Ar new-buffer-name
.Ar data
.Xc
.D1 (alias: Ic setb )
@@ -3487,8 +3532,12 @@ Set the contents of the specified buffer to
The
.Fl a
option appends to rather than overwriting the buffer.
+The
+.Fl n
+option renames the buffer to
+.Ar new-buffer-name .
.It Xo Ic show-buffer
-.Op Fl b Ar buffer-index
+.Op Fl b Ar buffer-name
.Xc
.D1 (alias: Ic showb )
Display the contents of the specified buffer.
diff --git a/tmux.h b/tmux.h
index fde94afc..1f80f41f 100644
--- a/tmux.h
+++ b/tmux.h
@@ -82,7 +82,7 @@ extern char **environ;
/* Default template for choose-buffer. */
#define CHOOSE_BUFFER_TEMPLATE \
- "#{line}: #{buffer_size} bytes: #{buffer_sample}"
+ "#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
/* Default template for choose-client. */
#define CHOOSE_CLIENT_TEMPLATE \
@@ -115,7 +115,8 @@ extern char **environ;
/* Default template for list-buffers. */
#define LIST_BUFFERS_TEMPLATE \
- "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\""
+ "#{buffer_name}: #{buffer_size} bytes: " \
+ "\"#{buffer_sample}\""
/* Default template for list-clients. */
#define LIST_CLIENTS_TEMPLATE \
@@ -579,6 +580,7 @@ enum mode_key_cmd {
MODEKEYCOPY_SEARCHREVERSE,
MODEKEYCOPY_SEARCHUP,
MODEKEYCOPY_SELECTLINE,
+ MODEKEYCOPY_STARTNAMEDBUFFER,
MODEKEYCOPY_STARTNUMBERPREFIX,
MODEKEYCOPY_STARTOFLINE,
MODEKEYCOPY_STARTSELECTION,
@@ -889,6 +891,7 @@ struct window_choose_mode_item {
/* Child window structure. */
struct window_pane {
u_int id;
+ u_int active_point;
struct window *window;
@@ -908,7 +911,8 @@ struct window_pane {
#define PANE_RESIZE 0x8
#define PANE_FOCUSPUSH 0x10
- char *cmd;
+ int argc;
+ char **argv;
char *shell;
int cwd;
@@ -945,6 +949,7 @@ struct window_pane {
};
TAILQ_HEAD(window_panes, window_pane);
RB_HEAD(window_pane_tree, window_pane);
+ARRAY_DECL(window_pane_list, struct window_pane *);
/* Window structure. */
struct window {
@@ -1022,8 +1027,6 @@ struct layout_cell {
u_int yoff;
struct window_pane *wp;
- struct window_pane *lastwp;
-
struct layout_cells cells;
TAILQ_ENTRY(layout_cell) entry;
@@ -1033,6 +1036,13 @@ struct layout_cell {
struct paste_buffer {
char *data;
size_t size;
+
+ char *name;
+ int automatic;
+ u_int order;
+
+ RB_ENTRY(paste_buffer) name_entry;
+ RB_ENTRY(paste_buffer) time_entry;
};
/* Environment variable. */
@@ -1127,6 +1137,9 @@ LIST_HEAD(tty_terms, tty_term);
#define MOUSE_WHEEL_UP 0
#define MOUSE_WHEEL_DOWN 1
+/* Mouse wheel multipler. */
+#define MOUSE_WHEEL_SCALE 3
+
/* Mouse event bits. */
#define MOUSE_EVENT_DOWN 0x1
#define MOUSE_EVENT_DRAG 0x2
@@ -1493,7 +1506,7 @@ RB_HEAD(format_tree, format_entry);
#define CMD_SRCDST_WINDOW_USAGE "[-s src-window] [-t dst-window]"
#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]"
-#define CMD_BUFFER_USAGE "[-b buffer-index]"
+#define CMD_BUFFER_USAGE "[-b buffer-name]"
/* tmux.c */
extern struct options global_options;
@@ -1705,13 +1718,14 @@ void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *);
/* paste.c */
-struct paste_buffer *paste_walk_stack(u_int *);
+struct paste_buffer *paste_walk(struct paste_buffer *);
struct paste_buffer *paste_get_top(void);
-struct paste_buffer *paste_get_index(u_int);
+struct paste_buffer *paste_get_name(const char *);
int paste_free_top(void);
-int paste_free_index(u_int);
-void paste_add(char *, size_t, u_int);
-int paste_replace(u_int, char *, size_t);
+int paste_free_name(const char *);
+void paste_add(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 *, int);
void paste_send_pane(struct paste_buffer *, struct window_pane *,
const char *, int);
@@ -1732,8 +1746,9 @@ long long args_strtonum(
/* cmd.c */
int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***);
-char **cmd_copy_argv(int, char *const *);
+char **cmd_copy_argv(int, char **);
void cmd_free_argv(int, char **);
+char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
size_t cmd_print(struct cmd *, char *, size_t);
struct session *cmd_current_session(struct cmd_q *, int);
@@ -2124,7 +2139,7 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *);
int window_index(struct window *, u_int *);
struct window *window_find_by_id(u_int);
struct window *window_create1(u_int, u_int);
-struct window *window_create(const char *, const char *, const char *,
+struct window *window_create(const char *, int, char **, const char *,
const char *, int, struct environ *, struct termios *,
u_int, u_int, u_int, char **);
void window_destroy(struct window *);
@@ -2150,7 +2165,7 @@ struct window_pane *window_pane_find_by_id(u_int);
struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int);
void window_pane_destroy(struct window_pane *);
void window_pane_timer_start(struct window_pane *);
-int window_pane_spawn(struct window_pane *, const char *,
+int window_pane_spawn(struct window_pane *, int, char **,
const char *, const char *, int, struct environ *,
struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
@@ -2288,18 +2303,18 @@ RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *);
struct session *session_find(const char *);
struct session *session_find_by_id(u_int);
-struct session *session_create(const char *, const char *, const char *, int,
- struct environ *, struct termios *, int, u_int, u_int,
- char **);
+struct session *session_create(const char *, int, char **, const char *,
+ int, struct environ *, struct termios *, int, u_int,
+ u_int, char **);
void session_destroy(struct session *);
int session_check_name(const char *);
void session_update_activity(struct session *);
struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *);
-struct winlink *session_new(struct session *, const char *, const char *,
+struct winlink *session_new(struct session *, const char *, int, char **,
const char *, int, int, char **);
-struct winlink *session_attach(
- struct session *, struct window *, int, char **);
+struct winlink *session_attach(struct session *, struct window *, int,
+ char **);
int session_detach(struct session *, struct winlink *);
struct winlink *session_has(struct session *, struct window *);
int session_next(struct session *, int);
diff --git a/tty-keys.c b/tty-keys.c
index 42f2da40..37b89600 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -752,11 +752,11 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
if (b & MOUSE_MASK_SHIFT)
m->scroll = 1;
else
- m->scroll = 3;
+ m->scroll = MOUSE_WHEEL_SCALE;
if (b & MOUSE_MASK_META)
- m->scroll *= 3;
+ m->scroll *= MOUSE_WHEEL_SCALE;
if (b & MOUSE_MASK_CTRL)
- m->scroll *= 3;
+ m->scroll *= MOUSE_WHEEL_SCALE;
b &= MOUSE_MASK_BUTTONS;
if (b == 0)
diff --git a/window-choose.c b/window-choose.c
index 86f37ed5..23e77b32 100644
--- a/window-choose.c
+++ b/window-choose.c
@@ -721,17 +721,22 @@ window_choose_mouse(struct window_pane *wp, struct session *sess,
struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct window_choose_mode_item *item;
- u_int idx;
+ u_int idx, i, n;
if (m->event == MOUSE_EVENT_WHEEL) {
/*
- * Don't use m->scroll and just move line-by-line or it's
- * annoying.
+ * Multiple line scrolling by default is annoying, so scale
+ * m->scroll back down.
*/
- if (m->wheel == MOUSE_WHEEL_UP)
- window_choose_key(wp, sess, KEYC_UP);
- else
- window_choose_key(wp, sess, KEYC_DOWN);
+ n = m->scroll;
+ if (n >= MOUSE_WHEEL_SCALE)
+ n /= MOUSE_WHEEL_SCALE;
+ for (i = 0; i < n; i++) {
+ if (m->wheel == MOUSE_WHEEL_UP)
+ window_choose_key(wp, sess, KEYC_UP);
+ else
+ window_choose_key(wp, sess, KEYC_DOWN);
+ }
return;
}
diff --git a/window-copy.c b/window-copy.c
index 508001d3..ac29e6d9 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -54,14 +54,15 @@ void window_copy_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *);
int window_copy_update_selection(struct window_pane *, int);
void *window_copy_get_selection(struct window_pane *, size_t *);
-void window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
-void window_copy_copy_pipe(
- struct window_pane *, struct session *, int, const char *);
-void window_copy_copy_selection(struct window_pane *, int);
-void window_copy_append_selection(struct window_pane *, int);
+void window_copy_copy_buffer(struct window_pane *, const char *, void *,
+ size_t);
+void window_copy_copy_pipe(struct window_pane *, struct session *,
+ const char *, const char *);
+void window_copy_copy_selection(struct window_pane *, const char *);
+void window_copy_append_selection(struct window_pane *, const char *);
void window_copy_clear_selection(struct window_pane *);
-void window_copy_copy_line(
- struct window_pane *, char **, size_t *, u_int, u_int, u_int);
+void window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
+ u_int, u_int);
int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
u_int window_copy_find_length(struct window_pane *, u_int);
void window_copy_cursor_start_of_line(struct window_pane *);
@@ -94,6 +95,7 @@ const struct window_mode window_copy_mode = {
enum window_copy_input_type {
WINDOW_COPY_OFF,
+ WINDOW_COPY_NAMEDBUFFER,
WINDOW_COPY_NUMERICPREFIX,
WINDOW_COPY_SEARCHUP,
WINDOW_COPY_SEARCHDOWN,
@@ -417,7 +419,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
switch (cmd) {
case MODEKEYCOPY_APPENDSELECTION:
if (sess != NULL) {
- window_copy_append_selection(wp, data->numprefix);
+ window_copy_append_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@@ -543,7 +545,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
if (sess != NULL &&
(cmd == MODEKEYCOPY_COPYLINE ||
cmd == MODEKEYCOPY_COPYENDOFLINE)) {
- window_copy_copy_selection(wp, -1);
+ window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@@ -554,14 +556,14 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
break;
case MODEKEYCOPY_COPYPIPE:
if (sess != NULL) {
- window_copy_copy_pipe(wp, sess, data->numprefix, arg);
+ window_copy_copy_pipe(wp, sess, NULL, arg);
window_pane_reset_mode(wp);
return;
}
break;
case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) {
- window_copy_copy_selection(wp, data->numprefix);
+ window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
return;
}
@@ -676,6 +678,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_JUMPTOFORWARD:
case WINDOW_COPY_JUMPTOBACK:
+ case WINDOW_COPY_NAMEDBUFFER:
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
@@ -711,6 +714,11 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
data->inputprompt = "Goto Line";
*data->inputstr = '\0';
goto input_on;
+ case MODEKEYCOPY_STARTNAMEDBUFFER:
+ data->inputtype = WINDOW_COPY_NAMEDBUFFER;
+ data->inputprompt = "Buffer";
+ *data->inputstr = '\0';
+ goto input_on;
case MODEKEYCOPY_STARTNUMBERPREFIX:
key &= KEYC_MASK_KEY;
if (key >= '0' && key <= '9') {
@@ -814,6 +822,11 @@ window_copy_key_input(struct window_pane *wp, int key)
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
break;
+ case WINDOW_COPY_NAMEDBUFFER:
+ window_copy_copy_selection(wp, data->inputstr);
+ *data->inputstr = '\0';
+ window_pane_reset_mode(wp);
+ return (0);
case WINDOW_COPY_GOTOLINE:
window_copy_goto_line(wp, data->inputstr);
*data->inputstr = '\0';
@@ -918,7 +931,7 @@ reset_mode:
s->mode &= ~MODE_MOUSE_BUTTON;
s->mode |= MODE_MOUSE_STANDARD;
if (sess != NULL) {
- window_copy_copy_selection(wp, -1);
+ window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp);
}
}
@@ -1452,9 +1465,9 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
}
void
-window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
+window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf,
+ size_t len)
{
- u_int limit;
struct screen_write_ctx ctx;
if (options_get_number(&global_options, "set-clipboard")) {
@@ -1463,16 +1476,13 @@ window_copy_copy_buffer(struct window_pane *wp, int idx, void *buf, size_t len)
screen_write_stop(&ctx);
}
- if (idx == -1) {
- limit = options_get_number(&global_options, "buffer-limit");
- paste_add(buf, len, limit);
- } else if (paste_replace(idx, buf, len) != 0)
+ if (paste_set(buf, len, bufname, NULL) != 0)
free(buf);
}
void
-window_copy_copy_pipe(
- struct window_pane *wp, struct session *sess, int idx, const char *arg)
+window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
+ const char *bufname, const char *arg)
{
void *buf;
size_t len;
@@ -1486,11 +1496,11 @@ window_copy_copy_pipe(
job = job_run(arg, sess, NULL, NULL, NULL);
bufferevent_write(job->event, buf, len);
- window_copy_copy_buffer(wp, idx, buf, len);
+ window_copy_copy_buffer(wp, bufname, buf, len);
}
void
-window_copy_copy_selection(struct window_pane *wp, int idx)
+window_copy_copy_selection(struct window_pane *wp, const char *bufname)
{
void* buf;
size_t len;
@@ -1499,17 +1509,16 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
if (buf == NULL)
return;
- window_copy_copy_buffer(wp, idx, buf, len);
+ window_copy_copy_buffer(wp, bufname, buf, len);
}
void
-window_copy_append_selection(struct window_pane *wp, int idx)
+window_copy_append_selection(struct window_pane *wp, const char *bufname)
{
- char *buf;
- struct paste_buffer *pb;
- size_t len;
- u_int limit;
- struct screen_write_ctx ctx;
+ char *buf;
+ struct paste_buffer *pb;
+ size_t len;
+ struct screen_write_ctx ctx;
buf = window_copy_get_selection(wp, &len);
if (buf == NULL)
@@ -1521,24 +1530,19 @@ window_copy_append_selection(struct window_pane *wp, int idx)
screen_write_stop(&ctx);
}
- if (idx == -1)
- idx = 0;
-
- if (idx == 0 && paste_get_top() == NULL) {
- limit = options_get_number(&global_options, "buffer-limit");
- paste_add(buf, len, limit);
- return;
- }
-
- pb = paste_get_index(idx);
+ if (bufname == NULL || *bufname == '\0') {
+ pb = paste_get_top();
+ if (pb != NULL)
+ bufname = pb->name;
+ } else
+ pb = paste_get_name(bufname);
if (pb != NULL) {
buf = xrealloc(buf, 1, len + pb->size);
memmove(buf + pb->size, buf, len);
memcpy(buf, pb->data, pb->size);
len += pb->size;
}
-
- if (paste_replace(idx, buf, len) != 0)
+ if (paste_set(buf, len, bufname, NULL) != 0)
free(buf);
}
diff --git a/window.c b/window.c
index ee851bde..d65bf503 100644
--- a/window.c
+++ b/window.c
@@ -55,15 +55,14 @@ struct windows windows;
struct window_pane_tree all_window_panes;
u_int next_window_pane_id;
u_int next_window_id;
-
-struct window_pane *window_pane_active_set(struct window_pane *,
- struct window_pane *);
-void window_pane_active_lost(struct window_pane *, struct window_pane *);
+u_int next_active_point;
void window_pane_timer_callback(int, short, void *);
void window_pane_read_callback(struct bufferevent *, void *);
void window_pane_error_callback(struct bufferevent *, short, void *);
+struct window_pane *window_pane_choose_best(struct window_pane_list *);
+
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
int
@@ -307,7 +306,7 @@ window_create1(u_int sx, u_int sy)
}
struct window *
-window_create(const char *name, const char *cmd, const char *path,
+window_create(const char *name, int argc, char **argv, const char *path,
const char *shell, int cwd, struct environ *env, struct termios *tio,
u_int sx, u_int sy, u_int hlimit, char **cause)
{
@@ -318,7 +317,7 @@ window_create(const char *name, const char *cmd, const char *path,
wp = window_add_pane(w, hlimit);
layout_init(w, wp);
- if (window_pane_spawn(wp, cmd, path, shell, cwd, env, tio,
+ if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
cause) != 0) {
window_destroy(w);
return (NULL);
@@ -386,64 +385,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
w->sy = sy;
}
-/*
- * Restore previously active pane when changing from wp to nextwp. The intended
- * pane is in nextwp and it returns the previously focused pane.
- */
-struct window_pane *
-window_pane_active_set(struct window_pane *wp, struct window_pane *nextwp)
-{
- struct layout_cell *lc;
- struct window_pane *lastwp;
-
- /* Target pane's parent must not be an ancestor of source pane. */
- for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
- if (lc == nextwp->layout_cell->parent)
- return (nextwp);
- }
-
- /*
- * Previously active pane, if any, must not be the same as the source
- * pane.
- */
- lc = nextwp->layout_cell->parent;
- if (lc != NULL && lc->lastwp != NULL) {
- lastwp = lc->lastwp;
- if (lastwp != wp && window_pane_visible(lastwp))
- return (lastwp);
- }
- return (nextwp);
-}
-
-/* Remember previously active pane when changing from wp to nextwp. */
-void
-window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp)
-{
- struct layout_cell *lc, *lc2, *lcparent;
-
- /* Get the parent cell. */
- lcparent = nextwp->layout_cell->parent;
- if (lcparent == NULL)
- return;
-
- /* Save the target pane in its parent. */
- lcparent->lastwp = nextwp;
-
- /*
- * Save the source pane in all of its parents up to, but not including,
- * the common ancestor of itself and the target panes.
- */
- if (wp == NULL)
- return;
- for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) {
- for (lc2 = lcparent; lc2 != NULL; lc2 = lc2->parent) {
- if (lc == lc2)
- return;
- }
- lc->lastwp = wp;
- }
-}
-
void
window_set_active_pane(struct window *w, struct window_pane *wp)
{
@@ -451,7 +392,6 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
return;
w->last = w->active;
w->active = wp;
- window_pane_active_lost(w->last, wp);
while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL)
@@ -459,6 +399,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
if (w->active == wp)
return;
}
+ w->active->active_point = next_active_point++;
}
struct window_pane *
@@ -736,7 +677,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp);
- wp->cmd = NULL;
+ wp->argc = 0;
+ wp->argv = NULL;
wp->shell = NULL;
wp->cwd = -1;
@@ -770,16 +712,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
void
window_pane_destroy(struct window_pane *wp)
{
- struct window_pane *wp2;
-
- /* Forget removed pane in all layout cells that remember it. */
- RB_FOREACH(wp2, window_pane_tree, &all_window_panes) {
- if (wp2->layout_cell != NULL &&
- wp2->layout_cell->parent != NULL &&
- wp2->layout_cell->parent->lastwp == wp)
- wp2->layout_cell->parent->lastwp = NULL;
- }
-
window_pane_reset_mode(wp);
if (event_initialized(&wp->changes_timer))
@@ -808,30 +740,32 @@ window_pane_destroy(struct window_pane *wp)
close(wp->cwd);
free(wp->shell);
- free(wp->cmd);
+ cmd_free_argv(wp->argc, wp->argv);
free(wp);
}
int
-window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
- const char *shell, int cwd, struct environ *env, struct termios *tio,
- char **cause)
+window_pane_spawn(struct window_pane *wp, int argc, char **argv,
+ const char *path, const char *shell, int cwd, struct environ *env,
+ struct termios *tio, char **cause)
{
struct winsize ws;
- char *argv0, paneid[16];
- const char *ptr;
+ char *argv0, *cmd, **argvp, paneid[16];
+ const char *ptr, *first;
struct termios tio2;
#ifdef HAVE_UTEMPTER
char s[32];
#endif
+ int i;
if (wp->fd != -1) {
bufferevent_free(wp->event);
close(wp->fd);
}
- if (cmd != NULL) {
- free(wp->cmd);
- wp->cmd = xstrdup(cmd);
+ 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);
@@ -842,7 +776,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
wp->cwd = dup(cwd);
}
- log_debug("spawn: %s -- %s", wp->shell, wp->cmd);
+ cmd = cmd_stringify_argv(wp->argc, wp->argv);
+ log_debug("spawn: %s -- %s", wp->shell, cmd);
+ for (i = 0; i < wp->argc; i++)
+ log_debug("spawn: argv[%d] = %s", i, wp->argv[i]);
memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base);
@@ -852,6 +789,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
case -1:
wp->fd = -1;
xasprintf(cause, "%s: %s", cmd, strerror(errno));
+ free(cmd);
return (-1);
case 0:
if (fchdir(wp->cwd) != 0)
@@ -883,22 +821,32 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
setenv("SHELL", wp->shell, 1);
ptr = strrchr(wp->shell, '/');
- if (*wp->cmd != '\0') {
- /* Use the command. */
+ /*
+ * 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", wp->cmd, (char *) NULL);
+ execl(wp->shell, argv0, "-c", first, (char *)NULL);
fatal("execl failed");
}
-
- /* No command; fork a login shell. */
if (ptr != NULL && *(ptr + 1) != '\0')
xasprintf(&argv0, "-%s", ptr + 1);
else
xasprintf(&argv0, "-%s", wp->shell);
- execl(wp->shell, argv0, (char *) NULL);
+ execl(wp->shell, argv0, (char *)NULL);
fatal("execl failed");
}
@@ -909,10 +857,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
setblocking(wp->fd, 0);
- wp->event = bufferevent_new(wp->fd,
- window_pane_read_callback, NULL, window_pane_error_callback, wp);
+ wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
+ window_pane_error_callback, wp);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
+ free(cmd);
return (0);
}
@@ -1201,114 +1150,198 @@ window_pane_search(struct window_pane *wp, const char *searchstr,
return (msg);
}
-/* Find the pane directly above another. */
+/* Get MRU pane from a list. */
+struct window_pane *
+window_pane_choose_best(struct window_pane_list *list)
+{
+ struct window_pane *next, *best;
+ u_int i;
+
+ if (ARRAY_LENGTH(list) == 0)
+ return (NULL);
+
+ best = ARRAY_FIRST(list);
+ for (i = 1; i < ARRAY_LENGTH(list); i++) {
+ next = ARRAY_ITEM(list, i);
+ if (next->active_point > best->active_point)
+ best = next;
+ }
+ return (best);
+}
+
+/*
+ * Find the pane directly above another. We build a list of those adjacent to
+ * top edge and then choose the best.
+ */
struct window_pane *
window_pane_find_up(struct window_pane *wp)
{
- struct window_pane *wp2;
- u_int left, top;
+ struct window_pane *next, *best;
+ u_int edge, left, right, end;
+ struct window_pane_list list;
+ int found;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
+ ARRAY_INIT(&list);
+
+ edge = wp->yoff;
+ if (edge == 0)
+ edge = wp->window->sy + 1;
- top = wp->yoff;
- if (top == 0)
- top = wp->window->sy + 1;
left = wp->xoff;
+ right = wp->xoff + wp->sx;
- TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
- if (!window_pane_visible(wp2))
+ TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ if (next == wp || !window_pane_visible(next))
continue;
- if (wp2->yoff + wp2->sy + 1 != top)
+ if (next->yoff + next->sy + 1 != edge)
continue;
- if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
- return (window_pane_active_set(wp, wp2));
+ end = next->xoff + next->sx - 1;
+
+ found = 0;
+ if (next->xoff < left && end > right)
+ found = 1;
+ else if (next->xoff >= left && next->xoff <= right)
+ found = 1;
+ else if (end >= left && end <= right)
+ found = 1;
+ if (found)
+ ARRAY_ADD(&list, next);
}
- return (NULL);
+
+ best = window_pane_choose_best(&list);
+ ARRAY_FREE(&list);
+ return (best);
}
/* Find the pane directly below another. */
struct window_pane *
window_pane_find_down(struct window_pane *wp)
{
- struct window_pane *wp2;
- u_int left, bottom;
+ struct window_pane *next, *best;
+ u_int edge, left, right, end;
+ struct window_pane_list list;
+ int found;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
+ ARRAY_INIT(&list);
+
+ edge = wp->yoff + wp->sy + 1;
+ if (edge >= wp->window->sy)
+ edge = 0;
- bottom = wp->yoff + wp->sy + 1;
- if (bottom >= wp->window->sy)
- bottom = 0;
left = wp->xoff;
+ right = wp->xoff + wp->sx;
- TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
- if (!window_pane_visible(wp2))
+ TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ if (next == wp || !window_pane_visible(next))
continue;
- if (wp2->yoff != bottom)
+ if (next->yoff != edge)
continue;
- if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx)
- return (window_pane_active_set(wp, wp2));
+ end = next->xoff + next->sx - 1;
+
+ found = 0;
+ if (next->xoff < left && end > right)
+ found = 1;
+ else if (next->xoff >= left && next->xoff <= right)
+ found = 1;
+ else if (end >= left && end <= right)
+ found = 1;
+ if (found)
+ ARRAY_ADD(&list, next);
}
- return (NULL);
+
+ best = window_pane_choose_best(&list);
+ ARRAY_FREE(&list);
+ return (best);
}
-/*
- * Find the pane directly to the left of another, adjacent to the left side and
- * containing the top edge.
- */
+/* Find the pane directly to the left of another. */
struct window_pane *
window_pane_find_left(struct window_pane *wp)
{
- struct window_pane *wp2;
- u_int left, top;
+ struct window_pane *next, *best;
+ u_int edge, top, bottom, end;
+ struct window_pane_list list;
+ int found;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
+ ARRAY_INIT(&list);
+
+ edge = wp->xoff;
+ if (edge == 0)
+ edge = wp->window->sx + 1;
- left = wp->xoff;
- if (left == 0)
- left = wp->window->sx + 1;
top = wp->yoff;
+ bottom = wp->yoff + wp->sy;
- TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
- if (!window_pane_visible(wp2))
+ TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ if (next == wp || !window_pane_visible(next))
continue;
- if (wp2->xoff + wp2->sx + 1 != left)
+ if (next->xoff + next->sx + 1 != edge)
continue;
- if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
- return (window_pane_active_set(wp, wp2));
+ end = next->yoff + next->sy - 1;
+
+ found = 0;
+ if (next->yoff < top && end > bottom)
+ found = 1;
+ else if (next->yoff >= top && next->yoff <= bottom)
+ found = 1;
+ else if (end >= top && end <= bottom)
+ found = 1;
+ if (found)
+ ARRAY_ADD(&list, next);
}
- return (NULL);
+
+ best = window_pane_choose_best(&list);
+ ARRAY_FREE(&list);
+ return (best);
}
-/*
- * Find the pane directly to the right of another, that is adjacent to the
- * right edge and including the top edge.
- */
+/* Find the pane directly to the right of another. */
struct window_pane *
window_pane_find_right(struct window_pane *wp)
{
- struct window_pane *wp2;
- u_int right, top;
+ struct window_pane *next, *best;
+ u_int edge, top, bottom, end;
+ struct window_pane_list list;
+ int found;
if (wp == NULL || !window_pane_visible(wp))
return (NULL);
+ ARRAY_INIT(&list);
+
+ edge = wp->xoff + wp->sx + 1;
+ if (edge >= wp->window->sx)
+ edge = 0;
- right = wp->xoff + wp->sx + 1;
- if (right >= wp->window->sx)
- right = 0;
top = wp->yoff;
+ bottom = wp->yoff + wp->sy;
- TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
- if (!window_pane_visible(wp2))
+ TAILQ_FOREACH(next, &wp->window->panes, entry) {
+ if (next == wp || !window_pane_visible(next))
continue;
- if (wp2->xoff != right)
+ if (next->xoff != edge)
continue;
- if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy)
- return (window_pane_active_set(wp, wp2));
+ end = next->yoff + next->sy - 1;
+
+ found = 0;
+ if (next->yoff < top && end > bottom)
+ found = 1;
+ else if (next->yoff >= top && next->yoff <= bottom)
+ found = 1;
+ else if (end >= top && end <= bottom)
+ found = 1;
+ if (found)
+ ARRAY_ADD(&list, next);
}
- return (NULL);
+
+ best = window_pane_choose_best(&list);
+ ARRAY_FREE(&list);
+ return (best);
}
/* Clear alert flags for a winlink */