This implements a rough outline of how collapsing and expanding sessions in choose-tree output might work.
Currently, the tree renders expanded, and the use of Left and Right keys to collapse and expand items respectively, need to be used. I can't say I am happy with the implementation given that I'm manipulating a flat list of items as though they were a tree, but re-working things to assume choose-mode works with trees seems odd to me. I need to look at the memory side of things as well, as I'm probably leaking &data->list_orig -- but I'll take a more complete look if it's decided this is the best way of doing things. See what you think... I think it sucks. I know I need to add bindings to expand/collapse all sessions as well as only show sessions by default (i.e., in a collapsed state). Unsure which behaviour from that is needed by default. --- mode-key.c | 6 +++ tmux.h | 11 ++++- window-choose.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 145 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index cacdb91..b5336d7 100644 --- a/mode-key.c +++ b/mode-key.c @@ -77,7 +77,9 @@ const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { { MODEKEYCHOICE_BACKSPACE, "backspace" }, { MODEKEYCHOICE_CANCEL, "cancel" }, { MODEKEYCHOICE_CHOOSE, "choose" }, + { MODEKEYCHOICE_COLLAPSE, "collapse" }, { MODEKEYCHOICE_DOWN, "down" }, + { MODEKEYCHOICE_EXPAND, "expand" }, { MODEKEYCHOICE_PAGEDOWN, "page-down" }, { MODEKEYCHOICE_PAGEUP, "page-up" }, { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, @@ -218,6 +220,8 @@ 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 }, + { KEYC_LEFT, 0, MODEKEYCHOICE_COLLAPSE }, + { KEYC_RIGHT, 0, MODEKEYCHOICE_EXPAND }, { 0, -1, 0 } }; @@ -355,6 +359,8 @@ 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 }, + { KEYC_LEFT, 0, MODEKEYCHOICE_COLLAPSE }, + { KEYC_RIGHT, 0, MODEKEYCHOICE_EXPAND }, { 0, -1, 0 } }; diff --git a/tmux.h b/tmux.h index 249dd5d..4763c28 100644 --- a/tmux.h +++ b/tmux.h @@ -542,7 +542,9 @@ enum mode_key_cmd { MODEKEYCHOICE_BACKSPACE, MODEKEYCHOICE_CANCEL, MODEKEYCHOICE_CHOOSE, + MODEKEYCHOICE_COLLAPSE, MODEKEYCHOICE_DOWN, + MODEKEYCHOICE_EXPAND, MODEKEYCHOICE_PAGEDOWN, MODEKEYCHOICE_PAGEUP, MODEKEYCHOICE_SCROLLDOWN, @@ -887,12 +889,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 +906,8 @@ struct window_choose_mode_item { struct window_choose_data *wcd; char *name; int pos; + int state; +#define TREE_EXPANDED 0x1 }; /* Child window structure. */ @@ -2205,7 +2213,6 @@ struct window_choose_data *window_choose_add_session(struct window_pane *, struct window_choose_data *window_choose_add_item(struct window_pane *, struct cmd_ctx *, struct winlink *, const char *, char *, u_int); - /* names.c */ void queue_window_name(struct window *); char *default_window_name(struct window *); diff --git a/window-choose.c b/window-choose.c index c77a1d3..e91f35c 100644 --- a/window-choose.c +++ b/window-choose.c @@ -33,6 +33,8 @@ void window_choose_mouse( void window_choose_fire_callback( struct window_pane *, struct window_choose_data *); +void window_choose_collapse(struct window_pane *); +void window_choose_expand(struct window_pane *); void window_choose_redraw_screen(struct window_pane *); void window_choose_write_line( struct window_pane *, struct screen_write_ctx *, u_int); @@ -60,6 +62,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 +92,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 +112,8 @@ 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_redraw_screen(wp); } @@ -127,6 +133,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 +161,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); } @@ -228,6 +237,114 @@ 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 window_choose_mode_data *data = wp->modedata; + struct window_choose_mode_item *item, *chosen; + struct window_choose_data *wcd; + u_int i; + + ARRAY_DECL(, struct window_choose_mode_item) list_copy; + ARRAY_INIT(&list_copy); + + chosen = &ARRAY_ITEM(&data->list, data->selected); + 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 (chosen->wcd->tree_session == 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_expand(struct window_pane *wp) +{ + struct window_choose_mode_data *data = wp->modedata; + struct window_choose_mode_item *item, *chosen; + struct window_choose_data *wcd; + u_int i, pos, items; + + pos = data->selected; + 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); + wcd = item->wcd; + + if (chosen->wcd->tree_session == 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 +354,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 +402,14 @@ 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: + window_choose_collapse(wp); + window_choose_redraw_screen(wp); + break; + case MODEKEYCHOICE_EXPAND: + window_choose_expand(wp); + window_choose_redraw_screen(wp); + break; case MODEKEYCHOICE_UP: if (items == 0) break; @@ -623,6 +748,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 +811,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.10.4 ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users