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

Reply via email to