Allow session tree (C-b s) to expand and collapse sessions with

left/right/space keys. From Thomas Adam.
This commit is contained in:
Nicholas Marriott 2012-10-02 08:16:28 +00:00
parent ea289bc457
commit 9107b0c69a
3 changed files with 490 additions and 253 deletions

View File

@ -83,6 +83,9 @@ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
{ MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
{ MODEKEYCHOICE_SCROLLUP, "scroll-up" },
{ MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
{ MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
{ MODEKEYCHOICE_TREE_EXPAND_ALL, "tree-expand-all" },
{ MODEKEYCHOICE_TREE_TOGGLE, "tree-toggle" },
{ MODEKEYCHOICE_UP, "up" },
{ 0, NULL }
@ -212,12 +215,15 @@ const struct mode_key_entry mode_key_vi_choice[] = {
{ 'k', 0, MODEKEYCHOICE_UP },
{ 'q', 0, MODEKEYCHOICE_CANCEL },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCHOICE_UP },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL },
{ 0, -1, 0 }
};
@ -280,7 +286,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT },
{ KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE },
@ -349,12 +355,17 @@ const struct mode_key_entry mode_key_emacs_choice[] = {
{ 'q', 0, MODEKEYCHOICE_CANCEL },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_BSPACE, 0, MODEKEYCHOICE_BACKSPACE },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCHOICE_DOWN },
{ KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN },
{ KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP },
{ KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP },
{ KEYC_UP, 0, MODEKEYCHOICE_UP },
{ ' ', 0, MODEKEYCHOICE_TREE_TOGGLE },
{ KEYC_LEFT, 0, MODEKEYCHOICE_TREE_COLLAPSE },
{ KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND },
{ KEYC_LEFT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
{ KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL },
{ 0, -1, 0 }
};
@ -408,7 +419,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ 't', 0, MODEKEYCOPY_JUMPTO },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
{ KEYC_LEFT, 0, MODEKEYCOPY_LEFT },

13
tmux.h
View File

