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

This commit is contained in:
Nicholas Marriott 2013-03-17 23:45:19 +00:00
commit f5de847a0c
9 changed files with 195 additions and 30 deletions

View File

@ -524,6 +524,7 @@ client_dispatch_wait(void *data)
event_del(&client_stdin); event_del(&client_stdin);
client_attached = 1; client_attached = 1;
client_write_server(MSG_RESIZE, NULL, 0);
break; break;
case MSG_STDIN: case MSG_STDIN:
if (datalen != 0) if (datalen != 0)

View File

@ -70,6 +70,18 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'c')) {
c = cmd_find_client(cmdq, args_get(args, 'c'), 0);
if (c == NULL)
return (CMD_RETURN_ERROR);
} else {
c = cmd_current_client(cmdq);
if (c == NULL && !args_has(self->args, 'p')) {
cmdq_error(cmdq, "no client available");
return (CMD_RETURN_ERROR);
}
}
template = args_get(args, 'F'); template = args_get(args, 'F');
if (args->argc != 0) if (args->argc != 0)
template = args->argv[0]; template = args->argv[0];
@ -77,7 +89,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
template = DISPLAY_MESSAGE_TEMPLATE; template = DISPLAY_MESSAGE_TEMPLATE;
ft = format_create(); ft = format_create();
if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 1)) != NULL) if (c != NULL)
format_client(ft, c); format_client(ft, c);
format_session(ft, s); format_session(ft, s);
format_winlink(ft, s, wl); format_winlink(ft, s, wl);

View File

