Coverage Report

Created: 2026-04-12 06:58

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)
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
  size_t   len;
403
0
  u_int  ox, oy;
404
405
0
  len = strlen(label);
406
0
  if (sx == 0 || sy == 1 || len > sx)
407
0
    return;
408
0
  ox = (sx - len + 1) / 2;
409
0
  oy = (sy + 1) / 2;
410
411
0
  if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
412
0
    screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0);
413
0
    screen_write_box(ctx, len + 2, 3, BOX_LINES_DEFAULT, NULL,
414
0
        NULL);
415
0
  }
416
0
  screen_write_cursormove(ctx, px + ox, py + oy, 0);
417
0
  screen_write_puts(ctx, gc, "%s", label);
418
0
}
419
420
static void
421
window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
422
    struct screen_write_ctx *ctx, u_int sx, u_int sy)
423
0
{
424
0
  struct options    *oo = s->options;
425
0
  struct winlink    *wl;
426
0
  struct window   *w;
427
0
  u_int      cx = ctx->s->cx, cy = ctx->s->cy;
428
0
  u_int      loop, total, visible, each, width, offset;
429
0
  u_int      current, start, end, remaining, i;
430
0
  struct grid_cell   gc;
431
0
  int      colour, active_colour, left, right;
432
0
  char      *label;
433
434
0
  total = winlink_count(&s->windows);
435
436
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
437
0
  colour = options_get_number(oo, "display-panes-colour");
438
0
  active_colour = options_get_number(oo, "display-panes-active-colour");
439
440
0
  if (sx / total < 24) {
441
0
    visible = sx / 24;
442
0
    if (visible == 0)
443
0
      visible = 1;
444
0
  } else
445
0
    visible = total;
446
447
0
  current = 0;
448
0
  RB_FOREACH(wl, winlinks, &s->windows) {
449
0
    if (wl == s->curw)
450
0
      break;
451
0
    current++;
452
0
  }
453
454
0
  if (current < visible) {
455
0
    start = 0;
456
0
    end = visible;
457
0
  } else if (current >= total - visible) {
458
0
    start = total - visible;
459
0
    end = total;
460
0
  } else {
461
0
    start = current - (visible / 2);
462
0
    end = start + visible;
463
0
  }
464
465
0
  if (data->offset < -(int)start)
466
0
    data->offset = -(int)start;
467
0
  if (data->offset > (int)(total - end))
468
0
    data->offset = (int)(total - end);
469
0
  start += data->offset;
470
0
  end += data->offset;
471
472
0
  left = (start != 0);
473
0
  right = (end != total);
474
0
  if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
475
0
    left = right = 0;
476
0
  if (left && right) {
477
0
    each = (sx - 6) / visible;
478
0
    remaining = (sx - 6) - (visible * each);
479
0
  } else if (left || right) {
480
0
    each = (sx - 3) / visible;
481
0
    remaining = (sx - 3) - (visible * each);
482
0
  } else {
483
0
    each = sx / visible;
484
0
    remaining = sx - (visible * each);
485
0
  }
486
0
  if (each == 0)
487
0
    return;
488
489
0
  if (left) {
490
0
    data->left = cx + 2;
491
0
    screen_write_cursormove(ctx, cx + 2, cy, 0);
492
0
    screen_write_vline(ctx, sy, 0, 0);
493
0
    screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
494
0
    screen_write_puts(ctx, &grid_default_cell, "<");
495
0
  } else
496
0
    data->left = -1;
497
0
  if (right) {
498
0
    data->right = cx + sx - 3;
499
0
    screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
500
0
    screen_write_vline(ctx, sy, 0, 0);
501
0
    screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
502
0
    screen_write_puts(ctx, &grid_default_cell, ">");
503
0
  } else
504
0
    data->right = -1;
505
506
0
  data->start = start;
507
0
  data->end = end;
508
0
  data->each = each;
509
510
0
  i = loop = 0;
511
0
  RB_FOREACH(wl, winlinks, &s->windows) {
512
0
    if (loop == end)
513
0
      break;
514
0
    if (loop < start) {
515
0
      loop++;
516
0
      continue;
517
0
    }
518
0
    w = wl->window;
519
520
0
    if (wl == s->curw)
521
0
      gc.fg = active_colour;
522
0
    else
523
0
      gc.fg = colour;
524
525
0
    if (left)
526
0
      offset = 3 + (i * each);
527
0
    else
528
0
      offset = (i * each);
529
0
    if (loop == end - 1)
530
0
      width = each + remaining;
531
0
    else
532
0
      width = each - 1;
533
534
0
    screen_write_cursormove(ctx, cx + offset, cy, 0);
535
0
    screen_write_preview(ctx, &w->active->base, width, sy);
536
537
0
    xasprintf(&label, " %u:%s ", wl->idx, w->name);
538
0
    if (strlen(label) > width) {
539
0
      free(label);
540
0
      xasprintf(&label, " %u ", wl->idx);
541
0
    }
542
0
    window_tree_draw_label(ctx, cx + offset, cy, width, sy, &gc,
543
0
        label);
544
0
    free(label);
545
546
0
    if (loop != end - 1) {
547
0
      screen_write_cursormove(ctx, cx + offset + width, cy, 0);
548
0
      screen_write_vline(ctx, sy, 0, 0);
549
0
    }
550
0
    loop++;
551
552
0
    i++;
553
0
  }
554
0
}
555
556
static void
557
window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
558
    struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
