Annotation of src/usr.bin/tmux/window-tree.c, Revision 1.15
1.15 ! nicm 1: /* $OpenBSD: window-tree.c,v 1.14 2017/07/28 10:59:58 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
26: static struct screen *window_tree_init(struct window_pane *,
27: struct cmd_find_state *, struct args *);
28: static void window_tree_free(struct window_pane *);
29: static void window_tree_resize(struct window_pane *, u_int, u_int);
30: static void window_tree_key(struct window_pane *,
31: struct client *, struct session *, key_code,
32: struct mouse_event *);
33:
34: #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'"
35:
1.15 ! nicm 36: #define WINDOW_TREE_DEFAULT_FORMAT \
! 37: "#{?pane_format," \
! 38: "#{pane_current_command} \"#{pane_title}\"" \
! 39: "," \
! 40: "#{?window_format," \
! 41: "#{window_name}#{window_flags} " \
! 42: "(#{window_panes} panes)" \
! 43: "#{?#{==:#{window_panes},1}, \"#{pane_title}\",}" \
! 44: "," \
! 45: "#{session_windows} windows" \
! 46: "#{?session_grouped, (group ,}" \
! 47: "#{session_group}#{?session_grouped,),}" \
! 48: "#{?session_attached, (attached),}" \
! 49: "}" \
! 50: "}"
! 51:
1.1 nicm 52: const struct window_mode window_tree_mode = {
53: .name = "tree-mode",
54:
55: .init = window_tree_init,
56: .free = window_tree_free,
57: .resize = window_tree_resize,
58: .key = window_tree_key,
59: };
60:
61: enum window_tree_sort_type {
62: WINDOW_TREE_BY_INDEX,
63: WINDOW_TREE_BY_NAME,
64: WINDOW_TREE_BY_TIME,
65: };
66: static const char *window_tree_sort_list[] = {
67: "index",
68: "name",
69: "time"
70: };
71:
72: enum window_tree_type {
73: WINDOW_TREE_NONE,
74: WINDOW_TREE_SESSION,
75: WINDOW_TREE_WINDOW,
76: WINDOW_TREE_PANE,
77: };
78:
79: struct window_tree_itemdata {
80: enum window_tree_type type;
81: int session;
82: int winlink;
83: int pane;
84: };
85:
86: struct window_tree_modedata {
87: struct window_pane *wp;
88: int dead;
89: int references;
90:
91: struct mode_tree_data *data;
1.15 ! nicm 92: char *format;
1.1 nicm 93: char *command;
94:
95: struct window_tree_itemdata **item_list;
96: u_int item_size;
97:
98: struct client *client;
99: const char *entered;
100:
101: struct cmd_find_state fs;
102: enum window_tree_type type;
1.11 nicm 103:
104: int offset;
1.1 nicm 105: };
106:
107: static void
108: window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
109: struct winlink **wlp, struct window_pane **wp)
110: {
111: *wp = NULL;
112: *wlp = NULL;
113: *sp = session_find_by_id(item->session);
114: if (*sp == NULL)
115: return;
116: if (item->type == WINDOW_TREE_SESSION) {
117: *wlp = (*sp)->curw;
118: *wp = (*wlp)->window->active;
119: return;
120: }
121:
122: *wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
123: if (*wlp == NULL) {
124: *sp = NULL;
125: return;
126: }
127: if (item->type == WINDOW_TREE_WINDOW) {
128: *wp = (*wlp)->window->active;
129: return;
130: }
131:
132: *wp = window_pane_find_by_id(item->pane);
133: if (!window_has_pane((*wlp)->window, *wp))
134: *wp = NULL;
135: if (*wp == NULL) {
136: *sp = NULL;
137: *wlp = NULL;
138: return;
139: }
140: }
141:
142: static struct window_tree_itemdata *
143: window_tree_add_item(struct window_tree_modedata *data)
144: {
145: struct window_tree_itemdata *item;
146:
147: data->item_list = xreallocarray(data->item_list, data->item_size + 1,
148: sizeof *data->item_list);
149: item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
150: return (item);
151: }
152:
153: static void
154: window_tree_free_item(struct window_tree_itemdata *item)
155: {
156: free(item);
157: }
158:
159: static int
160: window_tree_cmp_session_name(const void *a0, const void *b0)
161: {
162: const struct session *const *a = a0;
163: const struct session *const *b = b0;
164:
165: return (strcmp((*a)->name, (*b)->name));
166: }
167:
168: static int
169: window_tree_cmp_session_time(const void *a0, const void *b0)
170: {
171: const struct session *const *a = a0;
172: const struct session *const *b = b0;
173:
174: if (timercmp(&(*a)->activity_time, &(*b)->activity_time, >))
175: return (-1);
176: if (timercmp(&(*a)->activity_time, &(*b)->activity_time, <))
177: return (1);
178: return (strcmp((*a)->name, (*b)->name));
179: }
180:
181: static int
182: window_tree_cmp_window_name(const void *a0, const void *b0)
183: {
184: const struct winlink *const *a = a0;
185: const struct winlink *const *b = b0;
186:
187: return (strcmp((*a)->window->name, (*b)->window->name));
188: }
189:
190: static int
191: window_tree_cmp_window_time(const void *a0, const void *b0)
192: {
193: const struct winlink *const *a = a0;
194: const struct winlink *const *b = b0;
195:
196: if (timercmp(&(*a)->window->activity_time,
197: &(*b)->window->activity_time, >))
198: return (-1);
199: if (timercmp(&(*a)->window->activity_time,
200: &(*b)->window->activity_time, <))
201: return (1);
202: return (strcmp((*a)->window->name, (*b)->window->name));
203: }
204:
205: static int
206: window_tree_cmp_pane_time(const void *a0, const void *b0)
207: {
208: const struct window_pane *const *a = a0;
209: const struct window_pane *const *b = b0;
210:
211: if ((*a)->active_point < (*b)->active_point)
212: return (-1);
213: if ((*a)->active_point > (*b)->active_point)
214: return (1);
215: return (0);
216: }
217:
218: static void
219: window_tree_build_pane(struct session *s, struct winlink *wl,
220: struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
221: {
222: struct window_tree_modedata *data = modedata;
223: struct window_tree_itemdata *item;
224: char *name, *text;
225: u_int idx;
226:
227: window_pane_index(wp, &idx);
228:
229: item = window_tree_add_item(data);
230: item->type = WINDOW_TREE_PANE;
231: item->session = s->id;
232: item->winlink = wl->idx;
233: item->pane = wp->id;
234:
1.15 ! nicm 235: text = format_single(NULL, data->format, NULL, s, wl, wp);
1.1 nicm 236: xasprintf(&name, "%u", idx);
237:
238: mode_tree_add(data->data, parent, item, (uint64_t)wp, name, text, -1);
239: free(text);
240: free(name);
241: }
242:
243: static int
244: window_tree_build_window(struct session *s, struct winlink *wl, void* modedata,
1.5 nicm 245: u_int sort_type, struct mode_tree_item *parent, const char *filter)
1.1 nicm 246: {
247: struct window_tree_modedata *data = modedata;
248: struct window_tree_itemdata *item;
249: struct mode_tree_item *mti;
250: char *name, *text, *cp;
251: struct window_pane *wp, **l;
252: u_int n, i;
253: int expanded;
254:
255: item = window_tree_add_item(data);
256: item->type = WINDOW_TREE_WINDOW;
257: item->session = s->id;
258: item->winlink = wl->idx;
259: item->pane = -1;
260:
1.15 ! nicm 261: text = format_single(NULL, data->format, NULL, s, wl, NULL);
1.1 nicm 262: xasprintf(&name, "%u", wl->idx);
263:
264: if (data->type == WINDOW_TREE_SESSION ||
265: data->type == WINDOW_TREE_WINDOW)
266: expanded = 0;
267: else
268: expanded = 1;
269: mti = mode_tree_add(data->data, parent, item, (uint64_t)wl, name, text,
270: expanded);
271: free(text);
272: free(name);
273:
1.13 nicm 274: if (window_count_panes(wl->window) == 1)
275: return (1);
276:
1.1 nicm 277: l = NULL;
278: n = 0;
1.13 nicm 279:
1.1 nicm 280: TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1.5 nicm 281: if (filter != NULL) {
282: cp = format_single(NULL, filter, NULL, s, wl, wp);
1.1 nicm 283: if (!format_true(cp)) {
284: free(cp);
285: continue;
286: }
287: free(cp);
288: }
289: l = xreallocarray(l, n + 1, sizeof *l);
290: l[n++] = wp;
291: }
292: if (n == 0) {
293: window_tree_free_item(item);
294: data->item_size--;
295: mode_tree_remove(data->data, mti);
296: return (0);
297: }
298:
299: switch (sort_type) {
300: case WINDOW_TREE_BY_INDEX:
301: break;
302: case WINDOW_TREE_BY_NAME:
303: /* Panes don't have names, so leave in number order. */
304: break;
305: case WINDOW_TREE_BY_TIME:
306: qsort(l, n, sizeof *l, window_tree_cmp_pane_time);
307: break;
308: }
309:
310: for (i = 0; i < n; i++)
311: window_tree_build_pane(s, wl, l[i], modedata, mti);
312: free(l);
313: return (1);
314: }
315:
316: static void
317: window_tree_build_session(struct session *s, void* modedata,
1.5 nicm 318: u_int sort_type, const char *filter)
1.1 nicm 319: {
320: struct window_tree_modedata *data = modedata;
321: struct window_tree_itemdata *item;
322: struct mode_tree_item *mti;
323: char *text;
324: struct winlink *wl, **l;
325: u_int n, i, empty;
326: int expanded;
327:
328: item = window_tree_add_item(data);
329: item->type = WINDOW_TREE_SESSION;
330: item->session = s->id;
331: item->winlink = -1;
332: item->pane = -1;
333:
1.15 ! nicm 334: text = format_single(NULL, data->format, NULL, s, NULL, NULL);
1.1 nicm 335:
336: if (data->type == WINDOW_TREE_SESSION)
337: expanded = 0;
338: else
339: expanded = 1;
340: mti = mode_tree_add(data->data, NULL, item, (uint64_t)s, s->name, text,
341: expanded);
342: free(text);
343:
344: l = NULL;
345: n = 0;
346: RB_FOREACH(wl, winlinks, &s->windows) {
347: l = xreallocarray(l, n + 1, sizeof *l);
348: l[n++] = wl;
349: }
350: switch (sort_type) {
351: case WINDOW_TREE_BY_INDEX:
352: break;
353: case WINDOW_TREE_BY_NAME:
354: qsort(l, n, sizeof *l, window_tree_cmp_window_name);
355: break;
356: case WINDOW_TREE_BY_TIME:
357: qsort(l, n, sizeof *l, window_tree_cmp_window_time);
358: break;
359: }
360:
361: empty = 0;
362: for (i = 0; i < n; i++) {
363: if (!window_tree_build_window(s, l[i], modedata, sort_type, mti,
1.5 nicm 364: filter))
1.1 nicm 365: empty++;
366: }
367: if (empty == n) {
368: window_tree_free_item(item);
369: data->item_size--;
370: mode_tree_remove(data->data, mti);
371: }
372: free(l);
373: }
374:
375: static void
1.5 nicm 376: window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
377: const char *filter)
1.1 nicm 378: {
379: struct window_tree_modedata *data = modedata;
380: struct session *s, **l;
381: u_int n, i;
382:
383: for (i = 0; i < data->item_size; i++)
384: window_tree_free_item(data->item_list[i]);
385: free(data->item_list);
386: data->item_list = NULL;
387: data->item_size = 0;
388:
389: l = NULL;
390: n = 0;
391: RB_FOREACH(s, sessions, &sessions) {
392: l = xreallocarray(l, n + 1, sizeof *l);
393: l[n++] = s;
394: }
395: switch (sort_type) {
396: case WINDOW_TREE_BY_INDEX:
397: break;
398: case WINDOW_TREE_BY_NAME:
399: qsort(l, n, sizeof *l, window_tree_cmp_session_name);
400: break;
401: case WINDOW_TREE_BY_TIME:
402: qsort(l, n, sizeof *l, window_tree_cmp_session_time);
403: break;
404: }
405:
406: for (i = 0; i < n; i++)
1.5 nicm 407: window_tree_build_session(l[i], modedata, sort_type, filter);
1.1 nicm 408: free(l);
409:
410: switch (data->type) {
411: case WINDOW_TREE_NONE:
412: break;
413: case WINDOW_TREE_SESSION:
414: *tag = (uint64_t)data->fs.s;
415: break;
416: case WINDOW_TREE_WINDOW:
417: *tag = (uint64_t)data->fs.wl;
418: break;
419: case WINDOW_TREE_PANE:
420: *tag = (uint64_t)data->fs.wp;
421: break;
422: }
423: }
424:
1.6 nicm 425: static void
1.11 nicm 426: window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
427: struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 428: {
429: struct options *oo = s->options;
430: struct winlink *wl;
431: struct window *w;
1.9 nicm 432: u_int loop, total, visible, each, width, offset;
433: u_int current, start, end, remaining, i;
1.6 nicm 434: struct grid_cell gc;
1.9 nicm 435: int colour, active_colour, left, right;
1.6 nicm 436: char *label;
437: size_t len;
438:
1.9 nicm 439: total = winlink_count(&s->windows);
1.6 nicm 440:
441: memcpy(&gc, &grid_default_cell, sizeof gc);
442: colour = options_get_number(oo, "display-panes-colour");
443: active_colour = options_get_number(oo, "display-panes-active-colour");
444:
1.9 nicm 445: if (sx / total < 24) {
446: visible = sx / 24;
447: if (visible == 0)
448: visible = 1;
449: } else
450: visible = total;
451:
452: current = 0;
453: RB_FOREACH(wl, winlinks, &s->windows) {
454: if (wl == s->curw)
455: break;
456: current++;
457: }
1.6 nicm 458:
1.9 nicm 459: if (current < visible) {
460: start = 0;
461: end = visible;
462: } else if (current >= total - visible) {
463: start = total - visible;
464: end = total;
465: } else {
466: start = current - (visible / 2);
467: end = start + visible;
468: }
469:
1.11 nicm 470: if (data->offset < -(int)start)
471: data->offset = -(int)start;
472: if (data->offset > (int)(total - end))
473: data->offset = (int)(total - end);
474: start += data->offset;
475: end += data->offset;
476:
1.9 nicm 477: left = (start != 0);
478: right = (end != total);
479: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
480: left = right = 0;
481: if (left && right) {
482: each = (sx - 6) / visible;
483: remaining = (sx - 6) - (visible * each);
484: } else if (left || right) {
485: each = (sx - 3) / visible;
486: remaining = (sx - 3) - (visible * each);
487: } else {
488: each = sx / visible;
489: remaining = sx - (visible * each);
490: }
491: if (each == 0)
492: return;
493:
494: if (left) {
495: screen_write_cursormove(ctx, 2, 0);
496: screen_write_vline(ctx, sy, 0, 0);
497: screen_write_cursormove(ctx, 0, sy / 2);
498: screen_write_puts(ctx, &grid_default_cell, "<");
499: }
500: if (right) {
501: screen_write_cursormove(ctx, sx - 3, 0);
1.6 nicm 502: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 503: screen_write_cursormove(ctx, sx - 1, sy / 2);
504: screen_write_puts(ctx, &grid_default_cell, ">");
505: }
1.6 nicm 506:
1.9 nicm 507: i = loop = 0;
508: RB_FOREACH(wl, winlinks, &s->windows) {
509: if (loop == end)
510: break;
511: if (loop < start) {
512: loop++;
513: continue;
514: }
515: w = wl->window;
1.6 nicm 516:
517: if (wl == s->curw)
518: gc.fg = active_colour;
519: else
520: gc.fg = colour;
1.9 nicm 521:
522: if (left)
523: offset = 3 + (i * each);
524: else
525: offset = (i * each);
526: if (loop == end - 1)
1.12 nicm 527: width = each + remaining;
1.6 nicm 528: else
529: width = each - 1;
530:
1.9 nicm 531: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 532: screen_write_preview(ctx, &w->active->base, width, sy);
533:
534: xasprintf(&label, " %u:%s ", wl->idx, w->name);
535: if (strlen(label) > width)
536: xasprintf(&label, " %u ", wl->idx);
537: len = strlen(label) / 2;
1.9 nicm 538: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 539: if (len < width)
1.7 nicm 540: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 541: free(label);
542:
1.9 nicm 543: if (loop != end - 1) {
544: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 545: screen_write_vline(ctx, sy, 0, 0);
546: }
1.9 nicm 547: loop++;
548:
549: i++;
1.6 nicm 550: }
551: }
552:
553: static void
1.11 nicm 554: window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
555: struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6 nicm 556: {
557: struct options *oo = s->options;
558: struct window_pane *wp;
1.9 nicm 559: u_int loop, total, visible, each, width, offset;
560: u_int current, start, end, remaining, i;
1.6 nicm 561: struct grid_cell gc;
1.9 nicm 562: int colour, active_colour, left, right;
1.6 nicm 563: char *label;
564: size_t len;
565:
1.9 nicm 566: total = window_count_panes(w);
1.6 nicm 567:
568: memcpy(&gc, &grid_default_cell, sizeof gc);
569: colour = options_get_number(oo, "display-panes-colour");
570: active_colour = options_get_number(oo, "display-panes-active-colour");
571:
1.9 nicm 572: if (sx / total < 24) {
573: visible = sx / 24;
574: if (visible == 0)
575: visible = 1;
576: } else
577: visible = total;
578:
579: current = 0;
580: TAILQ_FOREACH(wp, &w->panes, entry) {
581: if (wp == w->active)
582: break;
583: current++;
584: }
585:
586: if (current < visible) {
587: start = 0;
588: end = visible;
589: } else if (current >= total - visible) {
590: start = total - visible;
591: end = total;
592: } else {
593: start = current - (visible / 2);
594: end = start + visible;
595: }
596:
1.11 nicm 597: if (data->offset < -(int)start)
598: data->offset = -(int)start;
599: if (data->offset > (int)(total - end))
600: data->offset = (int)(total - end);
601: start += data->offset;
602: end += data->offset;
603:
1.9 nicm 604: left = (start != 0);
605: right = (end != total);
606: if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
607: left = right = 0;
608: if (left && right) {
609: each = (sx - 6) / visible;
610: remaining = (sx - 6) - (visible * each);
611: } else if (left || right) {
612: each = (sx - 3) / visible;
613: remaining = (sx - 3) - (visible * each);
614: } else {
615: each = sx / visible;
616: remaining = sx - (visible * each);
617: }
618: if (each == 0)
619: return;
1.6 nicm 620:
1.9 nicm 621: if (left) {
622: screen_write_cursormove(ctx, 2, 0);
1.6 nicm 623: screen_write_vline(ctx, sy, 0, 0);
1.9 nicm 624: screen_write_cursormove(ctx, 0, sy / 2);
625: screen_write_puts(ctx, &grid_default_cell, "<");
626: }
627: if (right) {
628: screen_write_cursormove(ctx, sx - 3, 0);
629: screen_write_vline(ctx, sy, 0, 0);
630: screen_write_cursormove(ctx, sx - 1, sy / 2);
631: screen_write_puts(ctx, &grid_default_cell, ">");
632: }
1.6 nicm 633:
1.9 nicm 634: i = loop = 0;
635: TAILQ_FOREACH(wp, &w->panes, entry) {
636: if (loop == end)
637: break;
638: if (loop < start) {
639: loop++;
640: continue;
641: }
1.6 nicm 642:
643: if (wp == w->active)
644: gc.fg = active_colour;
645: else
646: gc.fg = colour;
1.9 nicm 647:
648: if (left)
649: offset = 3 + (i * each);
650: else
651: offset = (i * each);
652: if (loop == end - 1)
1.12 nicm 653: width = each + remaining;
1.6 nicm 654: else
655: width = each - 1;
656:
1.9 nicm 657: screen_write_cursormove(ctx, offset, 0);
1.6 nicm 658: screen_write_preview(ctx, &wp->base, width, sy);
659:
1.9 nicm 660: xasprintf(&label, " %u ", loop);
1.6 nicm 661: len = strlen(label) / 2;
1.9 nicm 662: screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8 nicm 663: if (len < width)
1.7 nicm 664: screen_write_puts(ctx, &gc, "%s", label);
1.6 nicm 665: free(label);
666:
1.9 nicm 667: if (loop != end - 1) {
668: screen_write_cursormove(ctx, offset + width, 0);
1.6 nicm 669: screen_write_vline(ctx, sy, 0, 0);
670: }
1.9 nicm 671: loop++;
672:
673: i++;
1.6 nicm 674: }
675: }
676:
1.1 nicm 677: static struct screen *
1.11 nicm 678: window_tree_draw(void *modedata, void *itemdata, u_int sx, u_int sy)
1.1 nicm 679: {
680: struct window_tree_itemdata *item = itemdata;
681: struct session *sp;
682: struct winlink *wlp;
683: struct window_pane *wp;
684: static struct screen s;
685: struct screen_write_ctx ctx;
686:
687: window_tree_pull_item(item, &sp, &wlp, &wp);
688: if (wp == NULL)
689: return (NULL);
690:
691: screen_init(&s, sx, sy, 0);
692: screen_write_start(&ctx, NULL, &s);
693:
1.6 nicm 694: switch (item->type) {
695: case WINDOW_TREE_NONE:
696: return (0);
697: case WINDOW_TREE_SESSION:
1.11 nicm 698: window_tree_draw_session(modedata, sp, &ctx, sx, sy);
1.6 nicm 699: break;
700: case WINDOW_TREE_WINDOW:
1.11 nicm 701: window_tree_draw_window(modedata, sp, wlp->window, &ctx, sx, sy);
1.6 nicm 702: break;
703: case WINDOW_TREE_PANE:
704: screen_write_preview(&ctx, &wp->base, sx, sy);
705: break;
706: }
1.1 nicm 707:
708: screen_write_stop(&ctx);
709: return (&s);
710: }
711:
1.3 nicm 712: static int
713: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
714: {
715: struct window_tree_itemdata *item = itemdata;
716: struct session *s;
717: struct winlink *wl;
718: struct window_pane *wp;
719: const char *cmd;
720:
721: window_tree_pull_item(item, &s, &wl, &wp);
722:
723: switch (item->type) {
724: case WINDOW_TREE_NONE:
725: return (0);
726: case WINDOW_TREE_SESSION:
727: if (s == NULL)
728: return (0);
729: return (strstr(s->name, ss) != NULL);
730: case WINDOW_TREE_WINDOW:
731: if (s == NULL || wl == NULL)
732: return (0);
733: return (strstr(wl->window->name, ss) != NULL);
734: case WINDOW_TREE_PANE:
735: if (s == NULL || wl == NULL || wp == NULL)
736: break;
737: cmd = get_proc_name(wp->fd, wp->tty);
738: if (cmd == NULL || *cmd == '\0')
739: return (0);
740: return (strstr(cmd, ss) != NULL);
741: }
742: return (0);
743: }
744:
1.1 nicm 745: static struct screen *
746: window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
747: struct args *args)
748: {
749: struct window_tree_modedata *data;
750: struct screen *s;
751:
752: wp->modedata = data = xcalloc(1, sizeof *data);
753:
754: if (args_has(args, 's'))
755: data->type = WINDOW_TREE_SESSION;
756: else if (args_has(args, 'w'))
757: data->type = WINDOW_TREE_WINDOW;
758: else
759: data->type = WINDOW_TREE_PANE;
760: memcpy(&data->fs, fs, sizeof data->fs);
761:
762: data->wp = wp;
763: data->references = 1;
764:
1.15 ! nicm 765: if (args == NULL || !args_has(args, 'F'))
! 766: data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
! 767: else
! 768: data->format = xstrdup(args_get(args, 'F'));
1.1 nicm 769: if (args == NULL || args->argc == 0)
770: data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
771: else
772: data->command = xstrdup(args->argv[0]);
773:
1.4 nicm 774: data->data = mode_tree_start(wp, args, window_tree_build,
775: window_tree_draw, window_tree_search, data, window_tree_sort_list,
1.1 nicm 776: nitems(window_tree_sort_list), &s);
777:
778: mode_tree_build(data->data);
779: mode_tree_draw(data->data);
780:
781: data->type = WINDOW_TREE_NONE;
782:
783: return (s);
784: }
785:
786: static void
787: window_tree_destroy(struct window_tree_modedata *data)
788: {
789: u_int i;
790:
791: if (--data->references != 0)
792: return;
793:
794: mode_tree_free(data->data);
795:
796: for (i = 0; i < data->item_size; i++)
797: window_tree_free_item(data->item_list[i]);
798: free(data->item_list);
799:
1.15 ! nicm 800: free(data->format);
1.1 nicm 801: free(data->command);
1.15 ! nicm 802:
1.1 nicm 803: free(data);
804: }
805:
806: static void
807: window_tree_free(struct window_pane *wp)
808: {
809: struct window_tree_modedata *data = wp->modedata;
810:
811: if (data == NULL)
812: return;
813:
814: data->dead = 1;
815: window_tree_destroy(data);
816: }
817:
818: static void
819: window_tree_resize(struct window_pane *wp, u_int sx, u_int sy)
820: {
821: struct window_tree_modedata *data = wp->modedata;
822:
823: mode_tree_resize(data->data, sx, sy);
824: }
825:
826: static char *
827: window_tree_get_target(struct window_tree_itemdata *item,
828: struct cmd_find_state *fs)
829: {
830: struct session *s;
831: struct winlink *wl;
832: struct window_pane *wp;
833: char *target;
834:
835: window_tree_pull_item(item, &s, &wl, &wp);
836:
837: target = NULL;
838: switch (item->type) {
839: case WINDOW_TREE_NONE:
840: break;
841: case WINDOW_TREE_SESSION:
842: if (s == NULL)
843: break;
844: xasprintf(&target, "=%s:", s->name);
845: break;
846: case WINDOW_TREE_WINDOW:
847: if (s == NULL || wl == NULL)
848: break;
849: xasprintf(&target, "=%s:%u.", s->name, wl->idx);
850: break;
851: case WINDOW_TREE_PANE:
852: if (s == NULL || wl == NULL || wp == NULL)
853: break;
854: xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
855: break;
856: }
857: if (target == NULL)
858: cmd_find_clear_state(fs, 0);
859: else
860: cmd_find_from_winlink_pane(fs, wl, wp);
861: return (target);
862: }
863:
864: static void
865: window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
866: {
867: struct window_tree_modedata *data = modedata;
868: struct window_tree_itemdata *item = itemdata;
869: char *name;
870: struct cmd_find_state fs;
871:
872: name = window_tree_get_target(item, &fs);
873: if (name != NULL)
874: mode_tree_run_command(data->client, &fs, data->entered, name);
875: free(name);
876: }
877:
878: static enum cmd_retval
879: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
880: {
881: struct window_tree_modedata *data = modedata;
882:
883: if (!data->dead) {
884: mode_tree_build(data->data);
885: mode_tree_draw(data->data);
886: data->wp->flags |= PANE_REDRAW;
887: }
888: window_tree_destroy(data);
889: return (CMD_RETURN_NORMAL);
890: }
891:
892: static int
893: window_tree_command_callback(struct client *c, void *modedata, const char *s,
894: __unused int done)
895: {
896: struct window_tree_modedata *data = modedata;
897:
898: if (data->dead)
899: return (0);
900:
901: data->client = c;
902: data->entered = s;
903:
904: mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
905: 1);
906:
907: data->client = NULL;
908: data->entered = NULL;
909:
910: data->references++;
911: cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
912:
913: return (0);
914: }
915:
916: static void
917: window_tree_command_free(void *modedata)
918: {
919: struct window_tree_modedata *data = modedata;
920:
921: window_tree_destroy(data);
922: }
923:
924: static void
925: window_tree_key(struct window_pane *wp, struct client *c,
926: __unused struct session *s, key_code key, struct mouse_event *m)
927: {
928: struct window_tree_modedata *data = wp->modedata;
929: struct window_tree_itemdata *item;
930: char *command, *name, *prompt;
931: struct cmd_find_state fs;
932: int finished;
933: u_int tagged;
934:
1.11 nicm 935: item = mode_tree_get_current(data->data);
1.3 nicm 936: finished = mode_tree_key(data->data, c, &key, m);
1.11 nicm 937: if (item != mode_tree_get_current(data->data))
938: data->offset = 0;
1.1 nicm 939: switch (key) {
1.11 nicm 940: case '<':
941: data->offset--;
942: break;
943: case '>':
944: data->offset++;
945: break;
1.1 nicm 946: case ':':
947: tagged = mode_tree_count_tagged(data->data);
948: if (tagged != 0)
949: xasprintf(&prompt, "(%u tagged) ", tagged);
950: else
951: xasprintf(&prompt, "(current) ");
952: data->references++;
953: status_prompt_set(c, prompt, "", window_tree_command_callback,
954: window_tree_command_free, data, PROMPT_NOFORMAT);
955: free(prompt);
956: break;
957: case '\r':
958: item = mode_tree_get_current(data->data);
959: command = xstrdup(data->command);
960: name = window_tree_get_target(item, &fs);
961: window_pane_reset_mode(wp);
962: if (name != NULL)
1.2 nicm 963: mode_tree_run_command(c, NULL, command, name);
1.1 nicm 964: free(name);
965: free(command);
966: return;
967: }
968: if (finished)
969: window_pane_reset_mode(wp);
970: else {
971: mode_tree_draw(data->data);
972: wp->flags |= PANE_REDRAW;
973: }
974: }