@ -152,19 +152,20 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...)
} }
/* Print a guard line. */ /* Print a guard line. */
void int
cmdq_guard(struct cmd_q *cmdq, const char *guard) cmdq_guard(struct cmd_q *cmdq, const char *guard)
{ {
struct client *c = cmdq->client; struct client *c = cmdq->client;
if (c == NULL || c->session == NULL) if (c == NULL || c->session == NULL)
return; return 0;
if (!(c->flags & CLIENT_CONTROL)) if (!(c->flags & CLIENT_CONTROL))
return; return 0;
evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard, evbuffer_add_printf(c->stdout_data, "%%%s %ld %u\n", guard,
(long) cmdq->time, cmdq->number); (long) cmdq->time, cmdq->number);
server_push_stdout(c); server_push_stdout(c);
return 1;
} }
/* Add command list to queue and begin processing if needed. */ /* Add command list to queue and begin processing if needed. */
@ -197,7 +198,7 @@ cmdq_continue(struct cmd_q *cmdq)
{ {
struct cmd_q_item *next; struct cmd_q_item *next;
enum cmd_retval retval; enum cmd_retval retval;
int empty; int empty, guard;
char s[1024]; char s[1024];
notify_disable(); notify_disable();
@ -223,12 +224,14 @@ cmdq_continue(struct cmd_q *cmdq)
cmdq->time = time(NULL); cmdq->time = time(NULL);
cmdq->number++; cmdq->number++;
cmdq_guard(cmdq, "begin"); guard = cmdq_guard(cmdq, "begin");
retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq);
if (retval == CMD_RETURN_ERROR) if (guard) {
cmdq_guard(cmdq, "error"); if (retval == CMD_RETURN_ERROR)
else cmdq_guard(cmdq, "error");
cmdq_guard(cmdq, "end"); else
cmdq_guard(cmdq, "end");
}
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
break; break;

View File

@ -46,8 +46,12 @@ control_notify_input(struct client *c, struct window_pane *wp,
if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) { if (winlink_find_by_window(&c->session->windows, wp->window) != NULL) {
message = evbuffer_new(); message = evbuffer_new();
evbuffer_add_printf(message, "%%output %%%u ", wp->id); evbuffer_add_printf(message, "%%output %%%u ", wp->id);
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
evbuffer_add_printf(message, "%02hhx", buf[i]); if (buf[i] < ' ' || buf[i] == '\\')
evbuffer_add_printf(message, "\\%03o", buf[i]);
else
evbuffer_add_printf(message, "%c", buf[i]);
}
control_write_buffer(c, message); control_write_buffer(c, message);
evbuffer_free(message); evbuffer_free(message);
} }
@ -104,7 +108,7 @@ control_notify_window_unlinked(unused struct session *s, struct window *w)
continue; continue;
cs = c->session; cs = c->session;
control_write(c, "%%window-close %u", w->id); control_write(c, "%%window-close @%u", w->id);
} }
} }
@ -122,9 +126,9 @@ control_notify_window_linked(unused struct session *s, struct window *w)
cs = c->session; cs = c->session;
if (winlink_find_by_window_id(&cs->windows, w->id) != NULL) if (winlink_find_by_window_id(&cs->windows, w->id) != NULL)
control_write(c, "%%window-add %u", w->id); control_write(c, "%%window-add @%u", w->id);
else else
control_write(c, "%%unlinked-window-add %u", w->id); control_write(c, "%%unlinked-window-add @%u", w->id);
} }
} }
@ -141,7 +145,7 @@ control_notify_window_renamed(struct window *w)
continue; continue;
s = c->session; s = c->session;
control_write(c, "%%window-renamed %u %s", w->id, w->name); control_write(c, "%%window-renamed @%u %s", w->id, w->name);
} }
} }
@ -154,7 +158,7 @@ control_notify_attached_session_changed(struct client *c)
return; return;
s = c->session; s = c->session;
control_write(c, "%%session-changed %d %s", s->id, s->name); control_write(c, "%%session-changed $%u %s", s->id, s->name);
} }
void void
@ -165,10 +169,10 @@ control_notify_session_renamed(struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session != s) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue; continue;
control_write(c, "%%session-renamed %s", s->name); control_write(c, "%%session-renamed $%u %s", s->id, s->name);
} }
} }
@ -180,7 +184,7 @@ control_notify_session_created(unused struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue; continue;
control_write(c, "%%sessions-changed"); control_write(c, "%%sessions-changed");
@ -195,7 +199,7 @@ control_notify_session_close(unused struct session *s)
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue; continue;
control_write(c, "%%sessions-changed"); control_write(c, "%%sessions-changed");

View File

@ -280,7 +280,7 @@ format_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
format_add(ft, "session_width", "%u", s->sx); format_add(ft, "session_width", "%u", s->sx);
format_add(ft, "session_height", "%u", s->sy); format_add(ft, "session_height", "%u", s->sy);
format_add(ft, "session_id", "%u", s->id); format_add(ft, "session_id", "$%u", s->id);
sg = session_group_find(s); sg = session_group_find(s);
format_add(ft, "session_grouped", "%d", sg != NULL); format_add(ft, "session_grouped", "%d", sg != NULL);

View File

@ -24,7 +24,11 @@
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int); int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
int screen_redraw_cell_border(struct client *, u_int, u_int); int screen_redraw_cell_border(struct client *, u_int, u_int);
int screen_redraw_check_cell(struct client *, u_int, u_int); int screen_redraw_check_cell(struct client *, u_int, u_int,
struct window_pane **);
int screen_redraw_check_active(u_int, u_int, int, struct window *,
struct window_pane *);
void screen_redraw_draw_number(struct client *, struct window_pane *); void screen_redraw_draw_number(struct client *, struct window_pane *);
#define CELL_INSIDE 0 #define CELL_INSIDE 0
@ -93,7 +97,8 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
/* Check if cell inside a pane. */ /* Check if cell inside a pane. */
int int
screen_redraw_check_cell(struct client *c, u_int px, u_int py) screen_redraw_check_cell(struct client *c, u_int px, u_int py,
struct window_pane **wpp)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@ -105,6 +110,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py)
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
*wpp = wp;
/* If outside the pane and its border, skip it. */ /* If outside the pane and its border, skip it. */
if ((wp->xoff != 0 && px < wp->xoff - 1) || if ((wp->xoff != 0 && px < wp->xoff - 1) ||
@ -162,9 +168,52 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py)
} }
} }
*wpp = NULL;
return (CELL_OUTSIDE); return (CELL_OUTSIDE);
} }
/* Check active pane indicator. */
int
screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
struct window_pane *wp)
{
/* Is this off the active pane border? */
if (screen_redraw_cell_border1(w->active, px, py) != 1)
return (0);
/* If there are more than two panes, that's enough. */
if (window_count_panes(w) != 2)
return (1);
/* Else if the cell is not a border cell, forget it. */
if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
return (1);
/* Check if the pane covers the whole width. */
if (wp->xoff == 0 && wp->sx == w->sx) {
/* This can either be the top pane or the bottom pane. */
if (wp->yoff == 0) { /* top pane */
if (wp == w->active)
return (px <= wp->sx / 2);
return (px > wp->sx / 2);
}
return (0);
}
/* Check if the pane covers the whole height. */
if (wp->yoff == 0 && wp->sy == w->sy) {
/* This can either be the left pane or the right pane. */
if (wp->xoff == 0) { /* left pane */
if (wp == w->active)
return (py <= wp->sy / 2);
return (py > wp->sy / 2);
}
return (0);
}
return (type);
}
/* Redraw entire screen. */ /* Redraw entire screen. */
void void
screen_redraw_screen(struct client *c, int status_only, int borders_only) screen_redraw_screen(struct client *c, int status_only, int borders_only)
@ -223,10 +272,10 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only)
break; break;
} }
for (i = 0; i < tty->sx; i++) { for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j); type = screen_redraw_check_cell(c, i, j, &wp);
if (type == CELL_INSIDE) if (type == CELL_INSIDE)
continue; continue;
if (screen_redraw_cell_border1(w->active, i, j) == 1) if (screen_redraw_check_active(i, j, type, w, wp))
tty_attributes(tty, &active_gc); tty_attributes(tty, &active_gc);
else else
tty_attributes(tty, &other_gc); tty_attributes(tty, &other_gc);