559
0
{
560
0
  struct options    *oo = s->options;
561
0
  struct window_pane  *wp;
562
0
  u_int      cx = ctx->s->cx, cy = ctx->s->cy;
563
0
  u_int      loop, total, visible, each, width, offset;
564
0
  u_int      current, start, end, remaining, i, pane_idx;
565
0
  struct grid_cell   gc;
566
0
  int      colour, active_colour, left, right;
567
0
  char      *label;
568
569
0
  total = window_count_panes(w);
570
571
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
572
0
  colour = options_get_number(oo, "display-panes-colour");
573
0
  active_colour = options_get_number(oo, "display-panes-active-colour");
574
575
0
  if (sx / total < 24) {
576
0
    visible = sx / 24;
577
0
    if (visible == 0)
578
0
      visible = 1;
579
0
  } else
580
0
    visible = total;
581
582
0
  current = 0;
583
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
584
0
    if (wp == w->active)
585
0
      break;
586
0
    current++;
587
0
  }
588
589
0
  if (current < visible) {
590
0
    start = 0;
591
0
    end = visible;
592
0
  } else if (current >= total - visible) {
593
0
    start = total - visible;
594
0
    end = total;
595
0
  } else {
596
0
    start = current - (visible / 2);
597
0
    end = start + visible;
598
0
  }
599
600
0
  if (data->offset < -(int)start)
601
0
    data->offset = -(int)start;
602
0
  if (data->offset > (int)(total - end))
603
0
    data->offset = (int)(total - end);
604
0
  start += data->offset;
605
0
  end += data->offset;
606
607
0
  left = (start != 0);
608
0
  right = (end != total);
609
0
  if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
610
0
    left = right = 0;
611
0
  if (left && right) {
612
0
    each = (sx - 6) / visible;
613
0
    remaining = (sx - 6) - (visible * each);
614
0
  } else if (left || right) {
615
0
    each = (sx - 3) / visible;
616
0
    remaining = (sx - 3) - (visible * each);
617
0
  } else {
618
0
    each = sx / visible;
619
0
    remaining = sx - (visible * each);
620
0
  }
621
0
  if (each == 0)
622
0
    return;
623
624
0
  if (left) {
625
0
    data->left = cx + 2;
626
0
    screen_write_cursormove(ctx, cx + 2, cy, 0);
627
0
    screen_write_vline(ctx, sy, 0, 0);
628
0
    screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
629
0
    screen_write_puts(ctx, &grid_default_cell, "<");
630
0
  } else
631
0
    data->left = -1;
632
0
  if (right) {
633
0
    data->right = cx + sx - 3;
634
0
    screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
635
0
    screen_write_vline(ctx, sy, 0, 0);
636
0
    screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
637
0
    screen_write_puts(ctx, &grid_default_cell, ">");
638
0
  } else
639
0
    data->right = -1;
640
641
0
  data->start = start;
642
0
  data->end = end;
643
0
  data->each = each;
644
645
0
  i = loop = 0;
646
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
647
0
    if (loop == end)
648
0
      break;
649
0
    if (loop < start) {
650
0
      loop++;
651
0
      continue;
652
0
    }
653
654
0
    if (wp == w->active)
655
0
      gc.fg = active_colour;
656
0
    else
657
0
      gc.fg = colour;
658
659
0
    if (left)
660
0
      offset = 3 + (i * each);
