Merge branch 'master' of ssh://git.code.sf.net/p/tmux/tmux-code

This commit is contained in:
Nicholas Marriott 2014-06-18 09:31:07 +01:00
commit 77f582ff13
30 changed files with 748 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 = {
"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,25 +191,17 @@ 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);
bufname = NULL;
if (args_has(args, 'b'))
bufname = args_get(args, 'b');
if (paste_set(buf, len, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
free(buf);
free(cause);
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);

View File

@ -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);

View File

@ -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);
}

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);
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);
}

View File

@ -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);

View File

@ -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;
int ch, error, 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);
}
}
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);
}

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 = {
"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);

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 = {
"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);

View File

@ -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);

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 = {
"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);

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 = {
"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);

View File

@ -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);
}
}

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 = {
"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);
}

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 = {
"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);

30
cmd.c
View File

@ -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)
{

View File

@ -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);

View File

@ -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) {
/*

View File

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

1
log.c
View File

@ -17,6 +17,7 @@
*/
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>

View File

@ -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 },

12
names.c
View File

@ -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 *

218
paste.c
View File

@ -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;
pb = paste_get_index(*idx);
(*idx)++;
return (pb);
return (strcmp(a->name, b->name));
}
/* 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 *
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 (ARRAY_FIRST(&paste_buffers));
return (pb);
}
/* Get an item by its index. */
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. */
/* 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);
pb = ARRAY_FIRST(&paste_buffers);
ARRAY_REMOVE(&paste_buffers, 0);
free(pb->data);
free(pb);
return (0);
return (paste_free_name(pb->name));
}
/* Free an item by index. */
int
paste_free_index(u_int idx)
/* Get a paste buffer by name. */
struct paste_buffer *
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);
pb = ARRAY_ITEM(&paste_buffers, idx);
ARRAY_REMOVE(&paste_buffers, idx);
pbfind.name = (char*)name;
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->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);
}

View File

@ -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);

View File

@ -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

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
.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 are kept; when a new buffer is added, the buffer at the bottom of the
stack is removed.
option is reached, the oldest automatically named buffer is deleted.
Explicitly named are not subject to
.Ic buffer-limit
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.

55
tmux.h
View File

@ -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);

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)
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)

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 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;
}

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 *);
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);
}

327
window.c
View File

@ -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 */