Merge branch 'obsd-master'

Conflicts:
	format.c
	window.c
This commit is contained in:
Thomas Adam 2014-05-13 21:58:48 +01:00
commit bae95844d7
29 changed files with 747 additions and 486 deletions

View File

@ -38,7 +38,7 @@ char *cmd_capture_pane_history(struct args *, struct cmd_q *,
const struct cmd_entry cmd_capture_pane_entry = { const struct cmd_entry cmd_capture_pane_entry = {
"capture-pane", "capturep", "capture-pane", "capturep",
"ab:CeE:JpPqS:t:", 0, 0, "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, CMD_TARGET_PANE_USAGE,
0, 0,
NULL, NULL,
@ -165,8 +165,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c; struct client *c;
struct window_pane *wp; struct window_pane *wp;
char *buf, *cause; char *buf, *cause;
int buffer; const char *bufname;
u_int limit;
size_t len; size_t len;
if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL) if (cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp) == NULL)
@ -192,25 +191,17 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_q *cmdq)
evbuffer_add(c->stdout_data, "\n", 1); evbuffer_add(c->stdout_data, "\n", 1);
server_push_stdout(c); server_push_stdout(c);
} else { } 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); bufname = NULL;
if (cause != NULL) { if (args_has(args, 'b'))
cmdq_error(cmdq, "buffer %s", cause); bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(buf); free(buf);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (paste_replace(buffer, buf, len) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
free(buf);
return (CMD_RETURN_ERROR);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -75,19 +75,20 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
action = xstrdup("paste-buffer -b '%%'"); action = xstrdup("paste-buffer -b '%%'");
idx = 0; 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 = window_choose_data_create(TREE_OTHER, c, c->session);
cdata->idx = idx - 1; cdata->idx = idx;
cdata->ft_template = xstrdup(template); cdata->ft_template = xstrdup(template);
format_add(cdata->ft, "line", "%u", idx - 1);
format_paste_buffer(cdata->ft, pb, utf8flag); 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); cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data); free(action_data);
window_choose_add(wl->window->active, cdata); window_choose_add(wl->window->active, cdata);
idx++;
} }
free(action); free(action);

View File