661
0
    else
662
0
      offset = (i * each);
663
0
    if (loop == end - 1)
664
0
      width = each + remaining;
665
0
    else
666
0
      width = each - 1;
667
668
0
    screen_write_cursormove(ctx, cx + offset, cy, 0);
669
0
    screen_write_preview(ctx, &wp->base, width, sy);
670
671
0
    if (window_pane_index(wp, &pane_idx) != 0)
672
0
      pane_idx = loop;
673
0
    xasprintf(&label, " %u ", pane_idx);
674
0
    window_tree_draw_label(ctx, cx + offset, cy, each, sy, &gc,
675
0
        label);
676
0
    free(label);
677
678
0
    if (loop != end - 1) {
679
0
      screen_write_cursormove(ctx, cx + offset + width, cy, 0);
680
0
      screen_write_vline(ctx, sy, 0, 0);
681
0
    }
682
0
    loop++;
683
684
0
    i++;
685
0
  }
686
0
}
687
688
static void
689
window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
690
    u_int sx, u_int sy)
691
0
{
692
0
  struct window_tree_itemdata *item = itemdata;
693
0
  struct session      *sp;
694
0
  struct winlink      *wlp;
695
0
  struct window_pane    *wp;
696
697
0
  window_tree_pull_item(item, &sp, &wlp, &wp);
698
0
  if (wp == NULL)
699
0
    return;
700
701
0
  switch (item->type) {
702
0
  case WINDOW_TREE_NONE:
703
0
    break;
704
0
  case WINDOW_TREE_SESSION:
705
0
    window_tree_draw_session(modedata, sp, ctx, sx, sy);
706
0
    break;
707
0
  case WINDOW_TREE_WINDOW:
708
0
    window_tree_draw_window(modedata, sp, wlp->window, ctx, sx, sy);
709
0
    break;
710
0
  case WINDOW_TREE_PANE:
711
0
    screen_write_preview(ctx, &wp->base, sx, sy);
712
0
    break;
713
0
  }
714
0
}
715
716
static int
717
window_tree_search(__unused void *modedata, void *itemdata, const char *ss,
718
    int icase)
719
0
{
720
0
  struct window_tree_itemdata *item = itemdata;
721
0
  struct session      *s;
722
0
  struct winlink      *wl;
723
0
  struct window_pane    *wp;
724
0
  char        *cmd;
725
0
  int        retval;
726
727
0
  window_tree_pull_item(item, &s, &wl, &wp);
728
729
0
  switch (item->type) {
730
0
  case WINDOW_TREE_NONE:
731
0
    return (0);
732
0
  case WINDOW_TREE_SESSION:
733
0
    if (s == NULL)
734
0
      return (0);
735
0
    if (icase)
736
0
      return (strcasestr(s->name, ss) != NULL);
737
0
    return (strstr(s->name, ss) != NULL);
738
0
  case WINDOW_TREE_WINDOW:
739
0
    if (s == NULL || wl == NULL)
740
0
      return (0);
741
0
    if (icase)
742
0
      return (strcasestr(wl->window->name, ss) != NULL);
743
0
    return (strstr(wl->window->name, ss) != NULL);
744
0
  case WINDOW_TREE_PANE:
745
0
    if (s == NULL || wl == NULL || wp == NULL)
746
0
      break;
747
0
    cmd = osdep_get_name(wp->fd, wp->tty);
748
0
    if (cmd == NULL || *cmd == '\0') {
749
0
      free(cmd);
750
0
      return (0);
751
0
    }
752
0
    if (icase)
753
0
      retval = (strcasestr(cmd, ss) != NULL);
754
0
    else
755
0
      retval = (strstr(cmd, ss) != NULL);
756
0
    free(cmd);
757
0
    return (retval);
758
0
  }
759
0
  return (0);
760
0
}
761
762
static void
763
window_tree_menu(void *modedata, struct client *c, key_code key)
764
0
{
765
0
  struct window_tree_modedata *data = modedata;
766
0
  struct window_pane    *wp = data->wp;
767
0
  struct window_mode_entry  *wme;
768
769
0
  wme = TAILQ_FIRST(&wp->modes);
770
0
  if (wme == NULL || wme->data != modedata)
771
0
    return;
772
0
  window_tree_key(wme, c, NULL, NULL, key, NULL);
773
0
}
774
775
static key_code
776
window_tree_get_key(void *modedata, void *itemdata, u_int line)
777
0
{
778
0
  struct window_tree_modedata *data = modedata;
779
0
  struct window_tree_itemdata *item = itemdata;
780
0
  struct format_tree    *ft;
781
0
  struct session      *s;
782
0
  struct winlink      *wl;
783
0
  struct window_pane    *wp;
784
0
  char        *expanded;
785
0
  key_code       key;
786
787
0
  ft = format_create(NULL, NULL, FORMAT_NONE, 0);
788
0
  window_tree_pull_item(item, &s, &wl, &wp);
789
0
  if (item->type == WINDOW_TREE_SESSION)
790
0
    format_defaults(ft, NULL, s, NULL, NULL);
791
0
  else if (item->type == WINDOW_TREE_WINDOW)
792
0
    format_defaults(ft, NULL, s, wl, NULL);
793
0
  else
794
0
    format_defaults(ft, NULL, s, wl, wp);
795
0
  format_add(ft, "line", "%u", line);
796
797
0
  expanded = format_expand(ft, data->key_format);
798
0
  key = key_string_lookup_string(expanded);
799
0
  free(expanded);
800
0
  format_free(ft);
801
0
  return (key);
802
0
}
803
804
static int
805
window_tree_swap(void *cur_itemdata, void *other_itemdata,
806
    struct sort_criteria *sort_crit)
