Coverage Report

Created: 2026-05-30 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-tree.c
Line
Count
Source
1
/* $OpenBSD$ */
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 <ctype.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "tmux.h"
26
27
static struct screen  *window_tree_init(struct window_mode_entry *,
28
           struct cmd_find_state *, struct args *);
29
static void    window_tree_free(struct window_mode_entry *);
30
static void    window_tree_resize(struct window_mode_entry *, u_int,
31
           u_int);
32
static void    window_tree_update(struct window_mode_entry *);
33
static void    window_tree_key(struct window_mode_entry *,
34
           struct client *, struct session *,
35
           struct winlink *, key_code, struct mouse_event *);
36
37
0
#define WINDOW_TREE_DEFAULT_COMMAND "switch-client -Zt '%%'"
38
39
#define WINDOW_TREE_DEFAULT_FORMAT \
40
0
  "#{?pane_format," \
41
0
    "#{?pane_marked,#[reverse],}" \
42
0
    "#{pane_current_command}#{?pane_active,*,}#{?pane_marked,M,}" \
43
0
    "#{?#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}},: \"#{pane_title}\",}" \
44
0
  ",window_format," \
45
0
    "#{?window_marked_flag,#[reverse],}" \
46
0
    "#{window_name}#{window_flags}" \
47
0
    "#{?#{&&:#{==:#{window_panes},1},#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}}},: \"#{pane_title}\",}" \
48
0
  "," \
49
0
    "#{session_windows} windows" \
50
0
    "#{?session_grouped, " \
51
0
      "(group #{session_group}: " \
52
0
      "#{session_group_list})," \
53
0
    "}" \
54
0
    "#{?session_attached, (attached),}" \
55
0
  "}"
56
57
#define WINDOW_TREE_DEFAULT_KEY_FORMAT \
58
0
  "#{?#{e|<:#{line},10}," \
59
0
    "#{line}" \
60
0
  ",#{e|<:#{line},36}," \
61
0
          "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
62
0
  "}"
63
64
static const struct menu_item window_tree_menu_items[] = {
65
  { "Select", '\r', NULL },
66
  { "Expand", KEYC_RIGHT, NULL },
67
  { "Mark", 'm', NULL },
68
  { "", KEYC_NONE, NULL },
69
  { "Tag", 't', NULL },
70
  { "Tag All", '\024', NULL },
71
  { "Tag None", 'T', NULL },
72
  { "", KEYC_NONE, NULL },
73
  { "Kill", 'x', NULL },
74
  { "Kill Tagged", 'X', NULL },
75
  { "", KEYC_NONE, NULL },
76
  { "Cancel", 'q', NULL },
77
78
  { NULL, KEYC_NONE, NULL }
79
};
80
81
const struct window_mode window_tree_mode = {
82
  .name = "tree-mode",
83
  .default_format = WINDOW_TREE_DEFAULT_FORMAT,
84
85
  .init = window_tree_init,
86
  .free = window_tree_free,
87
  .resize = window_tree_resize,
88
  .update = window_tree_update,
89
  .key = window_tree_key,
90
};
91
92
enum window_tree_type {
93
  WINDOW_TREE_NONE,
94
  WINDOW_TREE_SESSION,
95
  WINDOW_TREE_WINDOW,
96
  WINDOW_TREE_PANE,
97
};
98
99
struct window_tree_itemdata {
100
  enum window_tree_type type;
101
  int     session;
102
  int     winlink;
103
  int     pane;
104
};
105
106
struct window_tree_modedata {
107
  struct window_pane     *wp;
108
  int         dead;
109
  int         references;
110
111
  struct mode_tree_data    *data;
112
  char         *format;
113
  char         *key_format;
114
  char         *command;
115
  int         squash_groups;
116
  int         prompt_flags;
117
118
  struct window_tree_itemdata **item_list;
119
  u_int         item_size;
120
121
  const char       *entered;
122
123
  struct cmd_find_state     fs;
124
  enum window_tree_type     type;
125
126
  int         offset;
127
128
  int         left;
129
  int         right;
130
  u_int         start;
131
  u_int         end;
132
  u_int         each;
133
};
134
135
static enum sort_order window_tree_order_seq[] = {
136
  SORT_INDEX,
137
  SORT_NAME,
138
  SORT_ACTIVITY,
139
  SORT_END,
140
};
141
142
static void
143
window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
144
    struct winlink **wlp, struct window_pane **wp)
