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
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users