98
tmux.1
View File

@ -23,7 +23,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm tmux .Nm tmux
.Bk -words .Bk -words
.Op Fl 28lquvV .Op Fl 28lCquvV
.Op Fl c Ar shell-command .Op Fl c Ar shell-command
.Op Fl f Ar file .Op Fl f Ar file
.Op Fl L Ar socket-name .Op Fl L Ar socket-name
@ -102,6 +102,11 @@ to assume the terminal supports 256 colours.
Like Like
.Fl 2 , .Fl 2 ,
but indicates that the terminal supports 88 colours. but indicates that the terminal supports 88 colours.
.It Fl C
Start in control mode.
Given twice
.Xo ( Fl CC ) Xc
disables echo.
.It Fl c Ar shell-command .It Fl c Ar shell-command
Execute Execute
.Ar shell-command .Ar shell-command
@ -1622,8 +1627,8 @@ is given in lines or cells (the default is 1).
.Pp .Pp
With With
.Fl Z , .Fl Z ,
the active pane is toggled between occupying the whole of the window and its the active pane is toggled between zoomed (occupying the whole of the window)
normal position in the layout. and unzoomed (its normal position in the layout).
.It Xo Ic respawn-pane .It Xo Ic respawn-pane
.Op Fl k .Op Fl k
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
@ -3255,6 +3260,7 @@ The flag is one of the following symbols appended to the window name:
.It Li "!" Ta "A bell has occurred in the window." .It Li "!" Ta "A bell has occurred in the window."
.It Li "+" Ta "Window is monitored for content and it has appeared." .It Li "+" Ta "Window is monitored for content and it has appeared."
.It Li "~" Ta "The window has been silent for the monitor-silence interval." .It Li "~" Ta "The window has been silent for the monitor-silence interval."
.It Li "Z" Ta "The window's active pane is zoomed."
.El .El
.Pp .Pp
The # symbol relates to the The # symbol relates to the
@ -3613,6 +3619,92 @@ option above and the
.Xr xterm 1 .Xr xterm 1
man page. man page.
.El .El
.Sh CONTROL MODE
.Nm
offers a textual interface called
.Em control mode .
This allows applications to communicate with
.Nm
using a simple text-only protocol.
.Pp
In control mode, a client sends
.Nm
commands or command sequences terminated by newlines on standard input.
Each command will produce one block of output on standard output.
An output block consists of a
.Em %begin
line followed by the output (which may be empty).
The output block ends with a
.Em %end
or
.Em %error .
.Em %begin
and matching
.Em %end
or
.Em %error
have two arguments: an integer time (as seconds from epoch) and command number.
For example:
.Bd -literal -offset indent
%begin 1363006971 2
0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active)
%end 1363006971 2
.Ed
.Pp
In control mode,
.Nm
outputs notifications.
A notification will never occur inside an output block.
.Pp
The following notifications are defined:
.Pp
.Bl -tag -width Ds
.It Ic %exit Op Ar reason
The
.Nm
client is exiting immediately, either because it is not attached to any session
or an error occurred.
If present,
.Ar reason
describes why the client exited.
.It Ic %layout-change Ar window-id Ar window-layout
The layout of a window with ID
.Ar window-id
changed.
The new layout is
.Ar window-layout .
.It Ic %output Ar pane-id Ar value
A window pane produced output.
.Ar value
escapes non-printable characters and backslash as octal \\xxx.
.It Ic %session-changed Ar session-id Ar name
The client is now attached to the session with ID
.Ar session-id ,
which is named
.Ar name .
.It Ic %session-renamed Ar name
The current session was renamed to
.Ar name .
.It Ic %sessions-changed
A session was created or destroyed.
.It Ic %unlinked-window-add Ar window-id
The window with ID
.Ar window-id
was created but is not linked to the current session.
.It Ic %window-add Ar window-id
The window with ID
.Ar window-id
was linked to the current session.
.It Ic %window-close Ar window-id
The window with ID
.Ar window-id
closed.
.It Ic %window-renamed Ar window-id Ar name
The window with ID
.Ar window-id
was renamed to
.Ar name .
.El
.Sh FILES .Sh FILES
.Bl -tag -width "/etc/tmux.confXXX" -compact .Bl -tag -width "/etc/tmux.confXXX" -compact
.It Pa ~/.tmux.conf .It Pa ~/.tmux.conf