145
0
{
146
0
  *wp = NULL;
147
0
  *wlp = NULL;
148
0
  *sp = session_find_by_id(item->session);
149
0
  if (*sp == NULL)
150
0
    return;
151
0
  if (item->type == WINDOW_TREE_SESSION) {
152
0
    *wlp = (*sp)->curw;
153
0
    *wp = (*wlp)->window->active;
154
0
    return;
155
0
  }
156
157
0
  *wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
158
0
  if (*wlp == NULL) {
159
0
    *sp = NULL;
160
0
    return;
161
0
  }
162
0
  if (item->type == WINDOW_TREE_WINDOW) {
163
0
    *wp = (*wlp)->window->active;
164
0
    return;
165
0
  }
166
167
0
  *wp = window_pane_find_by_id(item->pane);
168
0
  if (!window_has_pane((*wlp)->window, *wp))
169
0
    *wp = NULL;
170
0
  if (*wp == NULL) {
171
0
    *sp = NULL;
172
0
    *wlp = NULL;
173
0
    return;
174
0
  }
175
0
}
176
177
static struct window_tree_itemdata *
178
window_tree_add_item(struct window_tree_modedata *data)
179
0
{
180
0
  struct window_tree_itemdata *item;
181
182
0
  data->item_list = xreallocarray(data->item_list, data->item_size + 1,
183
0
      sizeof *data->item_list);
184
0
  item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
185
0
  return (item);
186
0
}
187
188
static void
189
window_tree_free_item(struct window_tree_itemdata *item)
190
0
{
191
0
  free(item);
192
0
}
193
194
static void
195
window_tree_build_pane(struct session *s, struct winlink *wl,
196
    struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
197
0
{
198
0
  struct window_tree_modedata *data = modedata;
199
0
  struct window_tree_itemdata *item;
200
0
  struct mode_tree_item   *mti;
201
0
  char        *name, *text;
202
0
  u_int        idx;
203
0
  struct format_tree    *ft;
204
205
0
  window_pane_index(wp, &idx);
206
207
0
  item = window_tree_add_item(data);
208
0
  item->type = WINDOW_TREE_PANE;
209
0
  item->session = s->id;
210
0
  item->winlink = wl->idx;
211
0
  item->pane = wp->id;
212
213
0
  ft = format_create(NULL, NULL, FORMAT_PANE|wp->id, 0);
214
0
  format_defaults(ft, NULL, s, wl, wp);
215
0
  text = format_expand(ft, data->format);
216
0
  xasprintf(&name, "%u", idx);
217
0
  format_free(ft);
218
219
0
  mti = mode_tree_add(data->data, parent, item, (uint64_t)wp, name, text,
220
0
      -1);
221
0
  free(text);
222
0
  free(name);
223
0
  mode_tree_align(mti, 1);
224
0
}
225
226
static int
227
window_tree_filter_pane(struct session *s, struct winlink *wl,
228
    struct window_pane *wp, const char *filter)
229
0
{
230
0
  char  *cp;
231
0
  int  result;
232
233
0
  if (filter == NULL)
234
0
    return (1);
235
236
0
  cp = format_single(NULL, filter, NULL, s, wl, wp);
237
0
  result = format_true(cp);
238
0
  free(cp);
239
240
0
  return (result);
241
0
}
242
243
static int
244
window_tree_build_window(struct session *s, struct winlink *wl,
245
    void *modedata, struct sort_criteria *sort_crit,
246
    struct mode_tree_item *parent, const char *filter)
247
0
{
248
0
  struct window_tree_modedata *data = modedata;
249
0
  struct window_tree_itemdata *item;
250
0
  struct mode_tree_item   *mti;
251
0
  char        *name, *text;
252
0
  struct window_pane    *wp, **l;
253
0
  u_int        n, i;
254
0
  int        expanded;
255
0
  struct format_tree    *ft;
256
257
0
  item = window_tree_add_item(data);
258
0
  item->type = WINDOW_TREE_WINDOW;
259
0
  item->session = s->id;
260
0
  item->winlink = wl->idx;
261
0
  item->pane = -1;
262
263
0
  ft = format_create(NULL, NULL, FORMAT_PANE|wl->window->active->id, 0);
264
0
  format_defaults(ft, NULL, s, wl, NULL);
265
0
  text = format_expand(ft, data->format);
266
0
  xasprintf(&name, "%u", wl->idx);
267
0
  format_free(ft);
268
269
0
  if (data->type == WINDOW_TREE_SESSION ||
270
0
      data->type == WINDOW_TREE_WINDOW)
271
0
    expanded = 0;
272
0
  else
273
0
    expanded = 1;
274
0
  mti = mode_tree_add(data->data, parent, item, (uint64_t)wl, name, text,
275
0
      expanded);
276
0
  free(text);
277
0
  free(name);
278
0
  mode_tree_align(mti, 1);
279
280
0
  if ((wp = TAILQ_FIRST(&wl->window->panes)) == NULL)
281
0
    goto empty;
282
0
  if (TAILQ_NEXT(wp, entry) == NULL) {
283
0
    if (!window_tree_filter_pane(s, wl, wp, filter))
284
0
      goto empty;
285
0
  }
286
287
0
  l = sort_get_panes_window(wl->window, &n, sort_crit);
288
0
  if (n == 0)
289
0
    goto empty;
290
0
  for (i = 0; i < n; i++) {
291
0
    if (window_tree_filter_pane(s, wl, l[i], filter))
292
0
      window_tree_build_pane(s, wl, l[i], modedata, mti);
293
0
  }
294
0
  return (1);
295
296
0
empty:
297
0
  window_tree_free_item(item);
298
0
  data->item_size--;
299
0
  mode_tree_remove(data->data, mti);
300
0
  return (0);
301
0
}
302
303
static void
304
window_tree_build_session(struct session *s, void *modedata,
305
    struct sort_criteria *sort_crit, const char *filter)
306
0
{
307
0
  struct window_tree_modedata *data = modedata;
308
0
  struct window_tree_itemdata *item;
309
0
  struct mode_tree_item   *mti;
310
0
  char        *text;
311
0
  struct winlink      *wl = s->curw, **l;
312
0
  u_int        n, i, empty;
313
0
  int        expanded;
314
0
  struct format_tree    *ft;
315
316
0
  item = window_tree_add_item(data);
317
0
  item->type = WINDOW_TREE_SESSION;
318
0
  item->session = s->id;
319
0
  item->winlink = -1;
320
0
  item->pane = -1;
321
322
0
  ft = format_create(NULL, NULL, FORMAT_PANE|wl->window->active->id, 0);
323
0
  format_defaults(ft, NULL, s, NULL, NULL);
324
0
  text = format_expand(ft, data->format);
325
0
  format_free(ft);
326
327
0
  if (data->type == WINDOW_TREE_SESSION)
328
0
    expanded = 0;
329
0
  else
330
0
    expanded = 1;
331
0
  mti = mode_tree_add(data->data, NULL, item, (uint64_t)s, s->name, text,
332
0
      expanded);
333
0
  free(text);
334
335
0
  l = sort_get_winlinks_session(s, &n, sort_crit);
336
0
  empty = 0;
337
0
  for (i = 0; i < n; i++) {
338
0
    if (!window_tree_build_window(s, l[i], modedata, sort_crit, mti,
339
0
        filter))
340
0
      empty++;
341
0
  }
342
0
  if (empty == n) {
343
0
    window_tree_free_item(item);
344
0
    data->item_size--;
345
0
    mode_tree_remove(data->data, mti);
346
0
  }
347
0
}
348
349
static void
350
window_tree_build(void *modedata, struct sort_criteria *sort_crit,
351
    uint64_t *tag, const char *filter)
352
0
{
353
0
  struct window_tree_modedata *data = modedata;
354
0
  struct session      *s, **l;
355
0
  struct session_group    *sg, *current;
356
0
  u_int        n, i;
357
358
0
  current = session_group_contains(data->fs.s);
359
360
0
  for (i = 0; i < data->item_size; i++)
361
0
    window_tree_free_item(data->item_list[i]);
362
0
  free(data->item_list);
363
0
  data->item_list = NULL;
364
0
  data->item_size = 0;
365
366
0
  l = sort_get_sessions(&n, sort_crit);
367
0
  if (n == 0)
368
0
    return;
369
0
  s = l[n - 1];
370
0
  for (i = 0; i < n; i++) {
371
0
    if (data->squash_groups &&
372
0
        (sg = session_group_contains(s)) != NULL) {
373
0
      if ((sg == current && s != data->fs.s) ||
374
0
          (sg != current && s != TAILQ_FIRST(&sg->sessions)))
375
0
        continue;
376
0
    }
377
0
    window_tree_build_session(l[i], modedata, sort_crit, filter);
378
0
  }
379
380
0
  switch (data->type) {
381
0
  case WINDOW_TREE_NONE:
382
0
    break;
383
0
  case WINDOW_TREE_SESSION:
384
0
    *tag = (uint64_t)data->fs.s;
385
0
    break;
386
0
  case WINDOW_TREE_WINDOW:
387
0
    *tag = (uint64_t)data->fs.wl;
388
0
    break;
389
0
  case WINDOW_TREE_PANE:
390
0
    if (window_count_panes(data->fs.wl->window, 1) == 1)
391
0
      *tag = (uint64_t)data->fs.wl;
392
0
    else
393
0
      *tag = (uint64_t)data->fs.wp;
394
0
    break;
395
0
  }
396
0
}
397
398
static void
399
window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
400
    u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
401
0
{
402
0
  u_int  width, ox, oy;
403
0
  char  *new_label = NULL;
404
405
0
  if (sx < 5 || sy < 3)
406
0
    return;
407
0
  width = format_width(label);
408
0
  if (width > sx - 4) {
409
0
    label = new_label = format_trim_left(label, sx - 4);
410
0
    width = format_width(new_label);
411
0
  }
412
0
  if (width == 0)
413
0
    return;
414
0
  ox = (sx - width + 1) / 2;
415
0
  oy = (sy + 1) / 2;
416
417
0
  screen_write_cursormove(ctx, px + ox - 2, py + oy - 1, 0);
418
0
  screen_write_box(ctx, width + 4, 3, BOX_LINES_DEFAULT,
419
0
      NULL, NULL);
420
0
  screen_write_cursormove(ctx, px + ox - 1, py + oy, 0);
421
0
  screen_write_clearcharacter(ctx, width + 2, 8);
422
0
  screen_write_cursormove(ctx, px + ox, py + oy, 0);
423
0
  format_draw(ctx, gc, width, label, NULL, 0);
424
0
  free(new_label);
425
0
}
426
427
static void
428
window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
429
    struct screen_write_ctx *ctx, u_int sx, u_int sy)