807
0
{
808
0
  struct window_tree_itemdata *cur = cur_itemdata;
809
0
  struct window_tree_itemdata *other = other_itemdata;
810
0
  struct session      *cur_session, *other_session;
811
0
  struct winlink      *cur_winlink, *other_winlink;
812
0
  struct window     *cur_window, *other_window;
813
0
  struct window_pane    *cur_pane, *other_pane;
814
815
0
  if (cur->type != other->type)
816
0
    return (0);
817
0
  if (cur->type != WINDOW_TREE_WINDOW)
818
0
    return (0);
819
820
0
  window_tree_pull_item(cur, &cur_session, &cur_winlink, &cur_pane);
821
0
  window_tree_pull_item(other, &other_session, &other_winlink,
822
0
      &other_pane);
823
824
0
  if (cur_session != other_session)
825
0
    return (0);
826
827
  /*
828
   * Swapping indexes would not swap positions in the tree, so prevent
829
   * swapping to avoid confusing the user.
830
   */
831
0
  if (sort_would_window_tree_swap(sort_crit, cur_winlink, other_winlink))
832
0
    return (0);
833
834
0
  other_window = other_winlink->window;
835
0
  TAILQ_REMOVE(&other_window->winlinks, other_winlink, wentry);
836
0
  cur_window = cur_winlink->window;
837
0
  TAILQ_REMOVE(&cur_window->winlinks, cur_winlink, wentry);
838
839
0
  other_winlink->window = cur_window;
840
0
  TAILQ_INSERT_TAIL(&cur_window->winlinks, other_winlink, wentry);
841
0
  cur_winlink->window = other_window;
842
0
  TAILQ_INSERT_TAIL(&other_window->winlinks, cur_winlink, wentry);
843
844
0
  if (cur_session->curw == cur_winlink)
845
0
    session_set_current(cur_session, other_winlink);
846
0
  else if (cur_session->curw == other_winlink)
847
0
    session_set_current(cur_session, cur_winlink);
848
0
  session_group_synchronize_from(cur_session);
849
0
  server_redraw_session_group(cur_session);
850
0
  recalculate_sizes();
851
852
0
  return (1);
853
0
}
854
855
static void
856
window_tree_sort(struct sort_criteria *sort_crit)
857
0
{
858
0
  sort_crit->order_seq = window_tree_order_seq;
859
0
  if (sort_crit->order == SORT_END)
860
0
    sort_crit->order = sort_crit->order_seq[0];
861
0
}
862
863
static const char* window_tree_help_lines[] = {
864
  "\r\033[1m      Enter \033[0m\016x\017 \033[0mChoose selected item\n",
865
  "\r\033[1m       S-Up \033[0m\016x\017 \033[0mSwap current and previous window\n",
866
  "\r\033[1m     S-Down \033[0m\016x\017 \033[0mSwap current and next window\n",
867
  "\r\033[1m          x \033[0m\016x\017 \033[0mKill selected item\n",
868
  "\r\033[1m          X \033[0m\016x\017 \033[0mKill tagged items\n",
869
  "\r\033[1m          < \033[0m\016x\017 \033[0mScroll previews left\n",
870
  "\r\033[1m          > \033[0m\016x\017 \033[0mScroll previews right\n",
871
  "\r\033[1m          m \033[0m\016x\017 \033[0mSet the marked pane\n",
872
  "\r\033[1m          M \033[0m\016x\017 \033[0mClear the marked pane\n",
873
  "\r\033[1m          : \033[0m\016x\017 \033[0mRun a command for each tagged item\n",
874
  "\r\033[1m          f \033[0m\016x\017 \033[0mEnter a format\n",
875
  "\r\033[1m          H \033[0m\016x\017 \033[0mJump to the starting pane\n",
876
  NULL
877
};
878
879
static const char**
880
window_tree_help(u_int *width, const char **item)
881
0
{
882
0
  *width = 51;
883
0
  *item = "item";
884
0
  return (window_tree_help_lines);
885
0
}
886
887
static struct screen *
888
window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
889
    struct args *args)