@ -552,6 +552,11 @@ enum mode_key_cmd {
MODEKEYCHOICE_SCROLLDOWN,
MODEKEYCHOICE_SCROLLUP,
MODEKEYCHOICE_STARTNUMBERPREFIX,
MODEKEYCHOICE_TREE_COLLAPSE,
MODEKEYCHOICE_TREE_COLLAPSE_ALL,
MODEKEYCHOICE_TREE_EXPAND,
MODEKEYCHOICE_TREE_EXPAND_ALL,
MODEKEYCHOICE_TREE_TOGGLE,
MODEKEYCHOICE_UP,
/* Copy keys. */
@ -891,12 +896,16 @@ struct window_mode {
/* Structures for choose mode. */
struct window_choose_data {
struct client *client;
struct session *session;
struct session *session; /* Session of current client. */
struct session *tree_session; /* Session of items in tree. */
struct format_tree *ft;
struct winlink *wl;
char *ft_template;
char *command;
u_int idx;
int type;
#define TREE_WINDOW 0x1
#define TREE_SESSION 0x2
int pane_id;
};
@ -904,6 +913,8 @@ struct window_choose_mode_item {
struct window_choose_data *wcd;
char *name;
int pos;
int state;
#define TREE_EXPANDED 0x1
};
/* Child window structure. */

View File

@ -40,6 +40,11 @@ void window_choose_write_line(
void window_choose_scroll_up(struct window_pane *);
void window_choose_scroll_down(struct window_pane *);
void window_choose_collapse(struct window_pane *, struct session *);
void window_choose_expand(struct window_pane *, struct session *, u_int);
void window_choose_collapse_all(struct window_pane *);
void window_choose_expand_all(struct window_pane *);
enum window_choose_input_type {
WINDOW_CHOOSE_NORMAL = -1,
WINDOW_CHOOSE_GOTO_ITEM,
@ -60,6 +65,7 @@ struct window_choose_mode_data {
struct mode_key_data mdata;
ARRAY_DECL(, struct window_choose_mode_item) list;
ARRAY_DECL(, struct window_choose_mode_item) old_list;
int width;
u_int top;
u_int selected;
@ -89,6 +95,7 @@ window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
item->name = format_expand(wcd->ft, wcd->ft_template);
item->wcd = wcd;
item->pos = ARRAY_LENGTH(&data->list) - 1;
item->state = 0;
data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos);
}
@ -108,6 +115,9 @@ window_choose_ready(struct window_pane *wp, u_int cur,
data->callbackfn = callbackfn;
data->freefn = freefn;
ARRAY_CONCAT(&data->old_list, &data->list);
window_choose_collapse_all(wp);
window_choose_redraw_screen(wp);
}
@ -127,6 +137,7 @@ window_choose_init(struct window_pane *wp)
data->input_prompt = NULL;
ARRAY_INIT(&data->list);
ARRAY_INIT(&data->old_list);
data->top = 0;
s = &data->screen;
@ -154,9 +165,11 @@ window_choose_data_create(struct cmd_ctx *ctx)
wcd->ft_template = NULL;
wcd->command = NULL;
wcd->wl = NULL;
wcd->tree_session = NULL;
wcd->client = ctx->curclient;
wcd->session = ctx->curclient->session;
wcd->idx = -1;
wcd->type = 0;
return (wcd);
}
@ -175,6 +188,7 @@ window_choose_free(struct window_pane *wp)
free(item->name);
}
ARRAY_FREE(&data->list);
ARRAY_FREE(&data->old_list);
free(data->input_str);
screen_free(&data->screen);
@ -228,6 +242,166 @@ window_choose_prompt_input(enum window_choose_input_type input_type,
window_choose_redraw_screen(wp);
}
void
window_choose_collapse(struct window_pane *wp, struct session *s)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item, *chosen;
struct window_choose_data *wcd;
u_int i, pos;
ARRAY_DECL(, struct window_choose_mode_item) list_copy;
ARRAY_INIT(&list_copy);
pos = data->selected;
chosen = &ARRAY_ITEM(&data->list, pos);
chosen->state &= ~TREE_EXPANDED;
/*
* Trying to mangle the &data->list in-place has lots of problems, so
* assign the actual result we want to render and copy the new one over
* the top of it.
*/
for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
{
item = &ARRAY_ITEM(&data->list, i);
wcd = item->wcd;
if (s == wcd->tree_session) {
/* We only show the session when collapsed. */
if (wcd->type & TREE_SESSION) {
item->state &= ~TREE_EXPANDED;
ARRAY_ADD(&list_copy,
ARRAY_ITEM(&data->list, i));
/*
* Update the selection to this session item so
* we don't end up highlighting a non-existent
* item.
*/
data->selected = i;
}
} else
ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
}
if (!ARRAY_EMPTY(&list_copy)) {
ARRAY_FREE(&data->list);
ARRAY_CONCAT(&data->list, &list_copy);
}
}
void
window_choose_collapse_all(struct window_pane *wp)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item, *chosen;
struct session *s;
u_int i;
chosen = &ARRAY_ITEM(&data->list, data->selected);
RB_FOREACH(s, sessions, &sessions)
window_choose_collapse(wp, s);
/* Reset the selection back to the starting session. */
for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
item = &ARRAY_ITEM(&data->list, i);
if (chosen->wcd->session != item->wcd->tree_session)
continue;
if (item->wcd->type & TREE_SESSION)
data->selected = i;
}
window_choose_redraw_screen(wp);
}
void
window_choose_expand_all(struct window_pane *wp)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item;
struct session *s;
u_int i;
RB_FOREACH(s, sessions, &sessions) {
for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
item = &ARRAY_ITEM(&data->list, i);
if (s != item->wcd->tree_session)
continue;
if (item->wcd->type & TREE_SESSION)
window_choose_expand(wp, s, i);
}
}
window_choose_redraw_screen(wp);
}
void
window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
{
struct window_choose_mode_data *data = wp->modedata;
struct window_choose_mode_item *item, *chosen;
struct window_choose_data *wcd;
u_int i, items;
chosen = &ARRAY_ITEM(&data->list, pos);
items = ARRAY_LENGTH(&data->old_list) - 1;
/* It's not possible to expand anything other than sessions. */
if (!(chosen->wcd->type & TREE_SESSION))
return;
/* Don't re-expand a session which is already expanded. */
if (chosen->state & TREE_EXPANDED)
return;
/* Mark the session entry as expanded. */
chosen->state |= TREE_EXPANDED;
/*
* Go back through the original list of all sessions and windows, and
* pull out the windows where the session matches the selection chosen
* to expand.
*/
for (i = items; i > 0; i--) {
item = &ARRAY_ITEM(&data->old_list, i);
item->state |= TREE_EXPANDED;
wcd = item->wcd;
if (s == wcd->tree_session) {
/*
* Since the session is already displayed, we only care
* to add back in window for it.
*/
if (wcd->type & TREE_WINDOW) {
/*
* If the insertion point for adding the
* windows to the session falls inside the
* range of the list, then we insert these
* entries in order *AFTER* the selected
* session.
*/
if (pos < i ) {
ARRAY_INSERT(&data->list,
pos + 1,
ARRAY_ITEM(&data->old_list,
i));
} else {
/* Ran out of room, add to the end. */
ARRAY_ADD(&data->list,
ARRAY_ITEM(&data->old_list,
i));
}
}
}
}
}
/* ARGSUSED */
void
window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
@ -285,6 +459,37 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
window_choose_fire_callback(wp, item->wcd);
window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_TREE_TOGGLE:
item = &ARRAY_ITEM(&data->list, data->selected);
if (item->state & TREE_EXPANDED)
window_choose_collapse(wp, item->wcd->tree_session);
else {
window_choose_expand(wp, item->wcd->tree_session,
data->selected);
}
window_choose_redraw_screen(wp);
break;
case MODEKEYCHOICE_TREE_COLLAPSE:
item = &ARRAY_ITEM(&data->list, data->selected);
if (item->state & TREE_EXPANDED) {
window_choose_collapse(wp, item->wcd->tree_session);
window_choose_redraw_screen(wp);
}
break;
case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
window_choose_collapse_all(wp);
break;
case MODEKEYCHOICE_TREE_EXPAND:
item = &ARRAY_ITEM(&data->list, data->selected);
if (!(item->state & TREE_EXPANDED)) {
window_choose_expand(wp, item->wcd->tree_session,
data->selected);
window_choose_redraw_screen(wp);
}
break;
case MODEKEYCHOICE_TREE_EXPAND_ALL:
window_choose_expand_all(wp);
break;
case MODEKEYCHOICE_UP:
if (items == 0)
break;
@ -469,7 +674,13 @@ window_choose_write_line(
else
xsnprintf (label, sizeof label, "(%d)", item->pos);
screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
"%*s %s", data->width + 2, label, item->name);
"%*s %s %s", data->width + 2, label,
/*
* Add indication to tree if necessary about whether it's
* expanded or not.
*/
(item->wcd->type & TREE_SESSION) ?
(item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
}
while (s->cx < screen_size_x(s))
screen_write_putc(ctx, &gc, ' ');
@ -623,6 +834,8 @@ window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx,
wcd = window_choose_data_create(ctx);
wcd->idx = s->idx;
wcd->tree_session = s;
wcd->type = TREE_SESSION;
wcd->command = cmd_template_replace(action, s->name, 1);
wcd->ft_template = xstrdup(template);
format_add(wcd->ft, "line", "%u", idx);
@ -684,6 +897,8 @@ window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx,
wcd->idx = wl->idx;
wcd->wl = wl;
wcd->tree_session = s;
wcd->type = TREE_WINDOW;
wcd->ft_template = xstrdup(template);
format_add(wcd->ft, "line", "%u", idx);
format_session(wcd->ft, s);