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