Add support for a single "marked pane". There is one marked pane in the

server at a time; it may be toggled or cleared with select-pane -m and
-M (the border is highlighted). A new target '~' or '{marked}' specifies
the marked pane to commands and it is the default target for the
swap-pane and join-pane -s flag (this makes them much simpler to use -
mark the source pane and then change to the target pane to run swapp or
joinp).
pull/15/head
nicm 2015-06-04 11:43:51 +00:00
parent a3edfd9e84
commit a863834574
11 changed files with 296 additions and 40 deletions

View File

@ -29,6 +29,7 @@
#define CMD_FIND_PREFER_UNATTACHED 0x1
#define CMD_FIND_QUIET 0x2
#define CMD_FIND_WINDOW_INDEX 0x4
#define CMD_FIND_DEFAULT_MARKED 0x8
enum cmd_find_type {
CMD_FIND_PANE,
@ -759,7 +760,14 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type,
/* Find current state. */
cmd_find_clear_state(&current, cmdq, flags);
if (cmd_find_current_session(&current) != 0) {
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
current.s = marked_session;
current.wl = marked_winlink;
current.idx = current.wl->idx;
current.w = current.wl->window;
current.wp = marked_window_pane;
}
if (current.s == NULL && cmd_find_current_session(&current) != 0) {
if (~flags & CMD_FIND_QUIET)
cmdq_error(cmdq, "no current session");
goto error;
@ -798,9 +806,24 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type,
}
return (&fs);
}
copy = xstrdup(target);
/* Marked target is a plain ~ or {marked}. */
if (strcmp(target, "~") == 0 || strcmp(target, "{marked}") == 0) {
if (!server_check_marked()) {
if (~flags & CMD_FIND_QUIET)
cmdq_error(cmdq, "no marked target");
goto error;
}
fs.s = marked_session;
fs.wl = marked_winlink;
fs.idx = fs.wl->idx;
fs.w = fs.wl->window;
fs.wp = marked_window_pane;
return (&fs);
}
/* Find separators if they exist. */
copy = xstrdup(target);
colon = strchr(copy, ':');
if (colon != NULL)
*colon++ = '\0';
@ -1053,6 +1076,24 @@ cmd_find_window(struct cmd_q *cmdq, const char *target, struct session **sp)
return (fs->wl);
}
/* Find the target window, defaulting to marked rather than current. */
struct winlink *
cmd_find_window_marked(struct cmd_q *cmdq, const char *target,
struct session **sp)
{
struct cmd_find_state *fs;
int flags = CMD_FIND_DEFAULT_MARKED;
fs = cmd_find_target(cmdq, target, CMD_FIND_WINDOW, flags);
cmd_find_log_state(__func__, target, fs);
if (fs == NULL)
return (NULL);
if (sp != NULL)
*sp = fs->s;
return (fs->wl);
}
/* Find the target pane and report an error and return NULL. */
struct winlink *
cmd_find_pane(struct cmd_q *cmdq, const char *target, struct session **sp,
@ -1072,6 +1113,26 @@ cmd_find_pane(struct cmd_q *cmdq, const char *target, struct session **sp,
return (fs->wl);
}
/* Find the target pane, defaulting to marked rather than current. */
struct winlink *
cmd_find_pane_marked(struct cmd_q *cmdq, const char *target,
struct session **sp, struct window_pane **wpp)
{
struct cmd_find_state *fs;
int flags = CMD_FIND_DEFAULT_MARKED;
fs = cmd_find_target(cmdq, target, CMD_FIND_PANE, flags);
cmd_find_log_state(__func__, target, fs);
if (fs == NULL)
return (NULL);
if (sp != NULL)
*sp = fs->s;
if (wpp != NULL)
*wpp = fs->wp;
return (fs->wl);
}
/* Find the target client or report an error and return NULL. */
struct client *
cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet)

View File