430
0
{
431
0
  struct winlink    *wl;
432
0
  struct window   *w;
433
0
  u_int      cx = ctx->s->cx, cy = ctx->s->cy;
434
0
  u_int      loop, total, visible, each, width, offset;
435
0
  u_int      current, start, end, remaining, i;
436
0
  struct grid_cell   gc;
437
0
  int      left, right;
438
0
  char      *label;
439
0
  const char    *format;
440
0
  struct format_tree  *ft;
441
0
  struct options    *oo;
442
443
0
  total = winlink_count(&s->windows);
444
445
0
  if (sx / total < 24) {
446
0
    visible = sx / 24;
447
0
    if (visible == 0)
448
0
      visible = 1;
449
0
  } else
450
0
    visible = total;
451
452
0
  current = 0;
453
0
  RB_FOREACH(wl, winlinks, &s->windows) {
454
0
    if (wl == s->curw)
455
0
      break;
456
0
    current++;
457
0
  }
458
459
0
  if (current < visible) {
460
0
    start = 0;
461
0
    end = visible;
462
0
  } else if (current >= total - visible) {
463
0
    start = total - visible;
464
0
    end = total;
465
0
  } else {
466
0
    start = current - (visible / 2);
467
0
    end = start + visible;
468
0
  }
469
470
0
  if (data->offset < -(int)start)
471
0
    data->offset = -(int)start;
472
0
  if (data->offset > (int)(total - end))
473
0
    data->offset = (int)(total - end);
474
0
  start += data->offset;
475
0
  end += data->offset;
476
477
0
  left = (start != 0);
478
0
  right = (end != total);
479
0
  if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
480
0
    left = right = 0;
481
0
  if (left && right) {
482
0
    each = (sx - 6) / visible;
483
0
    remaining = (sx - 6) - (visible * each);
484
0
  } else if (left || right) {
485
0
    each = (sx - 3) / visible;
486
0
    remaining = (sx - 3) - (visible * each);
487
0
  } else {
488
0
    each = sx / visible;
489
0
    remaining = sx - (visible * each);
490
0
  }
491
0
  if (each == 0)
492
0
    return;
493
494
0
  if (left) {
495
0
    data->left = cx + 2;
496
0
    screen_write_cursormove(ctx, cx + 2, cy, 0);
497
0
    screen_write_vline(ctx, sy, 0, 0);
498
0
    screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
499
0
    screen_write_puts(ctx, &grid_default_cell, "<");
500
0
  } else
501
0
    data->left = -1;
502
0
  if (right) {
503
0
    data->right = cx + sx - 3;
504
0
    screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
505
0
    screen_write_vline(ctx, sy, 0, 0);
506
0
    screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
507
0
    screen_write_puts(ctx, &grid_default_cell, ">");
508
0
  } else
509
0
    data->right = -1;
510
511
0
  data->start = start;
512
0
  data->end = end;
513
0
  data->each = each;
514
515
0
  i = loop = 0;
516
0
  RB_FOREACH(wl, winlinks, &s->windows) {
517
0
    if (loop == end)
518
0
      break;
519
0
    if (loop < start) {
520
0
      loop++;
521
0
      continue;
522
0
    }
523
0
    w = wl->window;
524
0
    oo = w->options;
525
526
0
    ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
527
0
    format_defaults(ft, NULL, s, wl, NULL);
528
529
0
    memcpy(&gc, &grid_default_cell, sizeof gc);
530
0
    style_apply(&gc, oo, "tree-mode-preview-style", ft);
531
532
0
    if (left)
533
0
      offset = 3 + (i * each);
534
0
    else
535
0
      offset = (i * each);
536
0
    if (loop == end - 1)
537
0
      width = each + remaining;
538
0
    else
539
0
      width = each - 1;
540
541
0
    screen_write_cursormove(ctx, cx + offset, cy, 0);
542
0
    screen_write_preview(ctx, &w->active->base, width, sy);
543
544
0
    format = options_get_string(oo, "tree-mode-preview-format");
545
0
    if (*format != '\0') {
546
0
      label = format_expand(ft, format);
547
0
      if (*label != '\0') {
548
0
        window_tree_draw_label(ctx, cx + offset, cy,
549
0
            width, sy, &gc, label);
550
0
      }
551
0
      free(label);
552
0
    }
553
554
0
    if (loop != end - 1) {
555
0
      screen_write_cursormove(ctx, cx + offset + width, cy,
556
0
          0);
557
0
      screen_write_vline(ctx, sy, 0, 0);
558
0
    }
559
0
    loop++;
560
561
0
    i++;
562
0
  }
563
0
}
564
565
static void
566
window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
567
    struct winlink *wl, struct screen_write_ctx *ctx, u_int sx, u_int sy)