@ -41,23 +41,16 @@ enum cmd_retval
cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{ {
struct args *args = self->args; struct args *args = self->args;
char *cause; const char *bufname;
int buffer;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
paste_free_top(); paste_free_top();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
bufname = args_get(args, 'b');
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); if (paste_free_name(bufname) != 0) {
if (cause != NULL) { cmdq_error(cmdq, "no buffer %s", bufname);
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);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@ -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); window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
out: out:
for (i = 0; i < ARRAY_LENGTH(&find_list); i++)
free(ARRAY_ITEM(&find_list, i).list_ctx);
ARRAY_FREE(&find_list); ARRAY_FREE(&find_list);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -44,17 +44,15 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq)
struct args *args = self->args; struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; struct format_tree *ft;
u_int idx;
char *line; char *line;
const char *template; const char *template;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE; template = LIST_BUFFERS_TEMPLATE;
idx = 0; pb = NULL;
while ((pb = paste_walk_stack(&idx)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(); ft = format_create();
format_add(ft, "line", "%u", idx - 1);
format_paste_buffer(ft, pb, 0); format_paste_buffer(ft, pb, 0);
line = format_expand(ft, template); line = format_expand(ft, template);

View File

@ -50,30 +50,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct session *s; struct session *s;
FILE *f; FILE *f;
const char *path; const char *path, *bufname;
char *pdata, *new_pdata, *cause; char *pdata, *new_pdata, *cause;
size_t psize; size_t psize;
u_int limit; int ch, error, cwd, fd;
int ch, error, buffer, *buffer_ptr, cwd, fd;
if (!args_has(args, 'b')) bufname = NULL;
buffer = -1; if (args_has(args, 'b'))
else { 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);
}
}
path = args->argv[0]; path = args->argv[0];
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
error = server_set_stdin_callback(c, cmd_load_buffer_callback, error = server_set_stdin_callback(c, cmd_load_buffer_callback,
buffer_ptr, &cause); (void*)bufname, &cause);
if (error != 0) { if (error != 0) {
cmdq_error(cmdq, "%s: %s", path, cause); cmdq_error(cmdq, "%s: %s", path, cause);
free(cause); free(cause);
@ -117,14 +106,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
fclose(f); fclose(f);
limit = options_get_number(&global_options, "buffer-limit"); if (paste_set(pdata, psize, bufname, &cause) != 0) {
if (buffer == -1) { cmdq_error(cmdq, "%s", cause);
paste_add(pdata, psize, limit);
return (CMD_RETURN_NORMAL);
}
if (paste_replace(buffer, pdata, psize) != 0) {
cmdq_error(cmdq, "no buffer %d", buffer);
free(pdata); free(pdata);
free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -140,10 +125,9 @@ error:
void void
cmd_load_buffer_callback(struct client *c, int closed, void *data) cmd_load_buffer_callback(struct client *c, int closed, void *data)
{ {
int *buffer = data; const char *bufname = data;
char *pdata; char *pdata, *cause;
size_t psize; size_t psize;
u_int limit;
if (!closed) if (!closed)
return; return;
@ -154,26 +138,21 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data)
return; return;
psize = EVBUFFER_LENGTH(c->stdin_data); psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { if (psize == 0 || (pdata = malloc(psize + 1)) == NULL)
free(data);
goto out; goto out;
}
memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0'; pdata[psize] = '\0';
evbuffer_drain(c->stdin_data, psize); evbuffer_drain(c->stdin_data, psize);
limit = options_get_number(&global_options, "buffer-limit"); if (paste_set(pdata, psize, bufname, &cause) != 0) {
if (*buffer == -1)
paste_add(pdata, psize, limit);
else if (paste_replace(*buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */ /* 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); server_push_stderr(c);
free(pdata); free(pdata);
free(cause);
} }
free(data);
out: out:
cmdq_continue(c->cmdq); cmdq_continue(c->cmdq);
} }

View File

@ -35,10 +35,10 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_session_entry = { const struct cmd_entry cmd_new_session_entry = {
"new-session", "new", "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] " "[-AdDP] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
"[command]", "[-y height] [command]",
CMD_STARTSERVER|CMD_CANTNEST, CMD_STARTSERVER|CMD_CANTNEST,
NULL, NULL,
cmd_new_session_exec cmd_new_session_exec
@ -55,8 +55,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
struct termios tio, *tiop; struct termios tio, *tiop;
const char *newname, *target, *update, *errstr, *template; const char *newname, *target, *update, *errstr, *template;
const char *path; const char *path;
char *cmd, *cause, *cp; char **argv, *cmd, *cause, *cp;
int detached, already_attached, idx, cwd, fd = -1; int detached, already_attached, idx, cwd, fd = -1;
int argc;
u_int sx, sy; u_int sx, sy;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent; struct environ_entry *envent;
@ -183,12 +184,21 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
sy = 1; sy = 1;
/* Figure out the command for the new window. */ /* Figure out the command for the new window. */
if (target != NULL) argc = -1;
cmd = NULL; argv = NULL;
else if (args->argc != 0) if (target == NULL && args->argc != 0) {
cmd = args->argv[0]; argc = args->argc;
else argv = args->argv;
} else if (target == NULL) {
cmd = options_get_string(&global_s_options, "default-command"); 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; path = NULL;
if (c != NULL && c->session == 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. */ /* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index"); idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(newname, cmd, path, cwd, &env, tiop, idx, sx, sy, s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx,
&cause); sy, &cause);
if (s == NULL) { if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause); cmdq_error(cmdq, "create session failed: %s", cause);
free(cause); free(cause);
@ -216,7 +226,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
environ_free(&env); environ_free(&env);
/* Set the initial window name if one given. */ /* 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; w = s->curw->window;
window_set_name(w, args_get(args, 'n')); window_set_name(w, args_get(args, 'n'));
options_set_number(&w->options, "automatic-rename", 0); options_set_number(&w->options, "automatic-rename", 0);

View File

@ -34,7 +34,7 @@ enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = { const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww", "new-window", "neww",
"ac:dF:kn:Pt:", 0, 1, "ac:dF:kn:Pt:", 0, -1,
"[-adkP] [-c start-directory] [-F format] [-n window-name] " "[-adkP] [-c start-directory] [-F format] [-n window-name] "
CMD_TARGET_WINDOW_USAGE " [command]", CMD_TARGET_WINDOW_USAGE " [command]",
0, 0,
@ -50,8 +50,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct winlink *wl; struct winlink *wl;
struct client *c; struct client *c;
const char *cmd, *path, *template; const char *cmd, *path, *template;
char *cause, *cp; char **argv, *cause, *cp;
int idx, last, detached, cwd, fd = -1; int argc, idx, last, detached, cwd, fd = -1;
struct format_tree *ft; struct format_tree *ft;
struct environ_entry *envent; struct environ_entry *envent;
@ -84,10 +84,19 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
} }
detached = args_has(args, 'd'); detached = args_has(args, 'd');
if (args->argc == 0) if (args->argc == 0) {
cmd = options_get_string(&s->options, "default-command"); cmd = options_get_string(&s->options, "default-command");
else if (cmd != NULL && *cmd != '\0') {
cmd = args->argv[0]; argc = 1;
argv = (char**)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
path = NULL; path = NULL;
if (cmdq->client != NULL && cmdq->client->session == 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) if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index"); 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) { if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause); cmdq_error(cmdq, "create window failed: %s", cause);
free(cause); free(cause);

View File

@ -35,7 +35,7 @@ void cmd_paste_buffer_filter(struct window_pane *,
const struct cmd_entry cmd_paste_buffer_entry = { const struct cmd_entry cmd_paste_buffer_entry = {
"paste-buffer", "pasteb", "paste-buffer", "pasteb",
"db:prs:t:", 0, 0, "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, 0,
NULL, NULL,
cmd_paste_buffer_exec cmd_paste_buffer_exec
@ -48,31 +48,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr; const char *sepstr, *bufname;
char *cause;
int buffer;
int pflag; int pflag;
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL) if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (!args_has(args, 'b')) bufname = NULL;
buffer = -1; if (args_has(args, 'b'))
else { 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 (buffer == -1) if (bufname == NULL)
pb = paste_get_top(); pb = paste_get_top();
else { else {
pb = paste_get_index(buffer); pb = paste_get_name(bufname);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer); cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
@ -91,10 +82,10 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
/* Delete the buffer if -d. */ /* Delete the buffer if -d. */
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
if (buffer == -1) if (bufname == NULL)
paste_free_top(); paste_free_top();
else else
paste_free_index(buffer); paste_free_name(bufname);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -32,7 +32,7 @@ enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_pane_entry = { const struct cmd_entry cmd_respawn_pane_entry = {
"respawn-pane", "respawnp", "respawn-pane", "respawnp",
"kt:", 0, 1, "kt:", 0, -1,
"[-k] " CMD_TARGET_PANE_USAGE " [command]", "[-k] " CMD_TARGET_PANE_USAGE " [command]",
0, 0,
NULL, NULL,
@ -48,7 +48,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct environ env; struct environ env;
const char *cmd, *path; const char *path;
char *cause; char *cause;
u_int idx; u_int idx;
struct environ_entry *envent; struct environ_entry *envent;
@ -74,11 +74,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
screen_reinit(&wp->base); screen_reinit(&wp->base);
input_init(wp); input_init(wp);
if (args->argc != 0)
cmd = args->argv[0];
else
cmd = NULL;
path = NULL; path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL) if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH"); 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) if (envent != NULL)
path = envent->value; path = envent->value;
if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio, if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
&cause) != 0) { s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn pane failed: %s", cause); cmdq_error(cmdq, "respawn pane failed: %s", cause);
free(cause); free(cause);
environ_free(&env); environ_free(&env);

View File

@ -31,7 +31,7 @@ enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_respawn_window_entry = { const struct cmd_entry cmd_respawn_window_entry = {
"respawn-window", "respawnw", "respawn-window", "respawnw",
"kt:", 0, 1, "kt:", 0, -1,
"[-k] " CMD_TARGET_WINDOW_USAGE " [command]", "[-k] " CMD_TARGET_WINDOW_USAGE " [command]",
0, 0,
NULL, NULL,
@ -47,7 +47,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
struct environ env; struct environ env;
const char *cmd, *path; const char *path;
char *cause; char *cause;
struct environ_entry *envent; struct environ_entry *envent;
@ -76,10 +76,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
window_destroy_panes(w); window_destroy_panes(w);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
window_pane_resize(wp, w->sx, w->sy); window_pane_resize(wp, w->sx, w->sy);
if (args->argc != 0)
cmd = args->argv[0];
else
cmd = NULL;
path = NULL; path = NULL;
if (cmdq->client != NULL && cmdq->client->session == 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) if (envent != NULL)
path = envent->value; path = envent->value;
if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio, if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env,
&cause) != 0) { s->tio, &cause) != 0) {
cmdq_error(cmdq, "respawn window failed: %s", cause); cmdq_error(cmdq, "respawn window failed: %s", cause);
free(cause); free(cause);
environ_free(&env); environ_free(&env);

View File

@ -58,10 +58,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client; struct client *c = cmdq->client;
struct session *s; struct session *s;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *path; const char *path, *bufname;
char *cause, *start, *end, *msg; char *start, *end, *msg;
size_t size, used, msglen; size_t size, used, msglen;
int cwd, fd, buffer; int cwd, fd;
FILE *f; FILE *f;
if (!args_has(args, 'b')) { if (!args_has(args, 'b')) {
@ -70,16 +70,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); bufname = args_get(args, 'b');
if (cause != NULL) { pb = paste_get_name(bufname);
cmdq_error(cmdq, "buffer %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
pb = paste_get_index(buffer);
if (pb == NULL) { if (pb == NULL) {
cmdq_error(cmdq, "no buffer %d", buffer); cmdq_error(cmdq, "no buffer %s", bufname);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }

View File

@ -31,8 +31,8 @@ enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_set_buffer_entry = { const struct cmd_entry cmd_set_buffer_entry = {
"set-buffer", "setb", "set-buffer", "setb",
"ab:", 1, 1, "ab:n:", 0, 1,
"[-a] " CMD_BUFFER_USAGE " data", "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
0, 0,
NULL, NULL,
cmd_set_buffer_exec 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 args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
u_int limit;
char *pdata, *cause; char *pdata, *cause;
const char *bufname;
size_t psize, newsize; 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; psize = 0;
pdata = NULL; pdata = NULL;
pb = NULL; pb = NULL;
buffer = -1;
if ((newsize = strlen(args->argv[0])) == 0) if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'b')) { if (args_has(args, 'b')) {
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); bufname = args_get(args, 'b');
if (cause != NULL) { pb = paste_get_name(bufname);
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);
}
} else if (args_has(args, 'a')) { } else if (args_has(args, 'a')) {
pb = paste_get_top(); pb = paste_get_top();
if (pb != NULL) if (pb != NULL)
buffer = 0; bufname = pb->name;
} }
if (args_has(args, 'a') && pb != NULL) { 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); memcpy(pdata + psize, args->argv[0], newsize);
psize += newsize; psize += newsize;
if (buffer == -1) if (paste_set(pdata, psize, bufname, &cause) != 0) {
paste_add(pdata, psize, limit); cmdq_error(cmdq, "%s", cause);
else free(pdata);
paste_replace(buffer, pdata, psize); free(cause);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -35,7 +35,7 @@ enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_split_window_entry = { const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw", "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] " "[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
CMD_TARGET_PANE_USAGE " [command]", CMD_TARGET_PANE_USAGE " [command]",
0, 0,
@ -61,9 +61,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp, *new_wp = NULL; struct window_pane *wp, *new_wp = NULL;
struct environ env; struct environ env;
const char *cmd, *path, *shell, *template; const char *cmd, *path, *shell, *template;
char *cause, *new_cause, *cp; char **argv, *cause, *new_cause, *cp;
u_int hlimit; u_int hlimit;
int size, percentage, cwd, fd = -1; int argc, size, percentage, cwd, fd = -1;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct client *c; struct client *c;
@ -80,10 +80,19 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
environ_copy(&s->environ, &env); environ_copy(&s->environ, &env);
server_fill_environ(s, &env); server_fill_environ(s, &env);
if (args->argc == 0) if (args->argc == 0) {
cmd = options_get_string(&s->options, "default-command"); cmd = options_get_string(&s->options, "default-command");
else if (cmd != NULL && *cmd != '\0') {
cmd = args->argv[0]; argc = 1;
argv = (char**)&cmd;
} else {
argc = 0;
argv = NULL;
}
} else {
argc = args->argc;
argv = args->argv;
}
if (args_has(args, 'c')) { if (args_has(args, 'c')) {
ft = format_create(); ft = format_create();
@ -157,8 +166,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
if (envent != NULL) if (envent != NULL)
path = envent->value; path = envent->value;
if (window_pane_spawn( if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, &env,
new_wp, cmd, path, shell, cwd, &env, s->tio, &cause) != 0) s->tio, &cause) != 0)
goto error; goto error;
layout_assign_pane(lc, new_wp); layout_assign_pane(lc, new_wp);

30
cmd.c
View File

@ -179,14 +179,14 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
} }
char ** char **
cmd_copy_argv(int argc, char *const *argv) cmd_copy_argv(int argc, char **argv)
{ {
char **new_argv; char **new_argv;
int i; int i;
if (argc == 0) if (argc == 0)
return (NULL); return (NULL);
new_argv = xcalloc(argc, sizeof *new_argv); new_argv = xcalloc(argc + 1, sizeof *new_argv);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (argv[i] != NULL) if (argv[i] != NULL)
new_argv[i] = xstrdup(argv[i]); new_argv[i] = xstrdup(argv[i]);
@ -206,6 +206,32 @@ cmd_free_argv(int argc, char **argv)
free(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 * struct cmd *
cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
{ {

View File

@ -368,7 +368,7 @@ format_get_command(struct window_pane *wp)
cmd = osdep_get_name(wp->fd, wp->tty); cmd = osdep_get_name(wp->fd, wp->tty);
if (cmd == NULL || *cmd == '\0') { if (cmd == NULL || *cmd == '\0') {
free(cmd); free(cmd);
cmd = xstrdup(wp->cmd); cmd = cmd_stringify_argv(wp->argc, wp->argv);
if (cmd == NULL || *cmd == '\0') { if (cmd == NULL || *cmd == '\0') {
free(cmd); free(cmd);
cmd = xstrdup(wp->shell); cmd = xstrdup(wp->shell);
@ -559,10 +559,12 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
if (wp->tty != NULL) if (wp->tty != NULL)
format_add(ft, "pane_tty", "%s", wp->tty); format_add(ft, "pane_tty", "%s", wp->tty);
format_add(ft, "pane_pid", "%ld", (long) wp->pid); 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) if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
format_add(ft, "pane_current_path", "%s", cwd); 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) { if ((cmd = format_get_command(wp)) != NULL) {
format_add(ft, "pane_current_command", "%s", cmd); format_add(ft, "pane_current_command", "%s", cmd);
free(cmd); free(cmd);
@ -610,6 +612,7 @@ format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb,
char *s; char *s;
format_add(ft, "buffer_size", "%zu", pb->size); format_add(ft, "buffer_size", "%zu", pb->size);
format_add(ft, "buffer_name", "%s", pb->name);
s = paste_make_sample(pb, utf8flag); s = paste_make_sample(pb, utf8flag);
format_add(ft, "buffer_sample", "%s", s); format_add(ft, "buffer_sample", "%s", s);

View File

@ -204,6 +204,21 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
char buf[40]; char buf[40];
size_t len; size_t len;
struct paste_buffer *pb; 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) { if (wp->screen->mode & ALL_MOUSE_MODES) {
/* /*

View File

@ -53,7 +53,6 @@ layout_create_cell(struct layout_cell *lcparent)
lc->yoff = UINT_MAX; lc->yoff = UINT_MAX;
lc->wp = NULL; lc->wp = NULL;
lc->lastwp = NULL;
return (lc); return (lc);
} }

View File

@ -141,6 +141,7 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_SEARCHREVERSE, "search-reverse" }, { MODEKEYCOPY_SEARCHREVERSE, "search-reverse" },
{ MODEKEYCOPY_SEARCHUP, "search-backward" }, { MODEKEYCOPY_SEARCHUP, "search-backward" },
{ MODEKEYCOPY_SELECTLINE, "select-line" }, { MODEKEYCOPY_SELECTLINE, "select-line" },
{ MODEKEYCOPY_STARTNAMEDBUFFER, "start-named-buffer" },
{ MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" }, { MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" },
{ MODEKEYCOPY_STARTOFLINE, "start-of-line" }, { MODEKEYCOPY_STARTOFLINE, "start-of-line" },
{ MODEKEYCOPY_STARTSELECTION, "begin-selection" }, { MODEKEYCOPY_STARTSELECTION, "begin-selection" },
@ -257,6 +258,7 @@ struct mode_key_tree mode_key_tree_vi_choice;
/* vi copy mode keys. */ /* vi copy mode keys. */
const struct mode_key_entry mode_key_vi_copy[] = { const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION }, { ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '"', 0, MODEKEYCOPY_STARTNAMEDBUFFER },
{ '$', 0, MODEKEYCOPY_ENDOFLINE }, { '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE }, { ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN }, { ';', 0, MODEKEYCOPY_JUMPAGAIN },

12
names.c
View File

@ -68,9 +68,15 @@ window_name_callback(unused int fd, unused short events, void *data)
char * char *
default_window_name(struct window *w) default_window_name(struct window *w)
{ {
if (w->active->cmd != NULL && *w->active->cmd != '\0') char *cmd, *s;
return (parse_window_name(w->active->cmd));
return (parse_window_name(w->active->shell)); 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 * char *

218
paste.c
View File

@ -25,127 +25,237 @@
#include "tmux.h" #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! * 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. */ int paste_cmp_names(const struct paste_buffer *, const struct paste_buffer *);
struct paste_buffer * RB_PROTOTYPE(paste_name_tree, paste_buffer, name_entry, paste_cmp_names);
paste_walk_stack(u_int *idx) 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);
} }
/* Get the top item on the stack. */ 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);
}
/* Walk paste buffers by name. */
struct paste_buffer *
paste_walk(struct paste_buffer *pb)
{
if (pb == NULL)
return (RB_MIN(paste_time_tree, &paste_by_time));
return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
}
/* Get the most recent automatic buffer */
struct paste_buffer * struct paste_buffer *
paste_get_top(void) paste_get_top(void)
{ {
if (ARRAY_LENGTH(&paste_buffers) == 0) struct paste_buffer *pb;
pb = RB_MIN(paste_time_tree, &paste_by_time);
if (pb == NULL)
return (NULL); return (NULL);
return (ARRAY_FIRST(&paste_buffers)); return (pb);
} }
/* Get an item by its index. */ /* Free the most recent buffer */
struct paste_buffer *
paste_get_index(u_int idx)
{
if (idx >= ARRAY_LENGTH(&paste_buffers))
return (NULL);
return (ARRAY_ITEM(&paste_buffers, idx));
}
/* Free the top item on the stack. */
int int
paste_free_top(void) paste_free_top(void)
{ {
struct paste_buffer *pb; struct paste_buffer *pb;
if (ARRAY_LENGTH(&paste_buffers) == 0) pb = paste_get_top();
if (pb == NULL)
return (-1); return (-1);
return (paste_free_name(pb->name));
pb = ARRAY_FIRST(&paste_buffers);
ARRAY_REMOVE(&paste_buffers, 0);
free(pb->data);
free(pb);
return (0);
} }
/* Free an item by index. */ /* Get a paste buffer by name. */
int struct paste_buffer *
paste_free_index(u_int idx) paste_get_name(const char *name)
{ {
struct paste_buffer *pb; struct paste_buffer pbfind;
if (idx >= ARRAY_LENGTH(&paste_buffers)) if (name == NULL || *name == '\0')
return (NULL);
pbfind.name = (char*)name;
return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind));
}
/* Free a paste buffer by name. */
int
paste_free_name(const char *name)
{
struct paste_buffer *pb, pbfind;
if (name == NULL || *name == '\0')
return (-1); return (-1);
pb = ARRAY_ITEM(&paste_buffers, idx); pbfind.name = (char*)name;
ARRAY_REMOVE(&paste_buffers, idx); pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind);
if (pb == NULL)
return (-1);
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->data);
free(pb->name);
free(pb); free(pb);
return (0); 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. * that the caller is responsible for allocating data.
*/ */
void 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) if (size == 0)
return; return;
while (ARRAY_LENGTH(&paste_buffers) >= limit) { limit = options_get_number(&global_options, "buffer-limit");
pb = ARRAY_LAST(&paste_buffers); RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) {
free(pb->data); if (paste_num_automatic < limit)
free(pb); break;
ARRAY_TRUNC(&paste_buffers, 1); if (pb->automatic)
paste_free_name(pb->name);
} }
pb = xmalloc(sizeof *pb); 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->data = data;
pb->size = size; 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. * allocating data.
*/ */
int 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; struct paste_buffer *pb;
if (cause != NULL)
*cause = NULL;
if (size == 0) { if (size == 0) {
free(data); free(data);
return (0); 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); return (-1);
}
pb = ARRAY_ITEM(&paste_buffers, idx); pb = paste_get_name(name);
free(pb->data); if (pb != NULL)
paste_free_name(name);
pb = xmalloc(sizeof *pb);
pb->name = xstrdup(name);
pb->data = data; pb->data = data;
pb->size = size; 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); return (0);
} }

View File

@ -84,11 +84,12 @@ session_find_by_id(u_int id)
/* Create a new session. */ /* Create a new session. */
struct session * struct session *
session_create(const char *name, const char *cmd, const char *path, int cwd, session_create(const char *name, int argc, char **argv, const char *path,
struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy, int cwd, struct environ *env, struct termios *tio, int idx, u_int sx,
char **cause) u_int sy, char **cause)
{ {
struct session *s; struct session *s;
struct winlink *wl;
s = xmalloc(sizeof *s); s = xmalloc(sizeof *s);
s->references = 0; 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); RB_INSERT(sessions, &sessions, s);
if (cmd != NULL) { if (argc >= 0) {
if (session_new(s, NULL, cmd, path, cwd, idx, cause) == NULL) { wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause);
if (wl == NULL) {
session_destroy(s); session_destroy(s);
return (NULL); return (NULL);
} }
@ -226,7 +228,7 @@ session_previous_session(struct session *s)
/* Create a new window on a session. */ /* Create a new window on a session. */
struct winlink * 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) const char *path, int cwd, int idx, char **cause)
{ {
struct window *w; struct window *w;
@ -250,8 +252,8 @@ session_new(struct session *s, const char *name, const char *cmd,
shell = _PATH_BSHELL; shell = _PATH_BSHELL;
hlimit = options_get_number(&s->options, "history-limit"); hlimit = options_get_number(&s->options, "history-limit");
w = window_create(name, cmd, path, shell, cwd, &env, s->tio, s->sx, w = window_create(name, argc, argv, path, shell, cwd, &env, s->tio,
s->sy, hlimit, cause); s->sx, s->sy, hlimit, cause);
if (w == NULL) { if (w == NULL) {
winlink_remove(&s->windows, wl); winlink_remove(&s->windows, wl);
environ_free(&env); environ_free(&env);

View File

@ -117,7 +117,7 @@ style_tostring(struct grid_cell *gc)
*s = '\0'; *s = '\0';
if (gc->fg != 8) { if (gc->fg != 8 || gc->flags & GRID_FLAG_FG256) {
if (gc->flags & GRID_FLAG_FG256) if (gc->flags & GRID_FLAG_FG256)
c = gc->fg | 0x100; c = gc->fg | 0x100;
else else
@ -126,7 +126,7 @@ style_tostring(struct grid_cell *gc)
comma = 1; comma = 1;
} }
if (gc->bg != 8) { if (gc->bg != 8 || gc->flags & GRID_FLAG_BG256) {
if (gc->flags & GRID_FLAG_BG256) if (gc->flags & GRID_FLAG_BG256)
c = gc->bg | 0x100; c = gc->bg | 0x100;
else else
@ -221,13 +221,13 @@ style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
struct grid_cell *gcp; struct grid_cell *gcp;
gcp = options_get_style(oo, name); 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) if (gcp->flags & GRID_FLAG_FG256)
colour_set_fg(gc, gcp->fg | 0x100); colour_set_fg(gc, gcp->fg | 0x100);
else else
colour_set_fg(gc, gcp->fg); 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) if (gcp->flags & GRID_FLAG_BG256)
colour_set_bg(gc, gcp->bg | 0x100); colour_set_bg(gc, gcp->bg | 0x100);
else else

93
tmux.1
View File

@ -482,12 +482,37 @@ It may be used alone to target a pane or the window containing it.
arguments are arguments are
.Xr sh 1 .Xr sh 1
commands. commands.
These must be passed as a single item, which typically means quoting them, for This may be a single argument passed to the shell, for example:
example:
.Bd -literal -offset indent .Bd -literal -offset indent
new-window 'vi /etc/passwd' new-window 'vi /etc/passwd'
.Ed .Ed
.Pp .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 .Ar command
.Op Ar arguments .Op Ar arguments
refers to a 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 Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Append selection" Ta "A" Ta "" .It Li "Append selection" Ta "A" Ta ""
.It Li "Back to indentation" Ta "^" Ta "M-m" .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 "Bottom of history" Ta "G" Ta "M-<"
.It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Clear selection" Ta "Escape" Ta "C-g"
.It Li "Copy selection" Ta "Enter" Ta "M-w" .It Li "Copy selection" Ta "Enter" Ta "M-w"
@ -934,9 +960,6 @@ in emacs mode, and
.Ql 10w .Ql 10w
in vi. in vi.
.Pp .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: Mode key bindings are defined in a set of named tables:
.Em vi-edit .Em vi-edit
and and
@ -1094,7 +1117,7 @@ but a different format may be specified with
.Fl F . .Fl F .
.It Xo Ic capture-pane .It Xo Ic capture-pane
.Op Fl aepPq .Op Fl aepPq
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Op Fl E Ar end-line .Op Fl E Ar end-line
.Op Fl S Ar start-line .Op Fl S Ar start-line
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
@ -3371,19 +3394,40 @@ is given, otherwise the active pane for the session attached to
.El .El
.Sh BUFFERS .Sh BUFFERS
.Nm .Nm
maintains a stack of maintains a set of named
.Em paste buffers . .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 .Ic buffer-limit
option are kept; when a new buffer is added, the buffer at the bottom of the option is reached, the oldest automatically named buffer is deleted.
stack is removed. Explicitly named are not subject to
.Ic buffer-limit
and may be deleted with
.Ic delete-buffer
command.
.Pp
Buffers may be added using Buffers may be added using
.Ic copy-mode .Ic copy-mode
or the or the
.Ic set-buffer .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 .Ic paste-buffer
command. command.
If a buffer command is used and no buffer is specified, the most
recently added automatically named buffer is assumed.
.Pp .Pp
A configurable history buffer is also maintained for each window. A configurable history buffer is also maintained for each window.
By default, up to 2000 lines are kept; this can be altered with the 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. interactively from a list.
After a buffer is selected, After a buffer is selected,
.Ql %% .Ql %%
is replaced by the buffer index in is replaced by the buffer name in
.Ar template .Ar template
and the result executed as a command. and the result executed as a command.
If 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 .It Ic clear-history Op Fl t Ar target-pane
.D1 (alias: Ic clearhist ) .D1 (alias: Ic clearhist )
Remove and free the history for the specified pane. 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 ) .D1 (alias: Ic deleteb )
Delete the buffer at Delete the buffer named
.Ar buffer-index , .Ar buffer-name ,
or the top buffer if not specified. or the most recently added automatically named buffer if not specified.
.It Xo Ic list-buffers .It Xo Ic list-buffers
.Op Fl F Ar format .Op Fl F Ar format
.Xc .Xc
@ -3435,7 +3479,7 @@ flag, see the
.Sx FORMATS .Sx FORMATS
section. section.
.It Xo Ic load-buffer .It Xo Ic load-buffer
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Ar path .Ar path
.Xc .Xc
.D1 (alias: Ic loadb ) .D1 (alias: Ic loadb )
@ -3443,7 +3487,7 @@ Load the contents of the specified paste buffer from
.Ar path . .Ar path .
.It Xo Ic paste-buffer .It Xo Ic paste-buffer
.Op Fl dpr .Op Fl dpr
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Op Fl s Ar separator .Op Fl s Ar separator
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Xc .Xc
@ -3452,7 +3496,7 @@ Insert the contents of a paste buffer into the specified pane.
If not specified, paste into the current one. If not specified, paste into the current one.
With With
.Fl d , .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 When output, any linefeed (LF) characters in the paste buffer are replaced with
a separator, by default carriage return (CR). a separator, by default carriage return (CR).
A custom separator may be specified using the 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. buffer if the application has requested bracketed paste mode.
.It Xo Ic save-buffer .It Xo Ic save-buffer
.Op Fl a .Op Fl a
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Ar path .Ar path
.Xc .Xc
.D1 (alias: Ic saveb ) .D1 (alias: Ic saveb )
@ -3478,7 +3522,8 @@ The
option appends to rather than overwriting the file. option appends to rather than overwriting the file.
.It Xo Ic set-buffer .It Xo Ic set-buffer
.Op Fl a .Op Fl a
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Op Fl n Ar new-buffer-name
.Ar data .Ar data
.Xc .Xc
.D1 (alias: Ic setb ) .D1 (alias: Ic setb )
@ -3487,8 +3532,12 @@ Set the contents of the specified buffer to
The The
.Fl a .Fl a
option appends to rather than overwriting the buffer. 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 .It Xo Ic show-buffer
.Op Fl b Ar buffer-index .Op Fl b Ar buffer-name
.Xc .Xc
.D1 (alias: Ic showb ) .D1 (alias: Ic showb )
Display the contents of the specified buffer. Display the contents of the specified buffer.

55
tmux.h
View File

@ -82,7 +82,7 @@ extern char **environ;
/* Default template for choose-buffer. */ /* Default template for choose-buffer. */
#define CHOOSE_BUFFER_TEMPLATE \ #define CHOOSE_BUFFER_TEMPLATE \
"#{line}: #{buffer_size} bytes: #{buffer_sample}" "#{buffer_name}: #{buffer_size} bytes: #{buffer_sample}"
/* Default template for choose-client. */ /* Default template for choose-client. */
#define CHOOSE_CLIENT_TEMPLATE \ #define CHOOSE_CLIENT_TEMPLATE \
@ -115,7 +115,8 @@ extern char **environ;
/* Default template for list-buffers. */ /* Default template for list-buffers. */
#define LIST_BUFFERS_TEMPLATE \ #define LIST_BUFFERS_TEMPLATE \
"#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" "#{buffer_name}: #{buffer_size} bytes: " \
"\"#{buffer_sample}\""
/* Default template for list-clients. */ /* Default template for list-clients. */
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
@ -579,6 +580,7 @@ enum mode_key_cmd {
MODEKEYCOPY_SEARCHREVERSE, MODEKEYCOPY_SEARCHREVERSE,
MODEKEYCOPY_SEARCHUP, MODEKEYCOPY_SEARCHUP,
MODEKEYCOPY_SELECTLINE, MODEKEYCOPY_SELECTLINE,
MODEKEYCOPY_STARTNAMEDBUFFER,
MODEKEYCOPY_STARTNUMBERPREFIX, MODEKEYCOPY_STARTNUMBERPREFIX,
MODEKEYCOPY_STARTOFLINE, MODEKEYCOPY_STARTOFLINE,
MODEKEYCOPY_STARTSELECTION, MODEKEYCOPY_STARTSELECTION,
@ -889,6 +891,7 @@ struct window_choose_mode_item {
/* Child window structure. */ /* Child window structure. */
struct window_pane { struct window_pane {
u_int id; u_int id;
u_int active_point;
struct window *window; struct window *window;
@ -908,7 +911,8 @@ struct window_pane {
#define PANE_RESIZE 0x8 #define PANE_RESIZE 0x8
#define PANE_FOCUSPUSH 0x10 #define PANE_FOCUSPUSH 0x10
char *cmd; int argc;
char **argv;
char *shell; char *shell;
int cwd; int cwd;
@ -945,6 +949,7 @@ struct window_pane {
}; };
TAILQ_HEAD(window_panes, window_pane); TAILQ_HEAD(window_panes, window_pane);
RB_HEAD(window_pane_tree, window_pane); RB_HEAD(window_pane_tree, window_pane);
ARRAY_DECL(window_pane_list, struct window_pane *);
/* Window structure. */ /* Window structure. */
struct window { struct window {
@ -1022,8 +1027,6 @@ struct layout_cell {
u_int yoff; u_int yoff;
struct window_pane *wp; struct window_pane *wp;
struct window_pane *lastwp;
struct layout_cells cells; struct layout_cells cells;
TAILQ_ENTRY(layout_cell) entry; TAILQ_ENTRY(layout_cell) entry;
@ -1033,6 +1036,13 @@ struct layout_cell {
struct paste_buffer { struct paste_buffer {
char *data; char *data;
size_t size; size_t size;
char *name;
int automatic;
u_int order;
RB_ENTRY(paste_buffer) name_entry;
RB_ENTRY(paste_buffer) time_entry;
}; };
/* Environment variable. */ /* Environment variable. */
@ -1127,6 +1137,9 @@ LIST_HEAD(tty_terms, tty_term);
#define MOUSE_WHEEL_UP 0 #define MOUSE_WHEEL_UP 0
#define MOUSE_WHEEL_DOWN 1 #define MOUSE_WHEEL_DOWN 1
/* Mouse wheel multipler. */
#define MOUSE_WHEEL_SCALE 3
/* Mouse event bits. */ /* Mouse event bits. */
#define MOUSE_EVENT_DOWN 0x1 #define MOUSE_EVENT_DOWN 0x1
#define MOUSE_EVENT_DRAG 0x2 #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_WINDOW_USAGE "[-s src-window] [-t dst-window]"
#define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]" #define CMD_SRCDST_SESSION_USAGE "[-s src-session] [-t dst-session]"
#define CMD_SRCDST_CLIENT_USAGE "[-s src-client] [-t dst-client]" #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 */ /* tmux.c */
extern struct options global_options; extern struct options global_options;
@ -1705,13 +1718,14 @@ void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *); int tty_keys_next(struct tty *);
/* paste.c */ /* 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_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_top(void);
int paste_free_index(u_int); int paste_free_name(const char *);
void paste_add(char *, size_t, u_int); void paste_add(char *, size_t);
int paste_replace(u_int, 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); char *paste_make_sample(struct paste_buffer *, int);
void paste_send_pane(struct paste_buffer *, struct window_pane *, void paste_send_pane(struct paste_buffer *, struct window_pane *,
const char *, int); const char *, int);
@ -1732,8 +1746,9 @@ long long args_strtonum(
/* cmd.c */ /* cmd.c */
int cmd_pack_argv(int, char **, char *, size_t); int cmd_pack_argv(int, char **, char *, size_t);
int cmd_unpack_argv(char *, size_t, int, char ***); 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 **); void cmd_free_argv(int, char **);
char *cmd_stringify_argv(int, char **);
struct cmd *cmd_parse(int, char **, const char *, u_int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **);
size_t cmd_print(struct cmd *, char *, size_t); size_t cmd_print(struct cmd *, char *, size_t);
struct session *cmd_current_session(struct cmd_q *, int); 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 *); int window_index(struct window *, u_int *);
struct window *window_find_by_id(u_int); struct window *window_find_by_id(u_int);
struct window *window_create1(u_int, 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 *, const char *, int, struct environ *, struct termios *,
u_int, u_int, u_int, char **); u_int, u_int, u_int, char **);
void window_destroy(struct window *); 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); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int);
void window_pane_destroy(struct window_pane *); void window_pane_destroy(struct window_pane *);
void window_pane_timer_start(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 *, const char *, const char *, int, struct environ *,
struct termios *, char **); struct termios *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int); 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 *); int session_alive(struct session *);
struct session *session_find(const char *); struct session *session_find(const char *);
struct session *session_find_by_id(u_int); struct session *session_find_by_id(u_int);
struct session *session_create(const char *, const char *, const char *, int, struct session *session_create(const char *, int, char **, const char *,
struct environ *, struct termios *, int, u_int, u_int, int, struct environ *, struct termios *, int, u_int,
char **); u_int, char **);
void session_destroy(struct session *); void session_destroy(struct session *);
int session_check_name(const char *); int session_check_name(const char *);
void session_update_activity(struct session *); void session_update_activity(struct session *);
struct session *session_next_session(struct session *); struct session *session_next_session(struct session *);
struct session *session_previous_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 **); const char *, int, int, char **);
struct winlink *session_attach( struct winlink *session_attach(struct session *, struct window *, int,
struct session *, struct window *, int, char **); char **);
int session_detach(struct session *, struct winlink *); int session_detach(struct session *, struct winlink *);
struct winlink *session_has(struct session *, struct window *); struct winlink *session_has(struct session *, struct window *);
int session_next(struct session *, int); int session_next(struct session *, int);

View File

@ -752,11 +752,11 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
if (b & MOUSE_MASK_SHIFT) if (b & MOUSE_MASK_SHIFT)
m->scroll = 1; m->scroll = 1;
else else
m->scroll = 3; m->scroll = MOUSE_WHEEL_SCALE;
if (b & MOUSE_MASK_META) if (b & MOUSE_MASK_META)
m->scroll *= 3; m->scroll *= MOUSE_WHEEL_SCALE;
if (b & MOUSE_MASK_CTRL) if (b & MOUSE_MASK_CTRL)
m->scroll *= 3; m->scroll *= MOUSE_WHEEL_SCALE;
b &= MOUSE_MASK_BUTTONS; b &= MOUSE_MASK_BUTTONS;
if (b == 0) if (b == 0)

View File

@ -721,17 +721,22 @@ window_choose_mouse(struct window_pane *wp, struct session *sess,
struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_data *data = wp->modedata;
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct window_choose_mode_item *item; struct window_choose_mode_item *item;
u_int idx; u_int idx, i, n;
if (m->event == MOUSE_EVENT_WHEEL) { if (m->event == MOUSE_EVENT_WHEEL) {
/* /*
* Don't use m->scroll and just move line-by-line or it's * Multiple line scrolling by default is annoying, so scale
* annoying. * m->scroll back down.
*/ */
if (m->wheel == MOUSE_WHEEL_UP) n = m->scroll;
window_choose_key(wp, sess, KEYC_UP); if (n >= MOUSE_WHEEL_SCALE)
else n /= MOUSE_WHEEL_SCALE;
window_choose_key(wp, sess, KEYC_DOWN); 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; return;
} }

View File

@ -54,14 +54,15 @@ void window_copy_update_cursor(struct window_pane *, u_int, u_int);
void window_copy_start_selection(struct window_pane *); void window_copy_start_selection(struct window_pane *);
int window_copy_update_selection(struct window_pane *, int); int window_copy_update_selection(struct window_pane *, int);
void *window_copy_get_selection(struct window_pane *, size_t *); 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_buffer(struct window_pane *, const char *, void *,
void window_copy_copy_pipe( size_t);
struct window_pane *, struct session *, int, const char *); void window_copy_copy_pipe(struct window_pane *, struct session *,
void window_copy_copy_selection(struct window_pane *, int); const char *, const char *);
void window_copy_append_selection(struct window_pane *, int); 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_clear_selection(struct window_pane *);
void window_copy_copy_line( void window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
struct window_pane *, char **, size_t *, u_int, u_int, u_int); u_int, u_int);
int window_copy_in_set(struct window_pane *, u_int, u_int, const char *); 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); u_int window_copy_find_length(struct window_pane *, u_int);
void window_copy_cursor_start_of_line(struct window_pane *); 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 { enum window_copy_input_type {
WINDOW_COPY_OFF, WINDOW_COPY_OFF,
WINDOW_COPY_NAMEDBUFFER,
WINDOW_COPY_NUMERICPREFIX, WINDOW_COPY_NUMERICPREFIX,
WINDOW_COPY_SEARCHUP, WINDOW_COPY_SEARCHUP,
WINDOW_COPY_SEARCHDOWN, WINDOW_COPY_SEARCHDOWN,
@ -417,7 +419,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
switch (cmd) { switch (cmd) {
case MODEKEYCOPY_APPENDSELECTION: case MODEKEYCOPY_APPENDSELECTION:
if (sess != NULL) { if (sess != NULL) {
window_copy_append_selection(wp, data->numprefix); window_copy_append_selection(wp, NULL);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
return; return;
} }
@ -543,7 +545,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
if (sess != NULL && if (sess != NULL &&
(cmd == MODEKEYCOPY_COPYLINE || (cmd == MODEKEYCOPY_COPYLINE ||
cmd == MODEKEYCOPY_COPYENDOFLINE)) { cmd == MODEKEYCOPY_COPYENDOFLINE)) {
window_copy_copy_selection(wp, -1); window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
return; return;
} }
@ -554,14 +556,14 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
break; break;
case MODEKEYCOPY_COPYPIPE: case MODEKEYCOPY_COPYPIPE:
if (sess != NULL) { 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); window_pane_reset_mode(wp);
return; return;
} }
break; break;
case MODEKEYCOPY_COPYSELECTION: case MODEKEYCOPY_COPYSELECTION:
if (sess != NULL) { if (sess != NULL) {
window_copy_copy_selection(wp, data->numprefix); window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
return; return;
} }
@ -676,6 +678,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
case WINDOW_COPY_JUMPBACK: case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_JUMPTOFORWARD: case WINDOW_COPY_JUMPTOFORWARD:
case WINDOW_COPY_JUMPTOBACK: case WINDOW_COPY_JUMPTOBACK:
case WINDOW_COPY_NAMEDBUFFER:
case WINDOW_COPY_NUMERICPREFIX: case WINDOW_COPY_NUMERICPREFIX:
break; break;
case WINDOW_COPY_SEARCHUP: 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->inputprompt = "Goto Line";
*data->inputstr = '\0'; *data->inputstr = '\0';
goto input_on; goto input_on;
case MODEKEYCOPY_STARTNAMEDBUFFER:
data->inputtype = WINDOW_COPY_NAMEDBUFFER;
data->inputprompt = "Buffer";
*data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_STARTNUMBERPREFIX: case MODEKEYCOPY_STARTNUMBERPREFIX:
key &= KEYC_MASK_KEY; key &= KEYC_MASK_KEY;
if (key >= '0' && key <= '9') { if (key >= '0' && key <= '9') {
@ -814,6 +822,11 @@ window_copy_key_input(struct window_pane *wp, int key)
data->searchtype = data->inputtype; data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr); data->searchstr = xstrdup(data->inputstr);
break; 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: case WINDOW_COPY_GOTOLINE:
window_copy_goto_line(wp, data->inputstr); window_copy_goto_line(wp, data->inputstr);
*data->inputstr = '\0'; *data->inputstr = '\0';
@ -918,7 +931,7 @@ reset_mode:
s->mode &= ~MODE_MOUSE_BUTTON; s->mode &= ~MODE_MOUSE_BUTTON;
s->mode |= MODE_MOUSE_STANDARD; s->mode |= MODE_MOUSE_STANDARD;
if (sess != NULL) { if (sess != NULL) {
window_copy_copy_selection(wp, -1); window_copy_copy_selection(wp, NULL);
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
} }
} }
@ -1452,9 +1465,9 @@ window_copy_get_selection(struct window_pane *wp, size_t *len)
} }
void 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; struct screen_write_ctx ctx;
if (options_get_number(&global_options, "set-clipboard")) { 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); screen_write_stop(&ctx);
} }
if (idx == -1) { if (paste_set(buf, len, bufname, NULL) != 0)
limit = options_get_number(&global_options, "buffer-limit");
paste_add(buf, len, limit);
} else if (paste_replace(idx, buf, len) != 0)
free(buf); free(buf);
} }
void void
window_copy_copy_pipe( window_copy_copy_pipe(struct window_pane *wp, struct session *sess,
struct window_pane *wp, struct session *sess, int idx, const char *arg) const char *bufname, const char *arg)
{ {
void *buf; void *buf;
size_t len; size_t len;
@ -1486,11 +1496,11 @@ window_copy_copy_pipe(
job = job_run(arg, sess, NULL, NULL, NULL); job = job_run(arg, sess, NULL, NULL, NULL);
bufferevent_write(job->event, buf, len); bufferevent_write(job->event, buf, len);
window_copy_copy_buffer(wp, idx, buf, len); window_copy_copy_buffer(wp, bufname, buf, len);
} }
void void
window_copy_copy_selection(struct window_pane *wp, int idx) window_copy_copy_selection(struct window_pane *wp, const char *bufname)
{ {
void* buf; void* buf;
size_t len; size_t len;
@ -1499,17 +1509,16 @@ window_copy_copy_selection(struct window_pane *wp, int idx)
if (buf == NULL) if (buf == NULL)
return; return;
window_copy_copy_buffer(wp, idx, buf, len); window_copy_copy_buffer(wp, bufname, buf, len);
} }
void void
window_copy_append_selection(struct window_pane *wp, int idx) window_copy_append_selection(struct window_pane *wp, const char *bufname)
{ {
char *buf; char *buf;
struct paste_buffer *pb; struct paste_buffer *pb;
size_t len; size_t len;
u_int limit; struct screen_write_ctx ctx;
struct screen_write_ctx ctx;
buf = window_copy_get_selection(wp, &len); buf = window_copy_get_selection(wp, &len);
if (buf == NULL) if (buf == NULL)
@ -1521,24 +1530,19 @@ window_copy_append_selection(struct window_pane *wp, int idx)
screen_write_stop(&ctx); screen_write_stop(&ctx);
} }
if (idx == -1) if (bufname == NULL || *bufname == '\0') {
idx = 0; pb = paste_get_top();
if (pb != NULL)
if (idx == 0 && paste_get_top() == NULL) { bufname = pb->name;
limit = options_get_number(&global_options, "buffer-limit"); } else
paste_add(buf, len, limit); pb = paste_get_name(bufname);
return;
}
pb = paste_get_index(idx);
if (pb != NULL) { if (pb != NULL) {
buf = xrealloc(buf, 1, len + pb->size); buf = xrealloc(buf, 1, len + pb->size);
memmove(buf + pb->size, buf, len); memmove(buf + pb->size, buf, len);
memcpy(buf, pb->data, pb->size); memcpy(buf, pb->data, pb->size);
len += pb->size; len += pb->size;
} }
if (paste_set(buf, len, bufname, NULL) != 0)
if (paste_replace(idx, buf, len) != 0)
free(buf); free(buf);
} }

327
window.c
View File

@ -55,15 +55,14 @@ struct windows windows;
struct window_pane_tree all_window_panes; struct window_pane_tree all_window_panes;
u_int next_window_pane_id; u_int next_window_pane_id;
u_int next_window_id; u_int next_window_id;
u_int next_active_point;
struct window_pane *window_pane_active_set(struct window_pane *,
struct window_pane *);
void window_pane_active_lost(struct window_pane *, struct window_pane *);
void window_pane_timer_callback(int, short, void *); void window_pane_timer_callback(int, short, void *);
void window_pane_read_callback(struct bufferevent *, void *); void window_pane_read_callback(struct bufferevent *, void *);
void window_pane_error_callback(struct bufferevent *, short, 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); RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
int int
@ -307,7 +306,7 @@ window_create1(u_int sx, u_int sy)
} }
struct window * 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, const char *shell, int cwd, struct environ *env, struct termios *tio,
u_int sx, u_int sy, u_int hlimit, char **cause) 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); wp = window_add_pane(w, hlimit);
layout_init(w, wp); 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) { cause) != 0) {
window_destroy(w); window_destroy(w);
return (NULL); return (NULL);
@ -386,64 +385,6 @@ window_resize(struct window *w, u_int sx, u_int sy)
w->sy = 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 void
window_set_active_pane(struct window *w, struct window_pane *wp) 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; return;
w->last = w->active; w->last = w->active;
w->active = wp; w->active = wp;
window_pane_active_lost(w->last, wp);
while (!window_pane_visible(w->active)) { while (!window_pane_visible(w->active)) {
w->active = TAILQ_PREV(w->active, window_panes, entry); w->active = TAILQ_PREV(w->active, window_panes, entry);
if (w->active == NULL) if (w->active == NULL)
@ -459,6 +399,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp)
if (w->active == wp) if (w->active == wp)
return; return;
} }
w->active->active_point = next_active_point++;
} }
struct window_pane * 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++; wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp); RB_INSERT(window_pane_tree, &all_window_panes, wp);
wp->cmd = NULL; wp->argc = 0;
wp->argv = NULL;
wp->shell = NULL; wp->shell = NULL;
wp->cwd = -1; wp->cwd = -1;
@ -770,16 +712,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
void void
window_pane_destroy(struct window_pane *wp) 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); window_pane_reset_mode(wp);
if (event_initialized(&wp->changes_timer)) if (event_initialized(&wp->changes_timer))
@ -808,30 +740,32 @@ window_pane_destroy(struct window_pane *wp)
close(wp->cwd); close(wp->cwd);
free(wp->shell); free(wp->shell);
free(wp->cmd); cmd_free_argv(wp->argc, wp->argv);
free(wp); free(wp);
} }
int int
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path, window_pane_spawn(struct window_pane *wp, int argc, char **argv,
const char *shell, int cwd, struct environ *env, struct termios *tio, const char *path, const char *shell, int cwd, struct environ *env,
char **cause) struct termios *tio, char **cause)
{ {
struct winsize ws; struct winsize ws;
char *argv0, paneid[16]; char *argv0, *cmd, **argvp, paneid[16];
const char *ptr; const char *ptr, *first;
struct termios tio2; struct termios tio2;
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
char s[32]; char s[32];
#endif #endif
int i;
if (wp->fd != -1) { if (wp->fd != -1) {
bufferevent_free(wp->event); bufferevent_free(wp->event);
close(wp->fd); close(wp->fd);
} }
if (cmd != NULL) { if (argc > 0) {
free(wp->cmd); cmd_free_argv(wp->argc, wp->argv);
wp->cmd = xstrdup(cmd); wp->argc = argc;
wp->argv = cmd_copy_argv(argc, argv);
} }
if (shell != NULL) { if (shell != NULL) {
free(wp->shell); free(wp->shell);
@ -842,7 +776,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
wp->cwd = dup(cwd); 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); memset(&ws, 0, sizeof ws);
ws.ws_col = screen_size_x(&wp->base); 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: case -1:
wp->fd = -1; wp->fd = -1;
xasprintf(cause, "%s: %s", cmd, strerror(errno)); xasprintf(cause, "%s: %s", cmd, strerror(errno));
free(cmd);
return (-1); return (-1);
case 0: case 0:
if (fchdir(wp->cwd) != 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); setenv("SHELL", wp->shell, 1);
ptr = strrchr(wp->shell, '/'); 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') if (ptr != NULL && *(ptr + 1) != '\0')
xasprintf(&argv0, "%s", ptr + 1); xasprintf(&argv0, "%s", ptr + 1);
else else
xasprintf(&argv0, "%s", wp->shell); 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"); fatal("execl failed");
} }
/* No command; fork a login shell. */
if (ptr != NULL && *(ptr + 1) != '\0') if (ptr != NULL && *(ptr + 1) != '\0')
xasprintf(&argv0, "-%s", ptr + 1); xasprintf(&argv0, "-%s", ptr + 1);
else else
xasprintf(&argv0, "-%s", wp->shell); xasprintf(&argv0, "-%s", wp->shell);
execl(wp->shell, argv0, (char *) NULL); execl(wp->shell, argv0, (char *)NULL);
fatal("execl failed"); fatal("execl failed");
} }
@ -909,10 +857,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path,
setblocking(wp->fd, 0); setblocking(wp->fd, 0);
wp->event = bufferevent_new(wp->fd, wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL,
window_pane_read_callback, NULL, window_pane_error_callback, wp); window_pane_error_callback, wp);
bufferevent_enable(wp->event, EV_READ|EV_WRITE); bufferevent_enable(wp->event, EV_READ|EV_WRITE);
free(cmd);
return (0); return (0);
} }
@ -1201,114 +1150,198 @@ window_pane_search(struct window_pane *wp, const char *searchstr,
return (msg); 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 * struct window_pane *
window_pane_find_up(struct window_pane *wp) window_pane_find_up(struct window_pane *wp)
{ {
struct window_pane *wp2; struct window_pane *next, *best;
u_int left, top; u_int edge, left, right, end;
struct window_pane_list list;
int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL || !window_pane_visible(wp))
return (NULL); 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; left = wp->xoff;
right = wp->xoff + wp->sx;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (!window_pane_visible(wp2)) if (next == wp || !window_pane_visible(next))
continue; continue;
if (wp2->yoff + wp2->sy + 1 != top) if (next->yoff + next->sy + 1 != edge)
continue; continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) end = next->xoff + next->sx - 1;
return (window_pane_active_set(wp, wp2));
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. */ /* Find the pane directly below another. */
struct window_pane * struct window_pane *
window_pane_find_down(struct window_pane *wp) window_pane_find_down(struct window_pane *wp)
{ {
struct window_pane *wp2; struct window_pane *next, *best;
u_int left, bottom; u_int edge, left, right, end;
struct window_pane_list list;
int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL || !window_pane_visible(wp))
return (NULL); 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; left = wp->xoff;
right = wp->xoff + wp->sx;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (!window_pane_visible(wp2)) if (next == wp || !window_pane_visible(next))
continue; continue;
if (wp2->yoff != bottom) if (next->yoff != edge)
continue; continue;
if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) end = next->xoff + next->sx - 1;
return (window_pane_active_set(wp, wp2));
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. */
* Find the pane directly to the left of another, adjacent to the left side and
* containing the top edge.
*/
struct window_pane * struct window_pane *
window_pane_find_left(struct window_pane *wp) window_pane_find_left(struct window_pane *wp)
{ {
struct window_pane *wp2; struct window_pane *next, *best;
u_int left, top; u_int edge, top, bottom, end;
struct window_pane_list list;
int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL || !window_pane_visible(wp))
return (NULL); 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; top = wp->yoff;
bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (!window_pane_visible(wp2)) if (next == wp || !window_pane_visible(next))
continue; continue;
if (wp2->xoff + wp2->sx + 1 != left) if (next->xoff + next->sx + 1 != edge)
continue; continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) end = next->yoff + next->sy - 1;
return (window_pane_active_set(wp, wp2));
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. */
* Find the pane directly to the right of another, that is adjacent to the
* right edge and including the top edge.
*/
struct window_pane * struct window_pane *
window_pane_find_right(struct window_pane *wp) window_pane_find_right(struct window_pane *wp)
{ {
struct window_pane *wp2; struct window_pane *next, *best;
u_int right, top; u_int edge, top, bottom, end;
struct window_pane_list list;
int found;
if (wp == NULL || !window_pane_visible(wp)) if (wp == NULL || !window_pane_visible(wp))
return (NULL); 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; top = wp->yoff;
bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(next, &wp->window->panes, entry) {
if (!window_pane_visible(wp2)) if (next == wp || !window_pane_visible(next))
continue; continue;
if (wp2->xoff != right) if (next->xoff != edge)
continue; continue;
if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) end = next->yoff + next->sy - 1;
return (window_pane_active_set(wp, wp2));
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 */ /* Clear alert flags for a winlink */