@ -75,7 +75,7 @@ join_pane(struct cmd *self, struct cmd_q *cmdq, int not_same_window)
dst_idx = dst_wl->idx;
server_unzoom_window(dst_w);
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
src_wl = cmd_find_pane_marked(cmdq, args_get(args, 's'), NULL, &src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;

View File

@ -28,8 +28,8 @@ enum cmd_retval cmd_select_pane_exec(struct cmd *, struct cmd_q *);
const struct cmd_entry cmd_select_pane_entry = {
"select-pane", "selectp",
"DdegLlP:Rt:U", 0, 0,
"[-DdegLlRU] [-P style] " CMD_TARGET_PANE_USAGE,
"DdegLlMmP:Rt:U", 0, 0,
"[-DdegLlMmRU] [-P style] " CMD_TARGET_PANE_USAGE,
0,
cmd_select_pane_exec
};
@ -47,7 +47,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct winlink *wl;
struct window_pane *wp;
struct session *s;
struct window_pane *wp, *lastwp, *markedwp;
const char *style;
if (self->entry == &cmd_last_pane_entry || args_has(args, 'l')) {
@ -74,9 +75,31 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
}
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL)
return (CMD_RETURN_ERROR);
if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL);
lastwp = marked_window_pane;
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked();
else
server_set_marked(s, wl, wp);
markedwp = marked_window_pane;
if (lastwp != NULL) {
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (args_has(args, 'P')) {
style = args_get(args, 'P');

View File

@ -58,18 +58,22 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
src_wl = dst_wl;
} else if (args_has(self->args, 'U')) {
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
src_wl = dst_wl;
} else {
src_wl = cmd_find_pane(cmdq, NULL, NULL, &src_wp);
src_wl = cmd_find_pane_marked(cmdq, NULL, NULL,
&src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;
}
} else {
src_wl = cmd_find_pane(cmdq, args_get(args, 's'), NULL, &src_wp);
src_wl = cmd_find_pane_marked(cmdq, args_get(args, 's'), NULL,
&src_wp);
if (src_wl == NULL)
return (CMD_RETURN_ERROR);
src_w = src_wl->window;

View File

@ -47,7 +47,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmd_q *cmdq)
struct window *w;
target_src = args_get(args, 's');
if ((wl_src = cmd_find_window(cmdq, target_src, &src)) == NULL)
if ((wl_src = cmd_find_window_marked(cmdq, target_src, &src)) == NULL)
return (CMD_RETURN_ERROR);
target_dst = args_get(args, 't');
if ((wl_dst = cmd_find_window(cmdq, target_dst, &dst)) == NULL)

View File

@ -177,6 +177,7 @@ key_bindings_init(void)
"bind ? list-keys",
"bind D choose-client",
"bind L switch-client -l",
"bind M select-pane -M",
"bind [ copy-mode",
"bind ] paste-buffer",
"bind c new-window",
@ -184,6 +185,7 @@ key_bindings_init(void)
"bind f command-prompt \"find-window '%%'\"",
"bind i display-message",
"bind l last-window",
"bind m select-pane -m",
"bind n next-window",
"bind o select-pane -t:.+",
"bind p previous-window",
@ -222,6 +224,7 @@ key_bindings_init(void)
"bind -n MouseDrag1Border resize-pane -M",
"bind -n MouseDown1Status select-window -t=",
"bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
"bind -n MouseDown3Pane select-pane -mt=",
};
u_int i;
struct cmd_list *cmdlist;

View File

@ -26,8 +26,8 @@ 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_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 *);
int screen_redraw_check_is(u_int, u_int, int, struct window *,
struct window_pane *, struct window_pane *);
void screen_redraw_draw_borders(struct client *, int, u_int);
void screen_redraw_draw_panes(struct client *, u_int);
@ -175,13 +175,13 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
return (CELL_OUTSIDE);
}
/* Check active pane indicator. */
/* Check if the border of a particular pane. */
int
screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
struct window_pane *wp)
screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
struct window_pane *wantwp, struct window_pane *wp)
{
/* Is this off the active pane border? */
if (screen_redraw_cell_border1(w->active, px, py) != 1)
if (screen_redraw_cell_border1(wantwp, px, py) != 1)
return (0);
/* If there are more than two panes, that's enough. */
@ -196,7 +196,7 @@ screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
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)
if (wp == wantwp)
return (px <= wp->sx / 2);
return (px > wp->sx / 2);
}
@ -207,7 +207,7 @@ screen_redraw_check_active(u_int px, u_int py, int type, struct window *w,
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)
if (wp == wantwp)
return (py <= wp->sy / 2);
return (py > wp->sy / 2);
}
@ -274,13 +274,15 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
void
screen_redraw_draw_borders(struct client *c, int status, u_int top)
{
struct window *w = c->session->curw->window;
struct session *s = c->session;
struct window *w = s->curw->window;
struct options *oo = &w->options;
struct tty *tty = &c->tty;
struct window_pane *wp;
struct grid_cell active_gc, other_gc, msg_gc;
struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc;
struct grid_cell msg_gc;
u_int i, j, type, msgx = 0, msgy = 0;
int small, flags;
int active, small, flags;
char msg[256];
const char *tmp;
size_t msglen = 0;
@ -314,15 +316,29 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
style_apply(&active_gc, oo, "pane-active-border-style");
active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET;
memcpy(&m_other_gc, &other_gc, sizeof m_other_gc);
m_other_gc.attr ^= GRID_ATTR_REVERSE;
memcpy(&m_active_gc, &active_gc, sizeof m_active_gc);
m_active_gc.attr ^= GRID_ATTR_REVERSE;
for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) {
type = screen_redraw_check_cell(c, i, j, &wp);
if (type == CELL_INSIDE)
continue;
if (type == CELL_OUTSIDE &&
small && i > msgx && j == msgy)
if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy)
continue;
if (screen_redraw_check_active(i, j, type, w, wp))
active = screen_redraw_check_is(i, j, type, w,
w->active, wp);
if (server_is_marked(s, s->curw, marked_window_pane) &&
screen_redraw_check_is(i, j, type, w,
marked_window_pane, wp)) {
if (active)
tty_attributes(tty, &m_active_gc, NULL);
else
tty_attributes(tty, &m_other_gc, NULL);
} else if (active)
tty_attributes(tty, &active_gc, NULL);
else
tty_attributes(tty, &other_gc, NULL);