568
0
{
569
0
  struct window   *w = wl->window;
570
0
  struct window_pane  *wp;
571
0
  u_int      cx = ctx->s->cx, cy = ctx->s->cy;
572
0
  u_int      loop, total, visible, each, width, offset;
573
0
  u_int      current, start, end, remaining, i;
574
0
  struct grid_cell   gc;
575
0
  int      left, right;
576
0
  char      *label;
577
0
  const char    *format;
578
0
  struct format_tree  *ft;
579
0
  struct options    *oo;
580
581
0
  total = window_count_panes(w, 1);
582
583
0
  if (sx / total < 24) {
584
0
    visible = sx / 24;
585
0
    if (visible == 0)
586
0
      visible = 1;
587
0
  } else
588
0
    visible = total;
589
590
0
  current = 0;
591
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
592
0
    if (wp == w->active)
593
0
      break;
594
0
    current++;
595
0
  }
596
597
0
  if (current < visible) {
598
0
    start = 0;
599
0
    end = visible;
600
0
  } else if (current >= total - visible) {
601
0
    start = total - visible;
602
0
    end = total;
603
0
  } else {
604
0
    start = current - (visible / 2);
605
0
    end = start + visible;
606
0
  }
607
608
0
  if (data->offset < -(int)start)
609
0
    data->offset = -(int)start;
610
0
  if (data->offset > (int)(total - end))
611
0
    data->offset = (int)(total - end);
612
0
  start += data->offset;
613
0
  end += data->offset;
614
615
0
  left = (start != 0);
616
0
  right = (end != total);
617
0
  if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
618
0
    left = right = 0;
619
0
  if (left && right) {
620
0
    each = (sx - 6) / visible;
621
0
    remaining = (sx - 6) - (visible * each);
622
0
  } else if (left || right) {
623
0
    each = (sx - 3) / visible;
624
0
    remaining = (sx - 3) - (visible * each);
625
0
  } else {
626
0
    each = sx / visible;
627
0
    remaining = sx - (visible * each);
628
0
  }
629
0
  if (each == 0)
630
0
    return;
631
632
0
  if (left) {
633
0
    data->left = cx + 2;
634
0
    screen_write_cursormove(ctx, cx + 2, cy, 0);
635
0
    screen_write_vline(ctx, sy, 0, 0);
636
0
    screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
637
0
    screen_write_puts(ctx, &grid_default_cell, "<");
638
0
  } else
639
0
    data->left = -1;
640
0
  if (right) {
641
0
    data->right = cx + sx - 3;
642
0
    screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
643
0
    screen_write_vline(ctx, sy, 0, 0);
644
0
    screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
645
0
    screen_write_puts(ctx, &grid_default_cell, ">");
646
0
  } else
647
0
    data->right = -1;
648
649
0
  data->start = start;
650
0
  data->end = end;
651
0
  data->each = each;
652
653
0
  i = loop = 0;
654
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
655
0
    if (loop == end)
656
0
      break;
657
0
    if (loop < start) {
658
0
      loop++;
659
0
      continue;
660
0
    }
661
0
    oo = wp->options;
662
663
0
    ft = format_create(NULL, NULL, FORMAT_PANE|wp->id, 0);
664
0
    format_defaults(ft, NULL, s, wl, wp);
665
666
0
    memcpy(&gc, &grid_default_cell, sizeof gc);
667
0
    style_apply(&gc, oo, "tree-mode-preview-style", ft);
668
669
0
    if (left)
670
0
      offset = 3 + (i * each);
671
0
    else
672
0
      offset = (i * each);
673
0
    if (loop == end - 1)
674
0
      width = each + remaining;
675
0
    else
676
0
      width = each - 1;
677
678
0
    screen_write_cursormove(ctx, cx + offset, cy, 0);
679
0
    screen_write_preview(ctx, &wp->base, width, sy);
680
681
0
    format = options_get_string(oo, "tree-mode-preview-format");
682
0
    if (*format != '\0') {
683
0
      label = format_expand(ft, format);
684
0
      if (*label != '\0') {
685
0
        window_tree_draw_label(ctx, cx + offset, cy,
686
0
            width, sy, &gc, label);
687
0
      }
688
0
      free(label);
689
0
    }
690
691
0
    if (loop != end - 1) {
692
0
      screen_write_cursormove(ctx, cx + offset + width, cy,
693
0
          0);
694
0
      screen_write_vline(ctx, sy, 0, 0);
695
0
    }
696
0
    loop++;
697
698
0
    i++;
699
0
  }
700
0
}
701
702
static void
703
window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
704
    u_int sx, u_int sy)
