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