View File

@ -50,19 +50,85 @@ int server_shutdown;
struct event server_ev_accept;
struct event server_ev_second;
int server_create_socket(void);
void server_loop(void);
int server_should_shutdown(void);
void server_send_shutdown(void);
void server_clean_dead(void);
void server_accept_callback(int, short, void *);
void server_signal_callback(int, short, void *);
void server_child_signal(void);
void server_child_exited(pid_t, int);
void server_child_stopped(pid_t, int);
void server_second_callback(int, short, void *);
void server_lock_server(void);
void server_lock_sessions(void);
struct session *marked_session;
struct winlink *marked_winlink;
struct window *marked_window;
struct window_pane *marked_window_pane;
struct layout_cell *marked_layout_cell;
int server_create_socket(void);
void server_loop(void);
int server_should_shutdown(void);
void server_send_shutdown(void);
void server_clean_dead(void);
void server_accept_callback(int, short, void *);
void server_signal_callback(int, short, void *);
void server_child_signal(void);
void server_child_exited(pid_t, int);
void server_child_stopped(pid_t, int);
void server_second_callback(int, short, void *);
void server_lock_server(void);
void server_lock_sessions(void);
/* Set marked pane. */
void
server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
{
marked_session = s;
marked_winlink = wl;
marked_window = wl->window;
marked_window_pane = wp;
marked_layout_cell = wp->layout_cell;
}
/* Clear marked pane. */
void
server_clear_marked(void)
{
marked_session = NULL;
marked_winlink = NULL;
marked_window = NULL;
marked_window_pane = NULL;
marked_layout_cell = NULL;
}
/* Is this the marked pane? */
int
server_is_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
{
if (s == NULL || wl == NULL || wp == NULL)
return (0);
if (marked_session != s || marked_winlink != wl)
return (0);
if (marked_window_pane != wp)
return (0);
return (server_check_marked());
}
/* Check if the marked pane is still valid. */
int
server_check_marked(void)
{
struct winlink *wl;
if (marked_window_pane == NULL)
return (0);
if (marked_layout_cell != marked_window_pane->layout_cell)
return (0);
if (!session_alive(marked_session))
return (0);
RB_FOREACH(wl, winlinks, &marked_session->windows) {
if (wl->window == marked_window && wl == marked_winlink)
break;
}
if (wl == NULL)
return (0);
if (!window_has_pane(marked_window, marked_window_pane))
return (0);
return (window_pane_visible(marked_window_pane));
}
/* Create server socket. */
int

71
tmux.1
View File