890
0
{
891
0
  struct window_pane    *wp = wme->wp;
892
0
  struct window_tree_modedata *data;
893
0
  struct screen     *s;
894
895
0
  wme->data = data = xcalloc(1, sizeof *data);
896
0
  data->wp = wp;
897
0
  data->references = 1;
898
899
0
  if (args_has(args, 's'))
900
0
    data->type = WINDOW_TREE_SESSION;
901
0
  else if (args_has(args, 'w'))
902
0
    data->type = WINDOW_TREE_WINDOW;
903
0
  else
904
0
    data->type = WINDOW_TREE_PANE;
905
0
  memcpy(&data->fs, fs, sizeof data->fs);
906
907
0
  if (args == NULL || !args_has(args, 'F'))
908
0
    data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
909
0
  else
910
0
    data->format = xstrdup(args_get(args, 'F'));
911
0
  if (args == NULL || !args_has(args, 'K'))
912
0
    data->key_format = xstrdup(WINDOW_TREE_DEFAULT_KEY_FORMAT);
913
0
  else
914
0
    data->key_format = xstrdup(args_get(args, 'K'));
915
0
  if (args == NULL || args_count(args) == 0)
916
0
    data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
917
0
  else
918
0
    data->command = xstrdup(args_string(args, 0));
919
0
  data->squash_groups = !args_has(args, 'G');
920
0
  if (args_has(args, 'y'))
921
0
    data->prompt_flags = PROMPT_ACCEPT;
922
923
0
  data->data = mode_tree_start(wp, args, window_tree_build,
924
0
      window_tree_draw, window_tree_search, window_tree_menu, NULL,
925
0
      window_tree_get_key, window_tree_swap, window_tree_sort,
926
0
      window_tree_help, data, window_tree_menu_items, &s);
927
0
  mode_tree_zoom(data->data, args);
928
929
0
  mode_tree_build(data->data);
930
0
  mode_tree_draw(data->data);
931
932
0
  data->type = WINDOW_TREE_NONE;
933
934
0
  return (s);
935
0
}
936
937
static void
938
window_tree_destroy(struct window_tree_modedata *data)
939
0
{
940
0
  u_int i;
941
942
0
  if (--data->references != 0)
943
0
    return;
944
945
0
  for (i = 0; i < data->item_size; i++)
946
0
    window_tree_free_item(data->item_list[i]);
947
0
  free(data->item_list);
948
949
0
  free(data->format);
950
0
  free(data->key_format);
951
0
  free(data->command);
952
953
0
  free(data);
954
0
}
955
956
static void
957
window_tree_free(struct window_mode_entry *wme)
958
0
{
959
0
  struct window_tree_modedata *data = wme->data;
960
961
0
  if (data == NULL)
962
0
    return;
963
964
0
  data->dead = 1;
965
0
  mode_tree_free(data->data);
966
0
  window_tree_destroy(data);
967
0
}
968
969
static void
970
window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
971
0
{
972
0
  struct window_tree_modedata *data = wme->data;
973
974
0
  mode_tree_resize(data->data, sx, sy);
975
0
}
976
977
static void
978
window_tree_update(struct window_mode_entry *wme)
979
0
{
980
0
  struct window_tree_modedata *data = wme->data;
981
982
0
  mode_tree_build(data->data);
983
0
  mode_tree_draw(data->data);
984
0
  data->wp->flags |= PANE_REDRAW;
985
0
}
986
987
static char *
988
window_tree_get_target(struct window_tree_itemdata *item,
989
    struct cmd_find_state *fs)
