This patch adds the ability to expand/collapse a single session using the spacebar.
Likewise, C-Left and C-Right will collapse and expand all sessions, respectively. --- This is the second version of the original patch, which takes Romain's suggestion. Now, spacebar will expand/collapse a single session. There is no longer explicit expand/collapse bindings -- only COLLAPSE_EXPAND_TOGGLE. Fixed a minor bug with selecting sessions after collapsing them too. I've still left the bindings for expand_all and collapse_all unchanged -- if they need to change, feel free to do so. I suppose I'll have to update the man page? mode-key.c | 9 +++ tmux.h | 11 ++- window-choose.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 223 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index cacdb91..887abf4 100644 --- a/mode-key.c +++ b/mode-key.c @@ -77,7 +77,10 @@ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_BACKSPACE, "backspace" }, { MODEKEYCHOICE_CANCEL, "cancel" }, { MODEKEYCHOICE_CHOOSE, "choose" }, + { MODEKEYCHOICE_COLLAPSE_ALL, "collapse-all" }, + { MODEKEYCHOICE_COLLAPSE_EXPAND_TOGGLE, "collapse-toggle" }, { MODEKEYCHOICE_DOWN, "down" }, + { MODEKEYCHOICE_EXPAND_ALL, "expand-all" }, { MODEKEYCHOICE_PAGEDOWN, "page-down" }, { MODEKEYCHOICE_PAGEUP, "page-up" }, { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, @@ -218,6 +221,9 @@ const struct mode_key_entry mode_key_vi_choice[] = { { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, + { ' ', 0, MODEKEYCHOICE_COLLAPSE_EXPAND_TOGGLE }, + { KEYC_LEFT | KEYC_CTRL,0, MODEKEYCHOICE_COLLAPSE_ALL }, + { KEYC_RIGHT | KEYC_CTRL,0,MODEKEYCHOICE_EXPAND_ALL }, { 0, -1, 0 } }; @@ -355,6 +361,9 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, + { ' ', 0, MODEKEYCHOICE_COLLAPSE_EXPAND_TOGGLE }, + { KEYC_LEFT | KEYC_CTRL,0, MODEKEYCHOICE_COLLAPSE_ALL }, + { KEYC_RIGHT | KEYC_CTRL,0,MODEKEYCHOICE_EXPAND_ALL }, { 0, -1, 0 } }; diff --git a/tmux.h b/tmux.h index c18499b..25d5bf5 100644 --- a/tmux.h +++ b/tmux.h @@ -542,7 +542,10 @@ enum mode_key_cmd { MODEKEYCHOICE_BACKSPACE, MODEKEYCHOICE_CANCEL, MODEKEYCHOICE_CHOOSE, + MODEKEYCHOICE_COLLAPSE_ALL, + MODEKEYCHOICE_COLLAPSE_EXPAND_TOGGLE, MODEKEYCHOICE_DOWN, + MODEKEYCHOICE_EXPAND_ALL, MODEKEYCHOICE_PAGEDOWN, MODEKEYCHOICE_PAGEUP, MODEKEYCHOICE_SCROLLDOWN, @@ -887,12 +890,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; }; @@ -900,6 +907,8 @@ struct window_choose_mode_item { struct window_choose_data *wcd; char *name; int pos; + int state; +#define TREE_EXPANDED 0x1 }; /* Child window structure. */ diff --git a/window-choose.c b/window-choose.c index c77a1d3..acde980 100644 --- a/window-choose.c +++ b/window-choose.c @@ -40,6 +40,12 @@ 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 +66,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) list_orig; int width; u_int top; u_int selected; @@ -89,6 +96,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 +116,9 @@ window_choose_ready(struct window_pane *wp, u_int cur, data->callbackfn = callbackfn; data->freefn = freefn; + ARRAY_CONCAT(&data->list_orig, &data->list); + + window_choose_collapse_all(wp); window_choose_redraw_screen(wp); } @@ -127,6 +138,7 @@ window_choose_init(struct window_pane *wp) data->input_prompt = NULL; ARRAY_INIT(&data->list); + ARRAY_INIT(&data->list_orig); data->top = 0; s = &data->screen; @@ -154,9 +166,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 +189,7 @@ window_choose_free(struct window_pane *wp) free(item->name); } ARRAY_FREE(&data->list); + ARRAY_FREE(&data->list_orig); free(data->input_str); screen_free(&data->screen); @@ -228,6 +243,168 @@ 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->list_orig) - 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->list_orig, 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->list_orig, + i)); + } else + /* + * Ran out of room, add it to the end. + */ + ARRAY_ADD(&data->list, + ARRAY_ITEM(&data->list_orig, + i)); + } + } + } +} + /* ARGSUSED */ void window_choose_key(struct window_pane *wp, unused struct session *sess, int key) @@ -237,7 +414,7 @@ window_choose_key(struct window_pane *wp, unused struct session *sess, int key) struct screen_write_ctx ctx; struct window_choose_mode_item *item; size_t input_len; - u_int items, n; + u_int items, n; int idx; items = ARRAY_LENGTH(&data->list); @@ -285,6 +462,21 @@ 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_COLLAPSE_EXPAND_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_COLLAPSE_ALL: + window_choose_collapse_all(wp); + break; + case MODEKEYCHOICE_EXPAND_ALL: + window_choose_expand_all(wp); + break; case MODEKEYCHOICE_UP: if (items == 0) break; @@ -469,7 +661,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 +821,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 +884,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); -- 1.7.11.4 ------------------------------------------------------------------------------ Got visibility? Most devs has no idea what their production app looks like. Find out how fast your code is with AppDynamics Lite. http://ad.doubleclick.net/clk;262219671;13503038;y? http://info.appdynamics.com/FreeJavaPerformanceDownload.html _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users