705
0
{
706
0
  struct window_tree_itemdata *item = itemdata;
707
0
  struct session      *sp;
708
0
  struct winlink      *wl;
709
0
  struct window_pane    *wp;
710
711
0
  window_tree_pull_item(item, &sp, &wl, &wp);
712
0
  if (wp == NULL)
713
0
    return;
714
715
0
  switch (item->type) {
716
0
  case WINDOW_TREE_NONE:
717
0
    break;
718
0
  case WINDOW_TREE_SESSION:
719
0
    window_tree_draw_session(modedata, sp, ctx, sx, sy);
720
0
    break;
721
0
  case WINDOW_TREE_WINDOW:
722
0
    window_tree_draw_window(modedata, sp, wl, ctx, sx, sy);
723
0
    break;
724
0
  case WINDOW_TREE_PANE:
725
0
    screen_write_preview(ctx, &wp->base, sx, sy);
726
0
    break;
727
0
  }
728
0
}
729
730
static int
731
window_tree_search(__unused void *modedata, void *itemdata, const char *ss,
732
    int icase)
733
0
{
734
0
  struct window_tree_itemdata *item = itemdata;
735
0
  struct session      *s;
736
0
  struct winlink      *wl;
737
0
  struct window_pane    *wp;
738
0
  char        *cmd;
739
0
  int        retval;
740
741
0
  window_tree_pull_item(item, &s, &wl, &wp);
742
743
0
  switch (item->type) {
744
0
  case WINDOW_TREE_NONE:
745
0
    return (0);
746
0
  case WINDOW_TREE_SESSION:
747
0
    if (s == NULL)
748
0
      return (0);
749
0
    if (icase)
750
0
      return (strcasestr(s->name, ss) != NULL);
751
0
    return (strstr(s->name, ss) != NULL);
752
0
  case WINDOW_TREE_WINDOW:
753
0
    if (s == NULL || wl == NULL)
754
0
      return (0);
755
0
    if (icase)
756
0
      return (strcasestr(wl->window->name, ss) != NULL);
757
0
    return (strstr(wl->window->name, ss) != NULL);
758
0
  case WINDOW_TREE_PANE:
759
0
    if (s == NULL || wl == NULL || wp == NULL)
760
0
      break;
761
0
    cmd = osdep_get_name(wp->fd, wp->tty);
762
0
    if (cmd == NULL || *cmd == '\0') {
763
0
      free(cmd);
764
0
      return (0);
765
0
    }
766
0
    if (icase)
767
0
      retval = (strcasestr(cmd, ss) != NULL);
768
0
    else
769
0
      retval = (strstr(cmd, ss) != NULL);
770
0
    free(cmd);
771
0
    return (retval);
772
0
  }
773
0
  return (0);
774
0
}
775
776
static void
777
window_tree_menu(void *modedata, struct client *c, key_code key)
778
0
{
779
0
  struct window_tree_modedata *data = modedata;
780
0
  struct window_pane    *wp = data->wp;
781
0
  struct window_mode_entry  *wme;
782
783
0
  wme = TAILQ_FIRST(&wp->modes);
784
0
  if (wme == NULL || wme->data != modedata)
785
0
    return;
786
0
  window_tree_key(wme, c, NULL, NULL, key, NULL);
787
0
}
788
789
static key_code
790
window_tree_get_key(void *modedata, void *itemdata, u_int line)
791
0
{
792
0
  struct window_tree_modedata *data = modedata;
793
0
  struct window_tree_itemdata *item = itemdata;
794
0
  struct format_tree    *ft;
795
0
  struct session      *s;
796
0
  struct winlink      *wl;
797
0
  struct window_pane    *wp;
798
0
  char        *expanded;
799
0
  key_code       key;
800
801
0
  ft = format_create(NULL, NULL, FORMAT_NONE, 0);
802
0
  window_tree_pull_item(item, &s, &wl, &wp);
803
0
  if (item->type == WINDOW_TREE_SESSION)
804
0
    format_defaults(ft, NULL, s, NULL, NULL);
805
0
  else if (item->type == WINDOW_TREE_WINDOW)
806
0
    format_defaults(ft, NULL, s, wl, NULL);
807
0
  else
808
0
    format_defaults(ft, NULL, s, wl, wp);
809
0
  format_add(ft, "line", "%u", line);
810
811
0
  expanded = format_expand(ft, data->key_format);
812
0
  key = key_string_lookup_string(expanded);
813
0
  free(expanded);
814
0
  format_free(ft);
815
0
  return (key);
816
0
}
817
818
static int
819
window_tree_swap(void *cur_itemdata, void *other_itemdata,
820
    struct sort_criteria *sort_crit)