990
0
{
991
0
  struct session    *s;
992
0
  struct winlink    *wl;
993
0
  struct window_pane  *wp;
994
0
  char      *target;
995
996
0
  window_tree_pull_item(item, &s, &wl, &wp);
997
998
0
  target = NULL;
999
0
  switch (item->type) {
1000
0
  case WINDOW_TREE_NONE:
1001
0
    break;
1002
0
  case WINDOW_TREE_SESSION:
1003
0
    if (s == NULL)
1004
0
      break;
1005
0
    xasprintf(&target, "=%s:", s->name);
1006
0
    break;
1007
0
  case WINDOW_TREE_WINDOW:
1008
0
    if (s == NULL || wl == NULL)
1009
0
      break;
1010
0
    xasprintf(&target, "=%s:%u.", s->name, wl->idx);
1011
0
    break;
1012
0
  case WINDOW_TREE_PANE:
1013
0
    if (s == NULL || wl == NULL || wp == NULL)
1014
0
      break;
1015
0
    xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
1016
0
    break;
1017
0
  }
1018
0
  if (target == NULL)
1019
0
    cmd_find_clear_state(fs, 0);
1020
0
  else
1021
0
    cmd_find_from_winlink_pane(fs, wl, wp, 0);
1022
0
  return (target);
1023
0
}
1024
1025
static void
1026
window_tree_command_each(void *modedata, void *itemdata, struct client *c,
1027
    __unused key_code key)
1028
0
{
1029
0
  struct window_tree_modedata *data = modedata;
1030
0
  struct window_tree_itemdata *item = itemdata;
1031
0
  char        *name;
1032
0
  struct cmd_find_state    fs;
1033
1034
0
  name = window_tree_get_target(item, &fs);
1035
0
  if (name != NULL)
1036
0
    mode_tree_run_command(c, &fs, data->entered, name);
1037
0
  free(name);
1038
0
}
1039
1040
static enum cmd_retval
1041
window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
1042
0
{
1043
0
  struct window_tree_modedata *data = modedata;
1044
1045
0
  if (!data->dead) {
1046
0
    mode_tree_build(data->data);
1047
0
    mode_tree_draw(data->data);
1048
0
    data->wp->flags |= PANE_REDRAW;
1049
0
  }
1050
0
  window_tree_destroy(data);
1051
0
  return (CMD_RETURN_NORMAL);
1052
0
}
1053
1054
static int
1055
window_tree_command_callback(struct client *c, void *modedata, const char *s,
1056
    __unused int done)
1057
0
{
1058
0
  struct window_tree_modedata *data = modedata;
1059
1060
0
  if (s == NULL || *s == '\0' || data->dead)
1061
0
    return (0);
1062
1063
0
  data->entered = s;
1064
0
  mode_tree_each_tagged(data->data, window_tree_command_each, c,
1065
0
      KEYC_NONE, 1);
1066
0
  data->entered = NULL;
1067
1068
0
  data->references++;
1069
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1070
1071
0
  return (0);
1072
0
}
1073
1074
static void
1075
window_tree_command_free(void *modedata)
1076
0
{
1077
0
  struct window_tree_modedata *data = modedata;
1078
1079
0
  window_tree_destroy(data);
1080
0
}
1081
1082
static void
1083
window_tree_kill_each(__unused void *modedata, void *itemdata,
1084
    __unused struct client *c, __unused key_code key)
1085
0
{
1086
0
  struct window_tree_itemdata *item = itemdata;
1087
0
  struct session      *s;
1088
0
  struct winlink      *wl;
1089
0
  struct window_pane    *wp;
1090
1091
0
  window_tree_pull_item(item, &s, &wl, &wp);
1092
1093
0
  switch (item->type) {
1094
0
  case WINDOW_TREE_NONE:
1095
0
    break;
1096
0
  case WINDOW_TREE_SESSION:
1097
0
    if (s != NULL) {
1098
0
      server_destroy_session(s);
1099
0
      session_destroy(s, 1, __func__);
1100
0
    }
1101
0
    break;
1102
0
  case WINDOW_TREE_WINDOW:
1103
0
    if (wl != NULL)
1104
0
      server_kill_window(wl->window, 0);
1105
0
    break;
1106
0
  case WINDOW_TREE_PANE:
1107
0
    if (wp != NULL)
1108
0
      server_kill_pane(wp);
1109
0
    break;
1110
0
  }
1111
0
}
1112
1113
static int
1114
window_tree_kill_current_callback(struct client *c, void *modedata,
1115
    const char *s, __unused int done)
