Need to set clients in context before changing their reference count.
[tmux-openbsd.git] / window-choose.c
blob4443e1a5271832e114f22d6d9587dcc8827e9c74
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "tmux.h"
27 struct screen *window_choose_init(struct window_pane *);
28 void window_choose_free(struct window_pane *);
29 void window_choose_resize(struct window_pane *, u_int, u_int);
30 void window_choose_key(struct window_pane *, struct session *, int);
31 void window_choose_mouse(
32 struct window_pane *, struct session *, struct mouse_event *);
34 void window_choose_default_callback(struct window_choose_data *);
36 void window_choose_fire_callback(
37 struct window_pane *, struct window_choose_data *);
38 void window_choose_redraw_screen(struct window_pane *);
39 void window_choose_write_line(
40 struct window_pane *, struct screen_write_ctx *, u_int);
42 void window_choose_scroll_up(struct window_pane *);
43 void window_choose_scroll_down(struct window_pane *);
45 void window_choose_collapse(struct window_pane *, struct session *);
46 void window_choose_expand(struct window_pane *, struct session *, u_int);
47 void window_choose_collapse_all(struct window_pane *);
49 enum window_choose_input_type {
50 WINDOW_CHOOSE_NORMAL = -1,
51 WINDOW_CHOOSE_GOTO_ITEM,
54 const struct window_mode window_choose_mode = {
55 window_choose_init,
56 window_choose_free,
57 window_choose_resize,
58 window_choose_key,
59 window_choose_mouse,
60 NULL,
63 struct window_choose_mode_data {
64 struct screen screen;
66 struct mode_key_data mdata;
68 ARRAY_DECL(, struct window_choose_mode_item) list;
69 ARRAY_DECL(, struct window_choose_mode_item) old_list;
70 int width;
71 u_int top;
72 u_int selected;
73 enum window_choose_input_type input_type;
74 const char *input_prompt;
75 char *input_str;
77 void (*callbackfn)(struct window_choose_data *);
80 void window_choose_free1(struct window_choose_mode_data *);
81 int window_choose_key_index(struct window_choose_mode_data *, u_int);
82 int window_choose_index_key(struct window_choose_mode_data *, int);
83 void window_choose_prompt_input(enum window_choose_input_type,
84 const char *, struct window_pane *, int);
86 void
87 window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
89 struct window_choose_mode_data *data = wp->modedata;
90 struct window_choose_mode_item *item;
91 char tmp[10];
93 ARRAY_EXPAND(&data->list, 1);
94 item = &ARRAY_LAST(&data->list);
96 item->name = format_expand(wcd->ft, wcd->ft_template);
97 item->wcd = wcd;
98 item->pos = ARRAY_LENGTH(&data->list) - 1;
99 item->state = 0;
101 data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos);
104 void
105 window_choose_ready(struct window_pane *wp, u_int cur,
106 void (*callbackfn)(struct window_choose_data *))
108 struct window_choose_mode_data *data = wp->modedata;
109 struct screen *s = &data->screen;
111 data->selected = cur;
112 if (data->selected > screen_size_y(s) - 1)
113 data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
115 data->callbackfn = callbackfn;
116 if (data->callbackfn == NULL)
117 data->callbackfn = window_choose_default_callback;
119 ARRAY_CONCAT(&data->old_list, &data->list);
121 window_choose_collapse_all(wp);
124 struct screen *
125 window_choose_init(struct window_pane *wp)
127 struct window_choose_mode_data *data;
128 struct screen *s;
129 int keys;
131 wp->modedata = data = xmalloc(sizeof *data);
133 data->callbackfn = NULL;
134 data->input_type = WINDOW_CHOOSE_NORMAL;
135 data->input_str = xstrdup("");
136 data->input_prompt = NULL;
138 ARRAY_INIT(&data->list);
139 ARRAY_INIT(&data->old_list);
140 data->top = 0;
142 s = &data->screen;
143 screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
144 s->mode &= ~MODE_CURSOR;
145 if (options_get_number(&wp->window->options, "mode-mouse"))
146 s->mode |= MODE_MOUSE_STANDARD;
148 keys = options_get_number(&wp->window->options, "mode-keys");
149 if (keys == MODEKEY_EMACS)
150 mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
151 else
152 mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
154 return (s);
157 struct window_choose_data *
158 window_choose_data_create(int type, struct client *c, struct session *s)
160 struct window_choose_data *wcd;
162 wcd = xmalloc(sizeof *wcd);
163 wcd->type = type;
165 wcd->ft = format_create();
166 wcd->ft_template = NULL;
168 wcd->command = NULL;
170 wcd->wl = NULL;
171 wcd->pane_id = -1;
172 wcd->idx = -1;
174 wcd->tree_session = NULL;
176 wcd->start_client = c;
177 wcd->start_client->references++;
178 wcd->start_session = s;
179 wcd->start_session->references++;
181 return (wcd);
184 void
185 window_choose_data_free(struct window_choose_data *wcd)
187 wcd->start_client->references--;
188 wcd->start_session->references--;
190 if (wcd->tree_session != NULL)
191 wcd->tree_session->references--;
193 free(wcd->ft_template);
194 format_free(wcd->ft);
196 free(wcd->command);
197 free(wcd);
200 void
201 window_choose_data_run(struct window_choose_data *cdata)
203 struct cmd_ctx *ctx;
204 struct cmd_list *cmdlist;
205 char *cause;
208 * The command template will have already been replaced. But if it's
209 * NULL, bail here.
211 if (cdata->command == NULL)
212 return;
214 if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) {
215 if (cause != NULL) {
216 *cause = toupper((u_char) *cause);
217 status_message_set(cdata->start_client, "%s", cause);
218 free(cause);
220 return;
223 ctx = cmd_get_ctx(NULL, cdata->start_client);
224 ctx->error = key_bindings_error;
225 ctx->print = key_bindings_print;
226 ctx->info = key_bindings_info;
228 cmd_list_exec(cmdlist, ctx);
229 cmd_list_free(cmdlist);
230 cmd_free_ctx(ctx);
233 void
234 window_choose_default_callback(struct window_choose_data *wcd)
236 if (wcd == NULL)
237 return;
238 if (wcd->start_client->flags & CLIENT_DEAD)
239 return;
241 window_choose_data_run(wcd);
244 void
245 window_choose_free(struct window_pane *wp)
247 if (wp->modedata != NULL)
248 window_choose_free1(wp->modedata);
251 void
252 window_choose_free1(struct window_choose_mode_data *data)
254 struct window_choose_mode_item *item;
255 u_int i;
257 if (data == NULL)
258 return;
260 for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
261 item = &ARRAY_ITEM(&data->old_list, i);
262 window_choose_data_free(item->wcd);
263 free(item->name);
265 ARRAY_FREE(&data->list);
266 ARRAY_FREE(&data->old_list);
267 free(data->input_str);
269 screen_free(&data->screen);
270 free(data);
273 void
274 window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
276 struct window_choose_mode_data *data = wp->modedata;
277 struct screen *s = &data->screen;
279 data->top = 0;
280 if (data->selected > sy - 1)
281 data->top = data->selected - (sy - 1);
283 screen_resize(s, sx, sy, 0);
284 window_choose_redraw_screen(wp);
287 void
288 window_choose_fire_callback(
289 struct window_pane *wp, struct window_choose_data *wcd)
291 struct window_choose_mode_data *data = wp->modedata;
293 wp->modedata = NULL;
294 window_pane_reset_mode(wp);
296 data->callbackfn(wcd);
298 window_choose_free1(data);
301 void
302 window_choose_prompt_input(enum window_choose_input_type input_type,
303 const char *prompt, struct window_pane *wp, int key)
305 struct window_choose_mode_data *data = wp->modedata;
306 size_t input_len;
308 data->input_type = input_type;
309 data->input_prompt = prompt;
310 input_len = strlen(data->input_str) + 2;
312 data->input_str = xrealloc(data->input_str, 1, input_len);
313 data->input_str[input_len - 2] = key;
314 data->input_str[input_len - 1] = '\0';
316 window_choose_redraw_screen(wp);
319 void
320 window_choose_collapse(struct window_pane *wp, struct session *s)
322 struct window_choose_mode_data *data = wp->modedata;
323 struct window_choose_mode_item *item, *chosen;
324 struct window_choose_data *wcd;
325 u_int i, pos;
327 ARRAY_DECL(, struct window_choose_mode_item) list_copy;
328 ARRAY_INIT(&list_copy);
330 pos = data->selected;
332 chosen = &ARRAY_ITEM(&data->list, pos);
333 chosen->state &= ~TREE_EXPANDED;
336 * Trying to mangle the &data->list in-place has lots of problems, so
337 * assign the actual result we want to render and copy the new one over
338 * the top of it.
340 for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
342 item = &ARRAY_ITEM(&data->list, i);
343 wcd = item->wcd;
345 if (s == wcd->tree_session) {
346 /* We only show the session when collapsed. */
347 if (wcd->type & TREE_SESSION) {
348 item->state &= ~TREE_EXPANDED;
350 ARRAY_ADD(&list_copy,
351 ARRAY_ITEM(&data->list, i));
353 * Update the selection to this session item so
354 * we don't end up highlighting a non-existent
355 * item.
357 data->selected = i;
359 } else
360 ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
363 if (!ARRAY_EMPTY(&list_copy)) {
364 ARRAY_FREE(&data->list);
365 ARRAY_CONCAT(&data->list, &list_copy);
366 ARRAY_FREE(&list_copy);
370 void
371 window_choose_collapse_all(struct window_pane *wp)
373 struct window_choose_mode_data *data = wp->modedata;
374 struct window_choose_mode_item *item;
375 struct session *s, *chosen;
376 u_int i;
378 chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
380 RB_FOREACH(s, sessions, &sessions)
381 window_choose_collapse(wp, s);
383 /* Reset the selection back to the starting session. */
384 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
385 item = &ARRAY_ITEM(&data->list, i);
387 if (chosen != item->wcd->tree_session)
388 continue;
390 if (item->wcd->type & TREE_SESSION)
391 data->selected = i;
393 window_choose_redraw_screen(wp);
396 void
397 window_choose_expand_all(struct window_pane *wp)
399 struct window_choose_mode_data *data = wp->modedata;
400 struct window_choose_mode_item *item;
401 struct session *s;
402 u_int i;
404 RB_FOREACH(s, sessions, &sessions) {
405 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
406 item = &ARRAY_ITEM(&data->list, i);
408 if (s != item->wcd->tree_session)
409 continue;
411 if (item->wcd->type & TREE_SESSION)
412 window_choose_expand(wp, s, i);
416 window_choose_redraw_screen(wp);
419 void
420 window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
422 struct window_choose_mode_data *data = wp->modedata;
423 struct window_choose_mode_item *item, *chosen;
424 struct window_choose_data *wcd;
425 u_int i, items;
427 chosen = &ARRAY_ITEM(&data->list, pos);
428 items = ARRAY_LENGTH(&data->old_list) - 1;
430 /* It's not possible to expand anything other than sessions. */
431 if (!(chosen->wcd->type & TREE_SESSION))
432 return;
434 /* Don't re-expand a session which is already expanded. */
435 if (chosen->state & TREE_EXPANDED)
436 return;
438 /* Mark the session entry as expanded. */
439 chosen->state |= TREE_EXPANDED;
442 * Go back through the original list of all sessions and windows, and
443 * pull out the windows where the session matches the selection chosen
444 * to expand.
446 for (i = items; i > 0; i--) {
447 item = &ARRAY_ITEM(&data->old_list, i);
448 item->state |= TREE_EXPANDED;
449 wcd = item->wcd;
451 if (s == wcd->tree_session) {
453 * Since the session is already displayed, we only care
454 * to add back in window for it.
456 if (wcd->type & TREE_WINDOW) {
458 * If the insertion point for adding the
459 * windows to the session falls inside the
460 * range of the list, then we insert these
461 * entries in order *AFTER* the selected
462 * session.
464 if (pos < i ) {
465 ARRAY_INSERT(&data->list,
466 pos + 1,
467 ARRAY_ITEM(&data->old_list,
468 i));
469 } else {
470 /* Ran out of room, add to the end. */
471 ARRAY_ADD(&data->list,
472 ARRAY_ITEM(&data->old_list,
473 i));
480 void
481 window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
483 struct window_choose_mode_data *data = wp->modedata;
484 struct screen *s = &data->screen;
485 struct screen_write_ctx ctx;
486 struct window_choose_mode_item *item;
487 size_t input_len;
488 u_int items, n;
489 int idx;
491 items = ARRAY_LENGTH(&data->list);
493 if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
494 switch (mode_key_lookup(&data->mdata, key, NULL)) {
495 case MODEKEYCHOICE_CANCEL:
496 data->input_type = WINDOW_CHOOSE_NORMAL;
497 window_choose_redraw_screen(wp);
498 break;
499 case MODEKEYCHOICE_CHOOSE:
500 n = strtonum(data->input_str, 0, INT_MAX, NULL);
501 if (n > items - 1) {
502 data->input_type = WINDOW_CHOOSE_NORMAL;
503 window_choose_redraw_screen(wp);
504 break;
506 item = &ARRAY_ITEM(&data->list, n);
507 window_choose_fire_callback(wp, item->wcd);
508 break;
509 case MODEKEYCHOICE_BACKSPACE:
510 input_len = strlen(data->input_str);
511 if (input_len > 0)
512 data->input_str[input_len - 1] = '\0';
513 window_choose_redraw_screen(wp);
514 break;
515 default:
516 if (key < '0' || key > '9')
517 break;
518 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
519 "Goto Item", wp, key);
520 break;
522 return;
525 switch (mode_key_lookup(&data->mdata, key, NULL)) {
526 case MODEKEYCHOICE_CANCEL:
527 window_choose_fire_callback(wp, NULL);
528 break;
529 case MODEKEYCHOICE_CHOOSE:
530 item = &ARRAY_ITEM(&data->list, data->selected);
531 window_choose_fire_callback(wp, item->wcd);
532 break;
533 case MODEKEYCHOICE_TREE_TOGGLE:
534 item = &ARRAY_ITEM(&data->list, data->selected);
535 if (item->state & TREE_EXPANDED)
536 window_choose_collapse(wp, item->wcd->tree_session);
537 else {
538 window_choose_expand(wp, item->wcd->tree_session,
539 data->selected);
541 window_choose_redraw_screen(wp);
542 break;
543 case MODEKEYCHOICE_TREE_COLLAPSE:
544 item = &ARRAY_ITEM(&data->list, data->selected);
545 if (item->state & TREE_EXPANDED) {
546 window_choose_collapse(wp, item->wcd->tree_session);
547 window_choose_redraw_screen(wp);
549 break;
550 case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
551 window_choose_collapse_all(wp);
552 break;
553 case MODEKEYCHOICE_TREE_EXPAND:
554 item = &ARRAY_ITEM(&data->list, data->selected);
555 if (!(item->state & TREE_EXPANDED)) {
556 window_choose_expand(wp, item->wcd->tree_session,
557 data->selected);
558 window_choose_redraw_screen(wp);
560 break;
561 case MODEKEYCHOICE_TREE_EXPAND_ALL:
562 window_choose_expand_all(wp);
563 break;
564 case MODEKEYCHOICE_UP:
565 if (items == 0)
566 break;
567 if (data->selected == 0) {
568 data->selected = items - 1;
569 if (data->selected > screen_size_y(s) - 1)
570 data->top = items - screen_size_y(s);
571 window_choose_redraw_screen(wp);
572 break;
574 data->selected--;
575 if (data->selected < data->top)
576 window_choose_scroll_up(wp);
577 else {
578 screen_write_start(&ctx, wp, NULL);
579 window_choose_write_line(
580 wp, &ctx, data->selected - data->top);
581 window_choose_write_line(
582 wp, &ctx, data->selected + 1 - data->top);
583 screen_write_stop(&ctx);
585 break;
586 case MODEKEYCHOICE_DOWN:
587 if (items == 0)
588 break;
589 if (data->selected == items - 1) {
590 data->selected = 0;
591 data->top = 0;
592 window_choose_redraw_screen(wp);
593 break;
595 data->selected++;
597 if (data->selected < data->top + screen_size_y(s)) {
598 screen_write_start(&ctx, wp, NULL);
599 window_choose_write_line(
600 wp, &ctx, data->selected - data->top);
601 window_choose_write_line(
602 wp, &ctx, data->selected - 1 - data->top);
603 screen_write_stop(&ctx);
604 } else
605 window_choose_scroll_down(wp);
606 break;
607 case MODEKEYCHOICE_SCROLLUP:
608 if (items == 0 || data->top == 0)
609 break;
610 if (data->selected == data->top + screen_size_y(s) - 1) {
611 data->selected--;
612 window_choose_scroll_up(wp);
613 screen_write_start(&ctx, wp, NULL);
614 window_choose_write_line(
615 wp, &ctx, screen_size_y(s) - 1);
616 screen_write_stop(&ctx);
617 } else
618 window_choose_scroll_up(wp);
619 break;
620 case MODEKEYCHOICE_SCROLLDOWN:
621 if (items == 0 ||
622 data->top + screen_size_y(&data->screen) >= items)
623 break;
624 if (data->selected == data->top) {
625 data->selected++;
626 window_choose_scroll_down(wp);
627 screen_write_start(&ctx, wp, NULL);
628 window_choose_write_line(wp, &ctx, 0);
629 screen_write_stop(&ctx);
630 } else
631 window_choose_scroll_down(wp);
632 break;
633 case MODEKEYCHOICE_PAGEUP:
634 if (data->selected < screen_size_y(s)) {
635 data->selected = 0;
636 data->top = 0;
637 } else {
638 data->selected -= screen_size_y(s);
639 if (data->top < screen_size_y(s))
640 data->top = 0;
641 else
642 data->top -= screen_size_y(s);
644 window_choose_redraw_screen(wp);
645 break;
646 case MODEKEYCHOICE_PAGEDOWN:
647 data->selected += screen_size_y(s);
648 if (data->selected > items - 1)
649 data->selected = items - 1;
650 data->top += screen_size_y(s);
651 if (screen_size_y(s) < items) {
652 if (data->top + screen_size_y(s) > items)
653 data->top = items - screen_size_y(s);
654 } else
655 data->top = 0;
656 if (data->selected < data->top)
657 data->top = data->selected;
658 window_choose_redraw_screen(wp);
659 break;
660 case MODEKEYCHOICE_BACKSPACE:
661 input_len = strlen(data->input_str);
662 if (input_len > 0)
663 data->input_str[input_len - 1] = '\0';
664 window_choose_redraw_screen(wp);
665 break;
666 case MODEKEYCHOICE_STARTNUMBERPREFIX:
667 key &= KEYC_MASK_KEY;
668 if (key < '0' || key > '9')
669 break;
670 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
671 "Goto Item", wp, key);
672 break;
673 default:
674 idx = window_choose_index_key(data, key);
675 if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
676 break;
677 data->selected = idx;
679 item = &ARRAY_ITEM(&data->list, data->selected);
680 window_choose_fire_callback(wp, item->wcd);
681 break;
685 void
686 window_choose_mouse(
687 struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
689 struct window_choose_mode_data *data = wp->modedata;
690 struct screen *s = &data->screen;
691 struct window_choose_mode_item *item;
692 u_int idx;
694 if (~m->event & MOUSE_EVENT_CLICK)
695 return;
696 if (m->x >= screen_size_x(s))
697 return;
698 if (m->y >= screen_size_y(s))
699 return;
701 idx = data->top + m->y;
702 if (idx >= ARRAY_LENGTH(&data->list))
703 return;
704 data->selected = idx;
706 item = &ARRAY_ITEM(&data->list, data->selected);
707 window_choose_fire_callback(wp, item->wcd);
710 void
711 window_choose_write_line(
712 struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
714 struct window_choose_mode_data *data = wp->modedata;
715 struct window_choose_mode_item *item;
716 struct options *oo = &wp->window->options;
717 struct screen *s = &data->screen;
718 struct grid_cell gc;
719 size_t last, xoff = 0;
720 char hdr[32], label[32];
721 int utf8flag, key;
723 if (data->callbackfn == NULL)
724 fatalx("called before callback assigned");
726 last = screen_size_y(s) - 1;
727 utf8flag = options_get_number(&wp->window->options, "utf8");
728 memcpy(&gc, &grid_default_cell, sizeof gc);
729 if (data->selected == data->top + py)
730 window_mode_attrs(&gc, oo);
732 screen_write_cursormove(ctx, 0, py);
733 if (data->top + py < ARRAY_LENGTH(&data->list)) {
734 item = &ARRAY_ITEM(&data->list, data->top + py);
735 if (item->wcd->wl != NULL &&
736 item->wcd->wl->flags & WINLINK_ALERTFLAGS)
737 gc.attr |= GRID_ATTR_BRIGHT;
739 key = window_choose_key_index(data, data->top + py);
740 if (key != -1)
741 xsnprintf (label, sizeof label, "(%c)", key);
742 else
743 xsnprintf (label, sizeof label, "(%d)", item->pos);
744 screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
745 "%*s %s %s", data->width + 2, label,
747 * Add indication to tree if necessary about whether it's
748 * expanded or not.
750 (item->wcd->type & TREE_SESSION) ?
751 (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
753 while (s->cx < screen_size_x(s) - 1)
754 screen_write_putc(ctx, &gc, ' ');
756 if (data->input_type != WINDOW_CHOOSE_NORMAL) {
757 window_mode_attrs(&gc, oo);
759 xoff = xsnprintf(hdr, sizeof hdr,
760 "%s: %s", data->input_prompt, data->input_str);
761 screen_write_cursormove(ctx, 0, last);
762 screen_write_puts(ctx, &gc, "%s", hdr);
763 screen_write_cursormove(ctx, xoff, py);
764 memcpy(&gc, &grid_default_cell, sizeof gc);
770 window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
772 static const char keys[] = "0123456789"
773 "abcdefghijklmnopqrstuvwxyz"
774 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
775 const char *ptr;
776 int mkey;
778 for (ptr = keys; *ptr != '\0'; ptr++) {
779 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
780 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
781 continue;
782 if (idx-- == 0)
783 return (*ptr);
785 return (-1);
789 window_choose_index_key(struct window_choose_mode_data *data, int key)
791 static const char keys[] = "0123456789"
792 "abcdefghijklmnopqrstuvwxyz"
793 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
794 const char *ptr;
795 int mkey;
796 u_int idx = 0;
798 for (ptr = keys; *ptr != '\0'; ptr++) {
799 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
800 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
801 continue;
802 if (key == *ptr)
803 return (idx);
804 idx++;
806 return (-1);
809 void
810 window_choose_redraw_screen(struct window_pane *wp)
812 struct window_choose_mode_data *data = wp->modedata;
813 struct screen *s = &data->screen;
814 struct screen_write_ctx ctx;
815 u_int i;
817 screen_write_start(&ctx, wp, NULL);
818 for (i = 0; i < screen_size_y(s); i++)
819 window_choose_write_line(wp, &ctx, i);
820 screen_write_stop(&ctx);
823 void
824 window_choose_scroll_up(struct window_pane *wp)
826 struct window_choose_mode_data *data = wp->modedata;
827 struct screen_write_ctx ctx;
829 if (data->top == 0)
830 return;
831 data->top--;
833 screen_write_start(&ctx, wp, NULL);
834 screen_write_cursormove(&ctx, 0, 0);
835 screen_write_insertline(&ctx, 1);
836 window_choose_write_line(wp, &ctx, 0);
837 if (screen_size_y(&data->screen) > 1)
838 window_choose_write_line(wp, &ctx, 1);
839 screen_write_stop(&ctx);
842 void
843 window_choose_scroll_down(struct window_pane *wp)
845 struct window_choose_mode_data *data = wp->modedata;
846 struct screen *s = &data->screen;
847 struct screen_write_ctx ctx;
849 if (data->top >= ARRAY_LENGTH(&data->list))
850 return;
851 data->top++;
853 screen_write_start(&ctx, wp, NULL);
854 screen_write_cursormove(&ctx, 0, 0);
855 screen_write_deleteline(&ctx, 1);
856 window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
857 if (screen_size_y(&data->screen) > 1)
858 window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
859 screen_write_stop(&ctx);
862 struct window_choose_data *
863 window_choose_add_session(struct window_pane *wp, struct client *c,
864 struct session *s, const char *template, const char *action, u_int idx)
866 struct window_choose_data *wcd;
868 wcd = window_choose_data_create(TREE_SESSION, c, c->session);
869 wcd->idx = s->idx;
871 wcd->tree_session = s;
872 wcd->tree_session->references++;
874 wcd->ft_template = xstrdup(template);
875 format_add(wcd->ft, "line", "%u", idx);
876 format_session(wcd->ft, s);
878 wcd->command = cmd_template_replace(action, s->name, 1);
880 window_choose_add(wp, wcd);
882 return (wcd);
885 struct window_choose_data *
886 window_choose_add_item(struct window_pane *wp, struct client *c,
887 struct winlink *wl, const char *template, const char *action, u_int idx)
889 struct window_choose_data *wcd;
890 char *expanded;
892 wcd = window_choose_data_create(TREE_OTHER, c, c->session);
893 wcd->idx = wl->idx;
895 wcd->ft_template = xstrdup(template);
896 format_add(wcd->ft, "line", "%u", idx);
897 format_session(wcd->ft, wcd->start_session);
898 format_winlink(wcd->ft, wcd->start_session, wl);
899 format_window_pane(wcd->ft, wl->window->active);
902 * Interpolate action here, since the data we pass back is the expanded
903 * template itself.
905 xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
906 wcd->command = cmd_template_replace(action, expanded, 1);
907 free(expanded);
909 window_choose_add(wp, wcd);
911 return (wcd);
915 struct window_choose_data *
916 window_choose_add_window(struct window_pane *wp, struct client *c,
917 struct session *s, struct winlink *wl, const char *template,
918 const char *action, u_int idx)
920 struct window_choose_data *wcd;
921 char *expanded;
923 wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
924 wcd->idx = wl->idx;
926 wcd->wl = wl;
928 wcd->tree_session = s;
929 wcd->tree_session->references++;
931 wcd->ft_template = xstrdup(template);
932 format_add(wcd->ft, "line", "%u", idx);
933 format_session(wcd->ft, s);
934 format_winlink(wcd->ft, s, wl);
935 format_window_pane(wcd->ft, wl->window->active);
937 xasprintf(&expanded, "%s:%d", s->name, wl->idx);
938 wcd->command = cmd_template_replace(action, expanded, 1);
939 free(expanded);
941 window_choose_add(wp, wcd);
943 return (wcd);