Merge branch 'master' of github.com:tmux/tmux

pull/35/merge
Nicholas Marriott 2015-06-20 08:45:19 +01:00
commit 8b8a007e8e
13 changed files with 148 additions and 64 deletions

View File

@ -352,9 +352,10 @@ client_main(int argc, char **argv, int flags)
void
client_send_identify(int flags)
{
const char *s;
const char *s;
char **ss;
int fd;
int fd;
pid_t pid;
client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
@ -374,6 +375,9 @@ client_send_identify(int flags)
fatal("dup failed");
client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0);
pid = getpid();
client_write_one(MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
for (ss = environ; *ss != NULL; ss++)
client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, strlen(*ss) + 1);

View File

@ -32,8 +32,8 @@ enum cmd_retval cmd_break_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_break_pane_entry = {
"break-pane", "breakp",
"dPF:t:", 0, 0,
"[-dP] [-F format] " CMD_TARGET_PANE_USAGE,
"dPF:s:t:", 0, 0,
"[-dP] [-F format] " CMD_SRCDST_PANE_USAGE,
0,
cmd_break_pane_exec
};
@ -48,13 +48,19 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w;
char *name;
char *cause;
int base_idx;
int idx;
struct format_tree *ft;
const char *template;
char *cp;
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
if ((wl = cmd_find_pane(cmdq, args_get(args, 's'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
return (CMD_RETURN_ERROR);
if (idx != -1 && winlink_find_by_index(&s->windows, idx) != NULL) {
cmdq_error(cmdq, "index %d already in use", idx);
return (CMD_RETURN_ERROR);
}
if (window_count_panes(wl->window) == 1) {
cmdq_error(cmdq, "can't break with only one pane");
@ -76,8 +82,9 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq)
free(name);
layout_init(w, wp);
base_idx = options_get_number(&s->options, "base-index");
wl = session_attach(s, w, -1 - base_idx, &cause); /* can't fail */
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");
wl = session_attach(s, w, idx, &cause); /* can't fail */
if (!args_has(self->args, 'd'))
session_select(s, wl->idx);

View File

@ -35,7 +35,7 @@ enum cmd_retval join_pane(struct cmd *, struct cmd_q *, int);
const struct cmd_entry cmd_join_pane_entry = {
"join-pane", "joinp",
"bdhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
"[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
0,
cmd_join_pane_exec
};
@ -43,7 +43,7 @@ const struct cmd_entry cmd_join_pane_entry = {
const struct cmd_entry cmd_move_pane_entry = {
"move-pane", "movep",
"bdhvp:l:s:t:", 0, 0,
"[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]",
"[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
0,
cmd_join_pane_exec
};

View File

@ -30,7 +30,7 @@ enum cmd_retval cmd_move_window_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_move_window_entry = {
"move-window", "movew",
"dkrs:t:", 0, 0,
"adkrs:t:", 0, 0,
"[-dkr] " CMD_SRCDST_WINDOW_USAGE,
0,
cmd_move_window_exec
@ -38,7 +38,7 @@ const struct cmd_entry cmd_move_window_entry = {
const struct cmd_entry cmd_link_window_entry = {
"link-window", "linkw",
"dks:t:", 0, 0,
"adks:t:", 0, 0,
"[-dk] " CMD_SRCDST_WINDOW_USAGE,
0,
cmd_move_window_exec
@ -72,6 +72,15 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq)
kflag = args_has(self->args, 'k');
dflag = args_has(self->args, 'd');
sflag = args_has(self->args, 's');
if (args_has(self->args, 'a')) {
s = cmd_find_session(cmdq, args_get(args, 't'), 0);
if (s == NULL)
return (CMD_RETURN_ERROR);
if ((idx = winlink_shuffle_up(s, s->curw)) == -1)
return (CMD_RETURN_ERROR);
}
if (server_link_window(src, wl, dst, idx, kflag, !dflag,
&cause) != 0) {
cmdq_error(cmdq, "can't link window: %s", cause);

View File

@ -51,7 +51,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct winlink *wl;
const char *cmd, *path, *template;
char **argv, *cause, *cp;
int argc, idx, last, detached, cwd, fd = -1;
int argc, idx, detached, cwd, fd = -1;
struct format_tree *ft;
struct environ_entry *envent;
@ -59,24 +59,10 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
if (wl == NULL)
return (CMD_RETURN_ERROR);
idx = wl->idx + 1;
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX) {
if ((idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(cmdq, "no free window indexes");
return (CMD_RETURN_ERROR);
}
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
}
} else {
idx = cmd_find_index(cmdq, args_get(args, 't'), &s);
if (idx == -2)

View File

@ -25,6 +25,8 @@
#include "tmux.h"
enum cmd_retval cmdq_continue_one(struct cmd_q *);
/* Create new command queue. */
struct cmd_q *
cmdq_new(struct client *c)
@ -160,14 +162,39 @@ cmdq_append(struct cmd_q *cmdq, struct cmd_list *cmdlist, struct mouse_event *m)
item->mouse.valid = 0;
}
/* Process one command. */
enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq)
{
struct cmd *cmd = cmdq->cmd;
enum cmd_retval retval;
char tmp[1024];
int flags = !!(cmd->flags & CMD_CONTROL);
cmd_print(cmd, tmp, sizeof tmp);
log_debug("cmdq %p: %s", cmdq, tmp);
cmdq->time = time(NULL);
cmdq->number++;
cmdq_guard(cmdq, "begin", flags);
retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error", flags);
else
cmdq_guard(cmdq, "end", flags);
return (retval);
}
/* Continue processing command queue. Returns 1 if finishes empty. */
int
cmdq_continue(struct cmd_q *cmdq)
{
struct cmd_q_item *next;
enum cmd_retval retval;
int empty, flags;
char s[1024];
int empty;
cmdq->references++;
notify_disable();
@ -184,23 +211,7 @@ cmdq_continue(struct cmd_q *cmdq)
do {
while (cmdq->cmd != NULL) {
cmd_print(cmdq->cmd, s, sizeof s);
log_debug("cmdq %p: %s (client %d)", cmdq, s,
cmdq->client != NULL ? cmdq->client->ibuf.fd : -1);
cmdq->time = time(NULL);
cmdq->number++;
flags = !!(cmdq->cmd->flags & CMD_CONTROL);
cmdq_guard(cmdq, "begin", flags);
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
if (retval == CMD_RETURN_ERROR)
cmdq_guard(cmdq, "error", flags);
else
cmdq_guard(cmdq, "end", flags);
retval = cmdq_continue_one(cmdq);
if (retval == CMD_RETURN_ERROR)
break;
if (retval == CMD_RETURN_WAIT)
@ -209,7 +220,6 @@ cmdq_continue(struct cmd_q *cmdq)
cmdq_flush(cmdq);
goto empty;
}
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
next = TAILQ_NEXT(cmdq->item, qentry);

View File

@ -272,6 +272,7 @@ format_create_status(int status)
*ptr = '\0';
format_add(ft, "host_short", "%s", host);
}
format_add(ft, "pid", "%ld", (long) getpid());
return (ft);
}
@ -338,7 +339,7 @@ format_find(struct format_tree *ft, const char *key)
case OPTIONS_STRING:
return (o->str);
case OPTIONS_NUMBER:
snprintf(s, sizeof s, "%lld", o->num);
xsnprintf(s, sizeof s, "%lld", o->num);
return (s);
case OPTIONS_STYLE:
return (style_tostring(&o->style));
@ -679,7 +680,7 @@ format_defaults_session(struct format_tree *ft, struct session *s)
RB_FOREACH (wl, winlinks, &s->windows) {
if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
continue;
snprintf(tmp, sizeof tmp, "%u", wl->idx);
xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
if (*alerts != '\0')
strlcat(alerts, ",", sizeof alerts);
@ -704,6 +705,7 @@ format_defaults_client(struct format_tree *ft, struct client *c)
if (ft->s == NULL)
ft->s = c->session;
format_add(ft, "client_pid", "%ld", (long) c->pid);
format_add(ft, "client_height", "%u", c->tty.sy);
format_add(ft, "client_width", "%u", c->tty.sx);
if (c->tty.path != NULL)
@ -748,6 +750,7 @@ void
format_defaults_window(struct format_tree *ft, struct window *w)
{
char *layout;
time_t t;
ft->w = w;
@ -756,6 +759,10 @@ format_defaults_window(struct format_tree *ft, struct window *w)
else
layout = layout_dump(w->layout_root);
t = w->activity_time.tv_sec;
format_add(ft, "window_activity", "%lld", (long long) t);
format_add(ft, "window_activity_string", "%s", format_time_string(t));
format_add(ft, "window_id", "@%u", w->id);
format_add(ft, "window_name", "%s", w->name);
format_add(ft, "window_width", "%u", w->sx);
@ -873,8 +880,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "pane_synchronized", "%d",
!!options_get_number(&wp->window->options, "synchronize-panes"));
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);
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
format_add(ft, "pane_current_path", "%s", cwd);

View File

@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tmux.h"
@ -849,6 +850,9 @@ input_parse(struct window_pane *wp)
wp->window->flags |= WINDOW_ACTIVITY;
wp->window->flags &= ~WINDOW_SILENCE;
if (gettimeofday(&wp->window->activity_time, NULL) != 0)
fatal("gettimeofday failed");
/*
* Open the screen. Use NULL wp if there is a mode set as don't want to
* update the tty.

13
job.c
View File

@ -99,6 +99,8 @@ job_run(const char *cmd, struct session *s, int cwd,
close(out[1]);
job = xmalloc(sizeof *job);
job->state = JOB_RUNNING;
job->cmd = xstrdup(cmd);
job->pid = pid;
job->status = 0;
@ -166,14 +168,13 @@ job_callback(unused struct bufferevent *bufev, unused short events, void *data)
log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
if (job->pid == -1) {
if (job->state == JOB_DEAD) {
if (job->callbackfn != NULL)
job->callbackfn(job);
job_free(job);
} else {
bufferevent_disable(job->event, EV_READ);
close(job->fd);
job->fd = -1;
job->state = JOB_CLOSED;
}
}
@ -185,10 +186,12 @@ job_died(struct job *job, int status)
job->status = status;
if (job->fd == -1) {
if (job->state == JOB_CLOSED) {
if (job->callbackfn != NULL)
job->callbackfn(job);
job_free(job);
} else
} else {
job->pid = -1;
job->state = JOB_DEAD;
}
}

View File

@ -1053,6 +1053,7 @@ server_client_msg_dispatch(struct client *c)
case MSG_IDENTIFY_CWD:
case MSG_IDENTIFY_STDIN:
case MSG_IDENTIFY_ENVIRON:
case MSG_IDENTIFY_CLIENTPID:
case MSG_IDENTIFY_DONE:
server_client_msg_identify(c, &imsg);
break;
@ -1227,6 +1228,11 @@ server_client_msg_identify(struct client *c, struct imsg *imsg)
if (strchr(data, '=') != NULL)
environ_put(&c->environ, data);
break;
case MSG_IDENTIFY_CLIENTPID:
if (datalen != sizeof c->pid)
fatalx("bad MSG_IDENTIFY_CLIENTPID size");
memcpy(&c->pid, data, sizeof c->pid);
break;
default:
break;
}

25
tmux.1
View File

@ -408,14 +408,15 @@ An
pattern which is matched against the session name.
.El
.Pp
If the session name is prefixed with a
.Ql = : ,
If the session name is prefixed with an
.Ql = ,
only an exact match is accepted (so
.Ql =mysess
will only match exactly
.Ql mysess ,
not
.Ql mysession ) .
.Pp
If a single session is found, it is used as the target session; multiple matches
produce an error.
If a session is omitted, the current session is used if available; if no
@ -1237,12 +1238,14 @@ Commands related to windows and panes are as follows:
.It Xo Ic break-pane
.Op Fl dP
.Op Fl F Ar format
.Op Fl t Ar target-pane
.Op Fl s Ar src-pane
.Op Fl t Ar dst-pane
.Xc
.D1 (alias: Ic breakp )
Break
.Ar target-pane
off from its containing window to make it the only pane in a new window.
.Ar src-pane
off from its containing window to make it the only pane in
.Ar dst-window .
If
.Fl d
is given, the new window does not become the current window.
@ -1548,7 +1551,7 @@ If no
.Ar target-session
is specified, select the last window of the current session.
.It Xo Ic link-window
.Op Fl dk
.Op Fl adk
.Op Fl s Ar src-window
.Op Fl t Ar dst-window
.Xc
@ -1562,6 +1565,10 @@ If
is specified and no such window exists, the
.Ar src-window
is linked there.
With
.Fl a ,
the window is moved to the next index up (following windows
are moved if necessary).
If
.Fl k
is given and
@ -1627,7 +1634,7 @@ and
.Ar dst-pane
may belong to the same window.
.It Xo Ic move-window
.Op Fl rdk
.Op Fl ardk
.Op Fl s Ar src-window
.Op Fl t Ar dst-window
.Xc
@ -3357,6 +3364,7 @@ The following variables are available, where appropriate:
.It Li "client_created_string" Ta "" Ta "String time client created"
.It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_last_session" Ta "" Ta "Name of the client's last session"
.It Li "client_pid" Ta "" Ta "PID of client process"
.It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed"
.It Li "client_readonly" Ta "" Ta "1 if client is readonly"
.It Li "client_session" Ta "" Ta "Name of the client's session"
@ -3401,6 +3409,7 @@ The following variables are available, where appropriate:
.It Li "pane_top" Ta "" Ta "Top of pane"
.It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane"
.It Li "pane_width" Ta "" Ta "Width of pane"
.It Li "pid" Ta "" Ta "Server PID"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
.It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
@ -3417,6 +3426,8 @@ The following variables are available, where appropriate:
.It Li "session_name" Ta "#S" Ta "Name of session"
.It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "window_activity" Ta "" Ta "Integer time of window last activity"
.It Li "window_activity_string" Ta "" Ta "String time of window last activity"
.It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity alert"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell"

10
tmux.h
View File

@ -429,6 +429,7 @@ enum msgtype {
MSG_IDENTIFY_STDIN,
MSG_IDENTIFY_ENVIRON,
MSG_IDENTIFY_DONE,
MSG_IDENTIFY_CLIENTPID,
MSG_COMMAND = 200,
MSG_DETACH,
@ -717,6 +718,12 @@ struct options {
/* Scheduled job. */
struct job {
enum {
JOB_RUNNING,
JOB_DEAD,
JOB_CLOSED
} state;
char *cmd;
pid_t pid;
int status;
@ -895,6 +902,7 @@ struct window {
char *name;
struct event name_timer;
struct timeval silence_timer;
struct timeval activity_time;
struct window_pane *active;
struct window_pane *last;
@ -1210,6 +1218,7 @@ RB_HEAD(status_out_tree, status_out);
struct client {
struct imsgbuf ibuf;
pid_t pid;
int fd;
struct event event;
int retval;
@ -2161,6 +2170,7 @@ struct window_pane *window_pane_find_right(struct window_pane *);
void window_set_name(struct window *, const char *);
void window_remove_ref(struct window *);
void winlink_clear_flags(struct winlink *);
int winlink_shuffle_up(struct session *, struct winlink *);
/* layout.c */
u_int layout_count_cells(struct layout_cell *);

View File

@ -294,6 +294,9 @@ window_create1(u_int sx, u_int sy)
w->sx = sx;
w->sy = sy;
if (gettimeofday(&w->activity_time, NULL) != 0)
fatal("gettimeofday failed");
options_init(&w->options, &global_w_options);
if (options_get_number(&w->options, "automatic-rename"))
queue_window_name(w);
@ -1389,3 +1392,28 @@ winlink_clear_flags(struct winlink *wl)
}
}
}
int
winlink_shuffle_up(struct session *s, struct winlink *wl)
{
int idx, last;
idx = wl->idx + 1;
/* Find the next free index. */
for (last = idx; last < INT_MAX; last++) {
if (winlink_find_by_index(&s->windows, last) == NULL)
break;
}
if (last == INT_MAX)
return (-1);
/* Move everything from last - 1 to idx up a bit. */
for (; last > idx; last--) {
wl = winlink_find_by_index(&s->windows, last - 1);
server_link_window(s, wl, s, last, 0, 0, NULL);
server_unlink_window(s, wl);
}
return (idx);
}