2
tmux.h
View File

@ -1856,7 +1856,7 @@ int cmdq_free(struct cmd_q *);
void printflike2 cmdq_print(struct cmd_q *, const char *, ...); void printflike2 cmdq_print(struct cmd_q *, const char *, ...);
void printflike2 cmdq_info(struct cmd_q *, const char *, ...); void printflike2 cmdq_info(struct cmd_q *, const char *, ...);
void printflike2 cmdq_error(struct cmd_q *, const char *, ...); void printflike2 cmdq_error(struct cmd_q *, const char *, ...);
void cmdq_guard(struct cmd_q *, const char *); int cmdq_guard(struct cmd_q *, const char *);
void cmdq_run(struct cmd_q *, struct cmd_list *); void cmdq_run(struct cmd_q *, struct cmd_list *);
void cmdq_append(struct cmd_q *, struct cmd_list *); void cmdq_append(struct cmd_q *, struct cmd_list *);
int cmdq_continue(struct cmd_q *); int cmdq_continue(struct cmd_q *);

View File

@ -480,6 +480,10 @@ window_zoom(struct window_pane *wp)
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
return (-1); return (-1);
if (window_count_panes(w) == 1)
return (-1);
if (w->active != wp) if (w->active != wp)
window_set_active_pane(w, wp); window_set_active_pane(w, wp);