@ -298,6 +298,12 @@ Change to the previous window.
Briefly display pane indexes.
.It r
Force redraw of the attached client.
.It m
Mark the current pane (see
.Ic select-pane
.Fl m ) .
.It M
Clear the marked pane.
.It s
Select a new session for the attached client interactively.
.It t
@ -351,6 +357,8 @@ This section contains a list of the commands supported by
.Nm .
Most commands accept the optional
.Fl t
(and sometimes
.Fl s )
argument with one of
.Ar target-client ,
.Ar target-session
@ -451,7 +459,6 @@ Each has a single-character alternative form.
.It Li "{last}" Ta "!" Ta "The last (previously current) window"
.It Li "{next}" Ta "+" Ta "The next window by number"
.It Li "{previous}" Ta "-" Ta "The previous window by number"
.It Li "{mouse}" Ta "=" Ta "The window where the mouse event happened"
.El
.Pp
.Ar target-pane
@ -481,7 +488,6 @@ The following special tokens are available for the pane index:
.It Li "{down}" Ta "" Ta "The pane below the active pane"
.It Li "{left}" Ta "" Ta "The pane to the left of the active pane"
.It Li "{right}" Ta "" Ta "The pane to the right of the active pane"
.It Li "{mouse}" Ta "=" Ta "The pane where the mouse event happened"
.El
.Pp
The tokens
@ -493,6 +499,27 @@ may be followed by an offset, for example:
select-window -t:+2
.Ed
.Pp
In addition,
.Em target-session ,
.Em target-window
or
.Em target-pane
may consist entirely of the token
.Ql {mouse}
(alternative form
.Ql = )
to specify the most recent mouse event
(see the
.Sx MOUSE SUPPORT
section)
or
.Ql {marked}
(alternative form
.Ql ~ )
to specify the marked pane (see
.Ic select-pane
.Fl m ) .
.Pp
Sessions, window and panes are each numbered with a unique ID; session IDs are
prefixed with a
.Ql $ ,
@ -1440,6 +1467,13 @@ option causes
.Ar src-pane
to be joined to left of or above
.Ar dst-pane .
.Pp
If
.Fl s
is omitted and a marked pane is present (see
.Ic select-pane
.Fl m ) ,
the marked pane is used rather than the current pane.
.It Xo Ic kill-pane
.Op Fl a
.Op Fl t Ar target-pane
@ -1795,7 +1829,7 @@ commands.
.Fl o
applies the last set layout if possible (undoes the most recent layout change).
.It Xo Ic select-pane
.Op Fl DdegLlRU
.Op Fl DdegLlMmRU
.Op Fl P Ar style
.Op Fl t Ar target-pane
.Xc
@ -1823,6 +1857,20 @@ enables or
.Fl d
disables input to the pane.
.Pp
.Fl m
and
.Fl M
are used to set and clear the
.Em marked pane .
There is one marked pane at a time, setting a new marked pane clears the last.
The marked pane is the default target for
.Fl s
to
.Ic join-pane ,
.Ic swap-pane
and
.Ic swap-window .
.Pp
Each pane has a style: by default the
.Ic window-style
and
@ -1911,6 +1959,13 @@ swaps with the next pane (after it numerically).
instructs
.Nm
not to change the active pane.
.Pp
If
.Fl s
is omitted and a marked pane is present (see
.Ic select-pane
.Fl m ) ,
the marked pane is used rather than the current pane.
.It Xo Ic swap-window
.Op Fl d
.Op Fl s Ar src-window
@ -1922,6 +1977,15 @@ This is similar to
except the source and destination windows are swapped.
It is an error if no window exists at
.Ar src-window .
.Pp
Like
.Ic swap-pane ,
if
.Fl s
is omitted and a marked pane is present (see
.Ic select-pane
.Fl m ) ,
the window containing the marked pane is used rather than the current window.
.It Xo Ic unlink-window
.Op Fl k
.Op Fl t Ar target-window
@ -3488,6 +3552,7 @@ The flag is one of the following symbols appended to the window name:
.It Li "#" Ta "Window is monitored and activity has been detected."
.It Li "!" Ta "A bell has occurred in the window."
.It Li "~" Ta "The window has been silent for the monitor-silence interval."
.It Li "M" Ta "The window contains the marked pane."
.It Li "Z" Ta "The window's active pane is zoomed."
.El
.Pp

13
tmux.h
View File

@ -1688,8 +1688,12 @@ struct session *cmd_find_current(struct cmd_q *);
struct session *cmd_find_session(struct cmd_q *, const char *, int);
struct winlink *cmd_find_window(struct cmd_q *, const char *,
struct session **);
struct winlink *cmd_find_window_marked(struct cmd_q *, const char *,
struct session **);
struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
struct window_pane **);
struct winlink *cmd_find_pane_marked(struct cmd_q *, const char *,
struct session **, struct window_pane **);
struct client *cmd_find_client(struct cmd_q *, const char *, int);
int cmd_find_index(struct cmd_q *, const char *,
struct session **);
@ -1850,6 +1854,15 @@ const char *key_string_lookup_key(int);
/* server.c */
extern struct clients clients;
extern struct clients dead_clients;
extern struct session *marked_session;
extern struct winlink *marked_winlink;
extern struct window_pane *marked_window_pane;
void server_set_marked(struct session *, struct winlink *,
struct window_pane *);
void server_clear_marked(void);
int server_is_marked(struct session *, struct winlink *,
struct window_pane *);
int server_check_marked(void);
int server_start(int, char *);
void server_update_socket(void);
void server_add_accept(int);

View File

@ -543,6 +543,9 @@ window_add_pane(struct window *w, u_int hlimit)
void
window_lost_pane(struct window *w, struct window_pane *wp)
{
if (wp == marked_window_pane)
server_clear_marked();
if (wp == w->active) {
w->active = w->last;
w->last = NULL;
@ -661,6 +664,8 @@ window_printable_flags(struct session *s, struct winlink *wl)
flags[pos++] = '*';
if (wl == TAILQ_FIRST(&s->lastw))
flags[pos++] = '-';
if (server_check_marked() && wl == marked_winlink)
flags[pos++] = 'M';
if (wl->window->flags & WINDOW_ZOOMED)
flags[pos++] = 'Z';
flags[pos] = '\0';