diff options
author | Nicholas Marriott <nicm@openbsd.org> | 2012-10-02 08:16:28 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@openbsd.org> | 2012-10-02 08:16:28 +0000 |
commit | 9107b0c69a12ebc6161e1a11c26a8c2265c61fcc (patch) | |
tree | f88c3a93c7be09e81d00d1ff70dbed5a34d4cf09 /window-choose.c | |
parent | ea289bc4579c30e5d752264c2779376c0f3f9657 (diff) |
Allow session tree (C-b s) to expand and collapse sessions with
left/right/space keys. From Thomas Adam.
Diffstat (limited to 'window-choose.c')
-rw-r--r-- | window-choose.c | 219 |
1 files changed, 217 insertions, 2 deletions
diff --git a/window-choose.c b/window-choose.c index 7bab2ffe..55f95de7 100644 --- a/window-choose.c +++ b/window-choose.c @@ -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) @@ -237,7 +411,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 +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); |