821
0
{
822
0
  struct window_tree_itemdata *cur = cur_itemdata;
823
0
  struct window_tree_itemdata *other = other_itemdata;
824
0
  struct session      *cur_session, *other_session;
825
0
  struct winlink      *cur_winlink, *other_winlink;
826
0
  struct window     *cur_window, *other_window;
827
0
  struct window_pane    *cur_pane, *other_pane;
828
829
0
  if (cur->type != other->type)
830
0
    return (0);
831
0
  if (cur->type != WINDOW_TREE_WINDOW)
832
0
    return (0);
833
834
0
  window_tree_pull_item(cur, &cur_session, &cur_winlink, &cur_pane);
835
0
  window_tree_pull_item(other, &other_session, &other_winlink,
836
0
      &other_pane);
837
838
0
  if (cur_session != other_session)
839
0
    return (0);
840
841
  /*
842
   * Swapping indexes would not swap positions in the tree, so prevent
843
   * swapping to avoid confusing the user.
844
   */
845
0
  if (sort_would_window_tree_swap(sort_crit, cur_winlink, other_winlink))
846
0
    return (0);
847
848
0
  other_window = other_winlink->window;
849
0
  TAILQ_REMOVE(&other_window->winlinks, other_winlink, wentry);
850
0
  cur_window = cur_winlink->window;
851
0
  TAILQ_REMOVE(&cur_window->winlinks, cur_winlink, wentry);
852
853
0
  other_winlink->window = cur_window;
854
0
  TAILQ_INSERT_TAIL(&cur_window->winlinks, other_winlink, wentry);
855
0
  cur_winlink->window = other_window;
856
0
  TAILQ_INSERT_TAIL(&other_window->winlinks, cur_winlink, wentry);
857
858
0
  if (cur_session->curw == cur_winlink)
859
0
    session_set_current(cur_session, other_winlink);
860
0
  else if (cur_session->curw == other_winlink)
861
0
    session_set_current(cur_session, cur_winlink);
862
0
  session_group_synchronize_from(cur_session);
863
0
  server_redraw_session_group(cur_session);
864
0
  recalculate_sizes();
865
866
0
  return (1);
867
0
}
868
869
static void
870
window_tree_sort(struct sort_criteria *sort_crit)
871
0
{
872
0
  sort_crit->order_seq = window_tree_order_seq;
873
0
  if (sort_crit->order == SORT_END)
874
0
    sort_crit->order = sort_crit->order_seq[0];
875
0
}
876
877
static const char* window_tree_help_lines[] = {
878
  "\r\033[1m      Enter \033[0m\016x\017 \033[0mChoose selected item\n",
879
  "\r\033[1m       S-Up \033[0m\016x\017 \033[0mSwap current and previous window\n",
880
  "\r\033[1m     S-Down \033[0m\016x\017 \033[0mSwap current and next window\n",
881
  "\r\033[1m          x \033[0m\016x\017 \033[0mKill selected item\n",
882
  "\r\033[1m          X \033[0m\016x\017 \033[0mKill tagged items\n",
883
  "\r\033[1m          < \033[0m\016x\017 \033[0mScroll previews left\n",
884
  "\r\033[1m          > \033[0m\016x\017 \033[0mScroll previews right\n",
885
  "\r\033[1m          m \033[0m\016x\017 \033[0mSet the marked pane\n",
886
  "\r\033[1m          M \033[0m\016x\017 \033[0mClear the marked pane\n",
887
  "\r\033[1m          : \033[0m\016x\017 \033[0mRun a command for each tagged item\n",
888
  "\r\033[1m          f \033[0m\016x\017 \033[0mEnter a format\n",
889
  "\r\033[1m          H \033[0m\016x\017 \033[0mJump to the starting pane\n",
890
  NULL
891
};
892
893
static const char**
894
window_tree_help(u_int *width, const char **item)
895
0
{
896
0
  *width = 51;
897
0
  *item = "item";
898
0
  return (window_tree_help_lines);
899
0
}
900
901
static struct screen *
902
window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
903
    struct args *args)
904
0
{
905
0
  struct window_pane    *wp = wme->wp;
906
0
  struct window_tree_modedata *data;
907
0
  struct screen     *s;
908
909
0
  wme->data = data = xcalloc(1, sizeof *data);
910
0
  data->wp = wp;
911
0
  data->references = 1;
912
913
0
  if (args_has(args, 's'))
914
0
    data->type = WINDOW_TREE_SESSION;
915
0
  else if (args_has(args, 'w'))
916
0
    data->type = WINDOW_TREE_WINDOW;
917
0
  else
918
0
    data->type = WINDOW_TREE_PANE;
919
0
  memcpy(&data->fs, fs, sizeof data->fs);
920
921
0
  if (args == NULL || !args_has(args, 'F'))
922
0
    data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
923
0
  else
924
0
    data->format = xstrdup(args_get(args, 'F'));
925
0
  if (args == NULL || !args_has(args, 'K'))
926
0
    data->key_format = xstrdup(WINDOW_TREE_DEFAULT_KEY_FORMAT);
927
0
  else
928
0
    data->key_format = xstrdup(args_get(args, 'K'));
929
0
  if (args == NULL || args_count(args) == 0)
930
0
    data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
931
0
  else
932
0
    data->command = xstrdup(args_string(args, 0));
933
0
  data->squash_groups = !args_has(args, 'G');
934
0
  if (args_has(args, 'y'))
935
0
    data->prompt_flags = PROMPT_ACCEPT;
936
937
0
  data->data = mode_tree_start(wp, args, window_tree_build,
938
0
      window_tree_draw, window_tree_search, window_tree_menu, NULL,
939
0
      window_tree_get_key, window_tree_swap, window_tree_sort,
940
0
      window_tree_help, data, window_tree_menu_items, &s);
941
0
  mode_tree_zoom(data->data, args);
942
943
0
  mode_tree_build(data->data);
944
0
  mode_tree_draw(data->data);
945
946
0
  data->type = WINDOW_TREE_NONE;
947
948
0
  return (s);
949
0
}
950
951
static void
952
window_tree_destroy(struct window_tree_modedata *data)
953
0
{
954
0
  u_int i;
955
956
0
  if (--data->references != 0)
957
0
    return;
958
959
0
  for (i = 0; i < data->item_size; i++)
960
0
    window_tree_free_item(data->item_list[i]);
961
0
  free(data->item_list);
962
963
0
  free(data->format);
964
0
  free(data->key_format);
965
0
  free(data->command);
966
967
0
  free(data);
968
0
}
969
970
static void
971
window_tree_free(struct window_mode_entry *wme)
972
0
{
973
0
  struct window_tree_modedata *data = wme->data;
974
975
0
  if (data == NULL)
976
0
    return;
977
978
0
  data->dead = 1;
979
0
  mode_tree_free(data->data);
980
0
  window_tree_destroy(data);
981
0
}
982
983
static void
984
window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
985
0
{
986
0
  struct window_tree_modedata *data = wme->data;
987
988
0
  mode_tree_resize(data->data, sx, sy);
989
0
}
990
991
static void
992
window_tree_update(struct window_mode_entry *wme)
993
0
{
994
0
  struct window_tree_modedata *data = wme->data;
995
996
0
  mode_tree_build(data->data);
997
0
  mode_tree_draw(data->data);
998
0
  data->wp->flags |= PANE_REDRAW;
999
0
}
1000
1001
static char *
1002
window_tree_get_target(struct window_tree_itemdata *item,
1003
    struct cmd_find_state *fs)