1116
0
{
1117
0
  struct window_tree_modedata *data = modedata;
1118
0
  struct mode_tree_data   *mtd = data->data;
1119
1120
0
  if (s == NULL || *s == '\0' || data->dead)
1121
0
    return (0);
1122
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
1123
0
    return (0);
1124
1125
0
  window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
1126
0
  server_renumber_all();
1127
1128
0
  data->references++;
1129
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1130
1131
0
  return (0);
1132
0
}
1133
1134
static int
1135
window_tree_kill_tagged_callback(struct client *c, void *modedata,
1136
    const char *s, __unused int done)
1137
0
{
1138
0
  struct window_tree_modedata *data = modedata;
1139
0
  struct mode_tree_data   *mtd = data->data;
1140
1141
0
  if (s == NULL || *s == '\0' || data->dead)
1142
0
    return (0);
1143
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
1144
0
    return (0);
1145
1146
0
  mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
1147
0
  server_renumber_all();
1148
1149
0
  data->references++;
1150
0
  cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
1151
1152
0
  return (0);
1153
0
}
1154
1155
static key_code
1156
window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
1157
    struct window_tree_itemdata *item)
1158
0
{
1159
0
  struct session    *s;
1160
0
  struct winlink    *wl;
1161
0
  struct window_pane  *wp;
1162
0
  u_int      loop;
1163
1164
0
  if (key != KEYC_MOUSEDOWN1_PANE)
1165
0
    return (KEYC_NONE);
1166
1167
0
  if (data->left != -1 && x <= (u_int)data->left)
1168
0
    return ('<');
1169
0
  if (data->right != -1 && x >= (u_int)data->right)
1170
0
    return ('>');
1171
1172
0
  if (data->left != -1)
1173
0
    x -= data->left;
1174
0
  else if (x != 0)
1175
0
    x--;
1176
0
  if (x == 0 || data->end == 0)
1177
0
    x = 0;
1178
0
  else {
1179
0
    x = x / data->each;
1180
0
    if (data->start + x >= data->end)
1181
0
      x = data->end - 1;
1182
0
  }
1183
1184
0
  window_tree_pull_item(item, &s, &wl, &wp);
1185
0
  if (item->type == WINDOW_TREE_SESSION) {
1186
0
    if (s == NULL)
1187
0
      return (KEYC_NONE);
1188
0
    mode_tree_expand_current(data->data);
1189
0
    loop = 0;
1190
0
    RB_FOREACH(wl, winlinks, &s->windows) {
1191
0
      if (loop == data->start + x)
1192
0
        break;
1193
0
      loop++;
1194
0
    }
1195
0
    if (wl != NULL)
1196
0
      mode_tree_set_current(data->data, (uint64_t)wl);
1197
0
    return ('\r');
1198
0
  }
1199
0
  if (item->type == WINDOW_TREE_WINDOW) {
1200
0
    if (wl == NULL)
1201
0
      return (KEYC_NONE);
1202
0
    mode_tree_expand_current(data->data);
1203
0
    loop = 0;
1204
0
    TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1205
0
      if (loop == data->start + x)
1206
0
        break;
1207
0
      loop++;
1208
0
    }
1209
0
    if (wp != NULL)
1210
0
      mode_tree_set_current(data->data, (uint64_t)wp);
1211
0
    return ('\r');
1212
0
  }
1213
0
  return (KEYC_NONE);
1214
0
}
1215
1216
static void
1217
window_tree_key(struct window_mode_entry *wme, struct client *c,
1218
    __unused struct session *s, __unused struct winlink *wl, key_code key,
1219
    struct mouse_event *m)