1004
0
{
1005
0
  struct session    *s;
1006
0
  struct winlink    *wl;
1007
0
  struct window_pane  *wp;
1008
0
  char      *target;
1009
1010
0
  window_tree_pull_item(item, &s, &wl, &wp);
1011
1012
0
  target = NULL;
1013
0
  switch (item->type) {
1014
0
  case WINDOW_TREE_NONE:
1015
0
    break;
1016
0
  case WINDOW_TREE_SESSION:
1017
0
    if (s == NULL)
1018
0
      break;
1019
0
    xasprintf(&target, "=%s:", s->name);
1020
0
    break;
1021
0
  case WINDOW_TREE_WINDOW:
1022
0
    if (s == NULL || wl == NULL)
1023
0
      break;
1024
0
    xasprintf(&target, "=%s:%u.", s->name, wl->idx);
1025
0
    break;
1026
0
  case WINDOW_TREE_PANE:
1027
0
    if (s == NULL || wl == NULL || wp == NULL)
1028
0
      break;
1029
0
    xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
1030
0
    break;
1031
0
  }
1032
0
  if (target == NULL)
1033
0
    cmd_find_clear_state(fs, 0);
1034
0
  else
1035
0
    cmd_find_from_winlink_pane(fs, wl, wp, 0);
1036
0
  return (target);
1037
0
}
1038
1039
static void
1040
window_tree_command_each(void *modedata, void *itemdata, struct client *c,
1041
    __unused key_code key)
1042
0
{
1043
0
  struct window_tree_modedata *data = modedata;
1044
0
  struct window_tree_itemdata *item = itemdata;
1045
0
  char        *name;
1046
0
  struct cmd_find_state    fs;
1047
1048
0
  name = window_tree_get_target(item, &fs);
1049
0
  if (name != NULL)
1050
0
    mode_tree_run_command(c, &fs, data->entered, name);
1051
0
  free(name);
1052
0
}
1053
1054
static enum cmd_retval
1055
window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
1056
0
{
1057
0
  struct window_tree_modedata *data = modedata;
1058
1059
0
  if (!data->dead) {
1060
0
    mode_tree_build(data->data);
1061
0
    mode_tree_draw(data->data);
1062
0
    data->wp->flags |= PANE_REDRAW;
1063
0
  }
1064
0
  window_tree_destroy(data);
1065
0
  return (CMD_RETURN_NORMAL);
1066
0
}
1067
1068
static int
1069
window_tree_command_callback(struct client *c, void *modedata, const char *s,
1070
    __unused int done)
1071
0
{
1072
0
  struct window_tree_modedata *data = modedata;
1073
1074
0
  if (s == NULL || *s == '\0' || data->dead)
1075
0
    return (0);
1076
1077
0
  data->entered = s;
1078
0
  mode_tree_each_tagged(data->data, window_tree_command_each, c,
1079
0
      KEYC_NONE, 1);
1080
0
  data->entered = NULL;
1081
1082
0
  data->references++;
1083
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1084
1085
0
  return (0);
1086
0
}
1087
1088
static void
1089
window_tree_command_free(void *modedata)
1090
0
{
1091
0
  struct window_tree_modedata *data = modedata;
1092
1093
0
  window_tree_destroy(data);
1094
0
}
1095
1096
static void
1097
window_tree_kill_each(__unused void *modedata, void *itemdata,
1098
    __unused struct client *c, __unused key_code key)
1099
0
{
1100
0
  struct window_tree_itemdata *item = itemdata;
1101
0
  struct session      *s;
1102
0
  struct winlink      *wl;
1103
0
  struct window_pane    *wp;
1104
1105
0
  window_tree_pull_item(item, &s, &wl, &wp);
1106
1107
0
  switch (item->type) {
1108
0
  case WINDOW_TREE_NONE:
1109
0
    break;
1110
0
  case WINDOW_TREE_SESSION:
1111
0
    if (s != NULL) {
1112
0
      server_destroy_session(s);
1113
0
      session_destroy(s, 1, __func__);
1114
0
    }
1115
0
    break;
1116
0
  case WINDOW_TREE_WINDOW:
1117
0
    if (wl != NULL)
1118
0
      server_kill_window(wl->window, 0);
1119
0
    break;
1120
0
  case WINDOW_TREE_PANE:
1121
0
    if (wp != NULL)
1122
0
      server_kill_pane(wp);
1123
0
    break;
1124
0
  }
1125
0
}
1126
1127
static int
1128
window_tree_kill_current_callback(struct client *c, void *modedata,
1129
    const char *s, __unused int done)
1130
0
{
1131
0
  struct window_tree_modedata *data = modedata;
1132
0
  struct mode_tree_data   *mtd = data->data;
1133
1134
0
  if (s == NULL || *s == '\0' || data->dead)
1135
0
    return (0);
1136
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
1137
0
    return (0);
1138
1139
0
  window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
1140
0
  server_renumber_all();
1141
1142
0
  data->references++;
1143
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1144
1145
0
  return (0);
1146
0
}
1147
1148
static int
1149
window_tree_kill_tagged_callback(struct client *c, void *modedata,
1150
    const char *s, __unused int done)
1151
0
{
1152
0
  struct window_tree_modedata *data = modedata;
1153
0
  struct mode_tree_data   *mtd = data->data;
1154
1155
0
  if (s == NULL || *s == '\0' || data->dead)
1156
0
    return (0);
1157
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
1158
0
    return (0);
1159
1160
0
  mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
1161
0
  server_renumber_all();
1162
1163
0
  data->references++;
1164
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1165
1166
0
  return (0);
1167
0
}
1168
1169
static key_code
1170
window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
1171
    struct window_tree_itemdata *item)
1172
0
{
1173
0
  struct session    *s;
1174
0
  struct winlink    *wl;
1175
0
  struct window_pane  *wp;
1176
0
  u_int      loop;
1177
1178
0
  if (key != KEYC_MOUSEDOWN1_PANE)
1179
0
    return (KEYC_NONE);
1180
1181
0
  if (data->left != -1 && x <= (u_int)data->left)
1182
0
    return ('<');
1183
0
  if (data->right != -1 && x >= (u_int)data->right)
1184
0
    return ('>');
1185
1186
0
  if (data->left != -1)
1187
0
    x -= data->left;
1188
0
  else if (x != 0)
1189
0
    x--;
1190
0
  if (x == 0 || data->end == 0)
1191
0
    x = 0;
1192
0
  else {
1193
0
    x = x / data->each;
1194
0
    if (data->start + x >= data->end)
1195
0
      x = data->end - 1;
1196
0
  }
1197
1198
0
  window_tree_pull_item(item, &s, &wl, &wp);
1199
0
  if (item->type == WINDOW_TREE_SESSION) {
1200
0
    if (s == NULL)
1201
0
      return (KEYC_NONE);
1202
0
    mode_tree_expand_current(data->data);
1203
0
    loop = 0;
1204
0
    RB_FOREACH(wl, winlinks, &s->windows) {
1205
0
      if (loop == data->start + x)
1206
0
        break;
1207
0
      loop++;
1208
0
    }
1209
0
    if (wl != NULL)
1210
0
      mode_tree_set_current(data->data, (uint64_t)wl);
1211
0
    return ('\r');
1212
0
  }
1213
0
  if (item->type == WINDOW_TREE_WINDOW) {
1214
0
    if (wl == NULL)
1215
0
      return (KEYC_NONE);
1216
0
    mode_tree_expand_current(data->data);
1217
0
    loop = 0;
1218
0
    TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1219
0
      if (loop == data->start + x)
1220
0
        break;
1221
0
      loop++;
1222
0
    }
1223
0
    if (wp != NULL)
1224
0
      mode_tree_set_current(data->data, (uint64_t)wp);
1225
0
    return ('\r');
1226
0
  }
1227
0
  return (KEYC_NONE);
1228
0
}
1229
1230
static void
1231
window_tree_key(struct window_mode_entry *wme, struct client *c,
1232
    __unused struct session *s, __unused struct winlink *wl, key_code key,
1233
    struct mouse_event *m)
1234
0
{
1235
0
  struct window_pane    *wp = wme->wp;
1236
0
  struct window_tree_modedata *data = wme->data;
1237
0
  struct window_tree_itemdata *item, *new_item;
1238
0
  char        *name, *prompt = NULL;
1239
0
  struct cmd_find_state    fs, *fsp = &data->fs;
1240
0
  int        finished;
1241
0
  u_int        tagged, x, y, idx;
1242
0
  struct session      *ns;
1243
0
  struct winlink      *nwl;
1244
0
  struct window_pane    *nwp;
1245
1246
0
  item = mode_tree_get_current(data->data);
1247
0
  finished = mode_tree_key(data->data, c, &key, m, &x, &y);
1248
1249
0
again:
1250
0
  if (item != (new_item = mode_tree_get_current(data->data))) {
1251
0
    item = new_item;
1252
0
    data->offset = 0;
1253
0
  }
1254
0
  if (KEYC_IS_MOUSE(key) && m != NULL) {
1255
0
    key = window_tree_mouse(data, key, x, item);
1256
0
    goto again;
1257
0
  }
1258
1259
0
  switch (key) {
1260
0
  case '<':
1261
0
    data->offset--;
1262
0
    break;
1263
0
  case '>':
1264
0
    data->offset++;
1265
0
    break;
1266
0
  case 'H':
1267
0
    mode_tree_expand(data->data, (uint64_t)fsp->s);
1268
0
    mode_tree_expand(data->data, (uint64_t)fsp->wl);
1269
0
    if (!mode_tree_set_current(data->data, (uint64_t)wme->wp))
1270
0
      mode_tree_set_current(data->data, (uint64_t)fsp->wl);
1271
0
    break;
1272
0
  case 'm':
1273
0
    window_tree_pull_item(item, &ns, &nwl, &nwp);
1274
0
    server_set_marked(ns, nwl, nwp);
1275
0
    mode_tree_build(data->data);
1276
0
    break;
1277
0
  case 'M':
1278
0
    server_clear_marked();
1279
0
    mode_tree_build(data->data);
1280
0
    break;
1281
0
  case 'x':
1282
0
    window_tree_pull_item(item, &ns, &nwl, &nwp);
1283
0
    switch (item->type) {
1284
0
    case WINDOW_TREE_NONE:
1285
0
      break;
1286
0
    case WINDOW_TREE_SESSION:
1287
0
      if (ns == NULL)
1288
0
        break;
1289
0
      xasprintf(&prompt, "Kill session %s? ", ns->name);
1290
0
      break;
1291
0
    case WINDOW_TREE_WINDOW:
1292
0
      if (nwl == NULL)
1293
0
        break;
1294
0
      xasprintf(&prompt, "Kill window %u? ", nwl->idx);
1295
0
      break;
1296
0
    case WINDOW_TREE_PANE:
1297
0
      if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
1298
0
        break;
1299
0
      xasprintf(&prompt, "Kill pane %u? ", idx);
1300
0
      break;
1301
0
    }
1302
0
    if (prompt == NULL)
1303
0
      break;
1304
0
    data->references++;
1305
0
    status_prompt_set(c, NULL, prompt, "",
1306
0
        window_tree_kill_current_callback, window_tree_command_free,
1307
0
        data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
1308
0
        PROMPT_TYPE_COMMAND);
1309
0
    free(prompt);
1310
0
    break;
1311
0
  case 'X':
1312
0
    tagged = mode_tree_count_tagged(data->data);
1313
0
    if (tagged == 0)
1314
0
      break;
1315
0
    xasprintf(&prompt, "Kill %u tagged? ", tagged);
1316
0
    data->references++;
1317
0
    status_prompt_set(c, NULL, prompt, "",
1318
0
        window_tree_kill_tagged_callback, window_tree_command_free,
1319
0
        data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
1320
0
        PROMPT_TYPE_COMMAND);
1321
0
    free(prompt);
1322
0
    break;
1323
0
  case ':':
1324
0
    tagged = mode_tree_count_tagged(data->data);
1325
0
    if (tagged != 0)
1326
0
      xasprintf(&prompt, "(%u tagged) ", tagged);
1327
0
    else
1328
0
      xasprintf(&prompt, "(current) ");
1329
0
    data->references++;
1330
0
    status_prompt_set(c, NULL, prompt, "",
1331
0
        window_tree_command_callback, window_tree_command_free,
1332
0
        data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1333
0
    free(prompt);
1334
0
    break;
1335
0
  case '\r':
1336
0
    name = window_tree_get_target(item, &fs);
1337
0
    if (name != NULL)
1338
0
      mode_tree_run_command(c, NULL, data->command, name);
1339
0
    finished = 1;
1340
0
    free(name);
1341
0
    break;
1342
0
  }
1343
0
  if (finished)
1344
0
    window_pane_reset_mode(wp);
1345
0
  else {
1346
0
    mode_tree_draw(data->data);
1347
0
    wp->flags |= PANE_REDRAW;
1348
0
  }
1349
0
}