1220
0
{
1221
0
  struct window_pane    *wp = wme->wp;
1222
0
  struct window_tree_modedata *data = wme->data;
1223
0
  struct window_tree_itemdata *item, *new_item;
1224
0
  char        *name, *prompt = NULL;
1225
0
  struct cmd_find_state    fs, *fsp = &data->fs;
1226
0
  int        finished;
1227
0
  u_int        tagged, x, y, idx;
1228
0
  struct session      *ns;
1229
0
  struct winlink      *nwl;
1230
0
  struct window_pane    *nwp;
1231
1232
0
  item = mode_tree_get_current(data->data);
1233
0
  finished = mode_tree_key(data->data, c, &key, m, &x, &y);
1234
1235
0
again:
1236
0
  if (item != (new_item = mode_tree_get_current(data->data))) {
1237
0
    item = new_item;
1238
0
    data->offset = 0;
1239
0
  }
1240
0
  if (KEYC_IS_MOUSE(key) && m != NULL) {
1241
0
    key = window_tree_mouse(data, key, x, item);
1242
0
    goto again;
1243
0
  }
1244
1245
0
  switch (key) {
1246
0
  case '<':
1247
0
    data->offset--;
1248
0
    break;
1249
0
  case '>':
1250
0
    data->offset++;
1251
0
    break;
1252
0
  case 'H':
1253
0
    mode_tree_expand(data->data, (uint64_t)fsp->s);
1254
0
    mode_tree_expand(data->data, (uint64_t)fsp->wl);
1255
0
    if (!mode_tree_set_current(data->data, (uint64_t)wme->wp))
1256
0
      mode_tree_set_current(data->data, (uint64_t)fsp->wl);
1257
0
    break;
1258
0
  case 'm':
1259
0
    window_tree_pull_item(item, &ns, &nwl, &nwp);
1260
0
    server_set_marked(ns, nwl, nwp);
1261
0
    mode_tree_build(data->data);
1262
0
    break;
1263
0
  case 'M':
1264
0
    server_clear_marked();
1265
0
    mode_tree_build(data->data);
1266
0
    break;
1267
0
  case 'x':
1268
0
    window_tree_pull_item(item, &ns, &nwl, &nwp);
1269
0
    switch (item->type) {
1270
0
    case WINDOW_TREE_NONE:
1271
0
      break;
1272
0
    case WINDOW_TREE_SESSION:
1273
0
      if (ns == NULL)
1274
0
        break;
1275
0
      xasprintf(&prompt, "Kill session %s? ", ns->name);
1276
0
      break;
1277
0
    case WINDOW_TREE_WINDOW:
1278
0
      if (nwl == NULL)
1279
0
        break;
1280
0
      xasprintf(&prompt, "Kill window %u? ", nwl->idx);
1281
0
      break;
1282
0
    case WINDOW_TREE_PANE:
1283
0
      if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
1284
0
        break;
1285
0
      xasprintf(&prompt, "Kill pane %u? ", idx);
1286
0
      break;
1287
0
    }
1288
0
    if (prompt == NULL)
1289
0
      break;
1290
0
    data->references++;
1291
0
    status_prompt_set(c, NULL, prompt, "",
1292
0
        window_tree_kill_current_callback, window_tree_command_free,
1293
0
        data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
1294
0
        PROMPT_TYPE_COMMAND);
1295
0
    free(prompt);
1296
0
    break;
1297
0
  case 'X':
1298
0
    tagged = mode_tree_count_tagged(data->data);
1299
0
    if (tagged == 0)
1300
0
      break;
1301
0
    xasprintf(&prompt, "Kill %u tagged? ", tagged);
1302
0
    data->references++;
1303
0
    status_prompt_set(c, NULL, prompt, "",
1304
0
        window_tree_kill_tagged_callback, window_tree_command_free,
1305
0
        data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
1306
0
        PROMPT_TYPE_COMMAND);
1307
0
    free(prompt);
1308
0
    break;
1309
0
  case ':':
1310
0
    tagged = mode_tree_count_tagged(data->data);
1311
0
    if (tagged != 0)
1312
0
      xasprintf(&prompt, "(%u tagged) ", tagged);
1313
0
    else
1314
0
      xasprintf(&prompt, "(current) ");
1315
0
    data->references++;
1316
0
    status_prompt_set(c, NULL, prompt, "",
1317
0
        window_tree_command_callback, window_tree_command_free,
1318
0
        data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
1319
0
    free(prompt);
1320
0
    break;
1321
0
  case '\r':
1322
0
    name = window_tree_get_target(item, &fs);
1323
0
    if (name != NULL)
1324
0
      mode_tree_run_command(c, NULL, data->command, name);
1325
0
    finished = 1;
1326
0
    free(name);
1327
0
    break;
1328
0
  }
1329
0
  if (finished)
1330
0
    window_pane_reset_mode(wp);
1331
0
  else {
1332
0
    mode_tree_draw(data->data);
1333
0
    wp->flags |= PANE_REDRAW;
1334
0
  }
1335
0
}