Do not leak command in formats, from Romain Francoise.
[tmux-openbsd.git] / window-choose.c
blob2671c78160407b7f0e655c47ce0e70bcd2b605c0
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_list *cmdlist;
204 char *cause;
207 * The command template will have already been replaced. But if it's
208 * NULL, bail here.
210 if (cdata->command == NULL)
211 return;
213 if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) {
214 if (cause != NULL) {
215 *cause = toupper((u_char) *cause);
216 status_message_set(cdata->start_client, "%s", cause);
217 free(cause);
219 return;
222 cmdq_run(cdata->start_client->cmdq, cmdlist);
223 cmd_list_free(cmdlist);
226 void
227 window_choose_default_callback(struct window_choose_data *wcd)
229 if (wcd == NULL)
230 return;
231 if (wcd->start_client->flags & CLIENT_DEAD)
232 return;
234 window_choose_data_run(wcd);
237 void
238 window_choose_free(struct window_pane *wp)
240 if (wp->modedata != NULL)
241 window_choose_free1(wp->modedata);
244 void
245 window_choose_free1(struct window_choose_mode_data *data)
247 struct window_choose_mode_item *item;
248 u_int i;
250 if (data == NULL)
251 return;
253 for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
254 item = &ARRAY_ITEM(&data->old_list, i);
255 window_choose_data_free(item->wcd);
256 free(item->name);
258 ARRAY_FREE(&data->list);
259 ARRAY_FREE(&data->old_list);
260 free(data->input_str);
262 screen_free(&data->screen);
263 free(data);
266 void
267 window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
269 struct window_choose_mode_data *data = wp->modedata;
270 struct screen *s = &data->screen;
272 data->top = 0;
273 if (data->selected > sy - 1)
274 data->top = data->selected - (sy - 1);
276 screen_resize(s, sx, sy, 0);
277 window_choose_redraw_screen(wp);
280 void
281 window_choose_fire_callback(
282 struct window_pane *wp, struct window_choose_data *wcd)
284 struct window_choose_mode_data *data = wp->modedata;
286 wp->modedata = NULL;
287 window_pane_reset_mode(wp);
289 data->callbackfn(wcd);
291 window_choose_free1(data);
294 void
295 window_choose_prompt_input(enum window_choose_input_type input_type,
296 const char *prompt, struct window_pane *wp, int key)
298 struct window_choose_mode_data *data = wp->modedata;
299 size_t input_len;
301 data->input_type = input_type;
302 data->input_prompt = prompt;
303 input_len = strlen(data->input_str) + 2;
305 data->input_str = xrealloc(data->input_str, 1, input_len);
306 data->input_str[input_len - 2] = key;
307 data->input_str[input_len - 1] = '\0';
309 window_choose_redraw_screen(wp);
312 void
313 window_choose_collapse(struct window_pane *wp, struct session *s)
315 struct window_choose_mode_data *data = wp->modedata;
316 struct window_choose_mode_item *item, *chosen;
317 struct window_choose_data *wcd;
318 u_int i, pos;
320 ARRAY_DECL(, struct window_choose_mode_item) list_copy;
321 ARRAY_INIT(&list_copy);
323 pos = data->selected;
325 chosen = &ARRAY_ITEM(&data->list, pos);
326 chosen->state &= ~TREE_EXPANDED;
329 * Trying to mangle the &data->list in-place has lots of problems, so
330 * assign the actual result we want to render and copy the new one over
331 * the top of it.
333 for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
335 item = &ARRAY_ITEM(&data->list, i);
336 wcd = item->wcd;
338 if (s == wcd->tree_session) {
339 /* We only show the session when collapsed. */
340 if (wcd->type & TREE_SESSION) {
341 item->state &= ~TREE_EXPANDED;
343 ARRAY_ADD(&list_copy,
344 ARRAY_ITEM(&data->list, i));
346 * Update the selection to this session item so
347 * we don't end up highlighting a non-existent
348 * item.
350 data->selected = i;
352 } else
353 ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
356 if (!ARRAY_EMPTY(&list_copy)) {
357 ARRAY_FREE(&data->list);
358 ARRAY_CONCAT(&data->list, &list_copy);
359 ARRAY_FREE(&list_copy);
363 void
364 window_choose_collapse_all(struct window_pane *wp)
366 struct window_choose_mode_data *data = wp->modedata;
367 struct window_choose_mode_item *item;
368 struct session *s, *chosen;
369 u_int i;
371 chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
373 RB_FOREACH(s, sessions, &sessions)
374 window_choose_collapse(wp, s);
376 /* Reset the selection back to the starting session. */
377 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
378 item = &ARRAY_ITEM(&data->list, i);
380 if (chosen != item->wcd->tree_session)
381 continue;
383 if (item->wcd->type & TREE_SESSION)
384 data->selected = i;
386 window_choose_redraw_screen(wp);
389 void
390 window_choose_expand_all(struct window_pane *wp)
392 struct window_choose_mode_data *data = wp->modedata;
393 struct window_choose_mode_item *item;
394 struct session *s;
395 u_int i;
397 RB_FOREACH(s, sessions, &sessions) {
398 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
399 item = &ARRAY_ITEM(&data->list, i);
401 if (s != item->wcd->tree_session)
402 continue;
404 if (item->wcd->type & TREE_SESSION)
405 window_choose_expand(wp, s, i);
409 window_choose_redraw_screen(wp);
412 void
413 window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
415 struct window_choose_mode_data *data = wp->modedata;
416 struct window_choose_mode_item *item, *chosen;
417 struct window_choose_data *wcd;
418 u_int i, items;
420 chosen = &ARRAY_ITEM(&data->list, pos);
421 items = ARRAY_LENGTH(&data->old_list) - 1;
423 /* It's not possible to expand anything other than sessions. */
424 if (!(chosen->wcd->type & TREE_SESSION))
425 return;
427 /* Don't re-expand a session which is already expanded. */
428 if (chosen->state & TREE_EXPANDED)
429 return;
431 /* Mark the session entry as expanded. */
432 chosen->state |= TREE_EXPANDED;
435 * Go back through the original list of all sessions and windows, and
436 * pull out the windows where the session matches the selection chosen
437 * to expand.
439 for (i = items; i > 0; i--) {
440 item = &ARRAY_ITEM(&data->old_list, i);
441 item->state |= TREE_EXPANDED;
442 wcd = item->wcd;
444 if (s == wcd->tree_session) {
446 * Since the session is already displayed, we only care
447 * to add back in window for it.
449 if (wcd->type & TREE_WINDOW) {
451 * If the insertion point for adding the
452 * windows to the session falls inside the
453 * range of the list, then we insert these
454 * entries in order *AFTER* the selected
455 * session.
457 if (pos < i ) {
458 ARRAY_INSERT(&data->list,
459 pos + 1,
460 ARRAY_ITEM(&data->old_list,
461 i));
462 } else {
463 /* Ran out of room, add to the end. */
464 ARRAY_ADD(&data->list,
465 ARRAY_ITEM(&data->old_list,
466 i));
473 void
474 window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
476 struct window_choose_mode_data *data = wp->modedata;
477 struct screen *s = &data->screen;
478 struct screen_write_ctx ctx;
479 struct window_choose_mode_item *item;
480 size_t input_len;
481 u_int items, n;
482 int idx;
484 items = ARRAY_LENGTH(&data->list);
486 if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
487 switch (mode_key_lookup(&data->mdata, key, NULL)) {
488 case MODEKEYCHOICE_CANCEL:
489 data->input_type = WINDOW_CHOOSE_NORMAL;
490 window_choose_redraw_screen(wp);
491 break;
492 case MODEKEYCHOICE_CHOOSE:
493 n = strtonum(data->input_str, 0, INT_MAX, NULL);
494 if (n > items - 1) {
495 data->input_type = WINDOW_CHOOSE_NORMAL;
496 window_choose_redraw_screen(wp);
497 break;
499 item = &ARRAY_ITEM(&data->list, n);
500 window_choose_fire_callback(wp, item->wcd);
501 break;
502 case MODEKEYCHOICE_BACKSPACE:
503 input_len = strlen(data->input_str);
504 if (input_len > 0)
505 data->input_str[input_len - 1] = '\0';
506 window_choose_redraw_screen(wp);
507 break;
508 default:
509 if (key < '0' || key > '9')
510 break;
511 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
512 "Goto Item", wp, key);
513 break;
515 return;
518 switch (mode_key_lookup(&data->mdata, key, NULL)) {
519 case MODEKEYCHOICE_CANCEL:
520 window_choose_fire_callback(wp, NULL);
521 break;
522 case MODEKEYCHOICE_CHOOSE:
523 item = &ARRAY_ITEM(&data->list, data->selected);
524 window_choose_fire_callback(wp, item->wcd);
525 break;
526 case MODEKEYCHOICE_TREE_TOGGLE:
527 item = &ARRAY_ITEM(&data->list, data->selected);
528 if (item->state & TREE_EXPANDED)
529 window_choose_collapse(wp, item->wcd->tree_session);
530 else {
531 window_choose_expand(wp, item->wcd->tree_session,
532 data->selected);
534 window_choose_redraw_screen(wp);
535 break;
536 case MODEKEYCHOICE_TREE_COLLAPSE:
537 item = &ARRAY_ITEM(&data->list, data->selected);
538 if (item->state & TREE_EXPANDED) {
539 window_choose_collapse(wp, item->wcd->tree_session);
540 window_choose_redraw_screen(wp);
542 break;
543 case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
544 window_choose_collapse_all(wp);
545 break;
546 case MODEKEYCHOICE_TREE_EXPAND:
547 item = &ARRAY_ITEM(&data->list, data->selected);
548 if (!(item->state & TREE_EXPANDED)) {
549 window_choose_expand(wp, item->wcd->tree_session,
550 data->selected);
551 window_choose_redraw_screen(wp);
553 break;
554 case MODEKEYCHOICE_TREE_EXPAND_ALL:
555 window_choose_expand_all(wp);
556 break;
557 case MODEKEYCHOICE_UP:
558 if (items == 0)
559 break;
560 if (data->selected == 0) {
561 data->selected = items - 1;
562 if (data->selected > screen_size_y(s) - 1)
563 data->top = items - screen_size_y(s);
564 window_choose_redraw_screen(wp);
565 break;
567 data->selected--;
568 if (data->selected < data->top)
569 window_choose_scroll_up(wp);
570 else {
571 screen_write_start(&ctx, wp, NULL);
572 window_choose_write_line(
573 wp, &ctx, data->selected - data->top);
574 window_choose_write_line(
575 wp, &ctx, data->selected + 1 - data->top);
576 screen_write_stop(&ctx);
578 break;
579 case MODEKEYCHOICE_DOWN:
580 if (items == 0)
581 break;
582 if (data->selected == items - 1) {
583 data->selected = 0;
584 data->top = 0;
585 window_choose_redraw_screen(wp);
586 break;
588 data->selected++;
590 if (data->selected < data->top + screen_size_y(s)) {
591 screen_write_start(&ctx, wp, NULL);
592 window_choose_write_line(
593 wp, &ctx, data->selected - data->top);
594 window_choose_write_line(
595 wp, &ctx, data->selected - 1 - data->top);
596 screen_write_stop(&ctx);
597 } else
598 window_choose_scroll_down(wp);
599 break;
600 case MODEKEYCHOICE_SCROLLUP:
601 if (items == 0 || data->top == 0)
602 break;
603 if (data->selected == data->top + screen_size_y(s) - 1) {
604 data->selected--;
605 window_choose_scroll_up(wp);
606 screen_write_start(&ctx, wp, NULL);
607 window_choose_write_line(
608 wp, &ctx, screen_size_y(s) - 1);
609 screen_write_stop(&ctx);
610 } else
611 window_choose_scroll_up(wp);
612 break;
613 case MODEKEYCHOICE_SCROLLDOWN:
614 if (items == 0 ||
615 data->top + screen_size_y(&data->screen) >= items)
616 break;
617 if (data->selected == data->top) {
618 data->selected++;
619 window_choose_scroll_down(wp);
620 screen_write_start(&ctx, wp, NULL);
621 window_choose_write_line(wp, &ctx, 0);
622 screen_write_stop(&ctx);
623 } else
624 window_choose_scroll_down(wp);
625 break;
626 case MODEKEYCHOICE_PAGEUP:
627 if (data->selected < screen_size_y(s)) {
628 data->selected = 0;
629 data->top = 0;
630 } else {
631 data->selected -= screen_size_y(s);
632 if (data->top < screen_size_y(s))
633 data->top = 0;
634 else
635 data->top -= screen_size_y(s);
637 window_choose_redraw_screen(wp);
638 break;
639 case MODEKEYCHOICE_PAGEDOWN:
640 data->selected += screen_size_y(s);
641 if (data->selected > items - 1)
642 data->selected = items - 1;
643 data->top += screen_size_y(s);
644 if (screen_size_y(s) < items) {
645 if (data->top + screen_size_y(s) > items)
646 data->top = items - screen_size_y(s);
647 } else
648 data->top = 0;
649 if (data->selected < data->top)
650 data->top = data->selected;
651 window_choose_redraw_screen(wp);
652 break;
653 case MODEKEYCHOICE_BACKSPACE:
654 input_len = strlen(data->input_str);
655 if (input_len > 0)
656 data->input_str[input_len - 1] = '\0';
657 window_choose_redraw_screen(wp);
658 break;
659 case MODEKEYCHOICE_STARTNUMBERPREFIX:
660 key &= KEYC_MASK_KEY;
661 if (key < '0' || key > '9')
662 break;
663 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
664 "Goto Item", wp, key);
665 break;
666 default:
667 idx = window_choose_index_key(data, key);
668 if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
669 break;
670 data->selected = idx;
672 item = &ARRAY_ITEM(&data->list, data->selected);
673 window_choose_fire_callback(wp, item->wcd);
674 break;
678 void
679 window_choose_mouse(
680 struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
682 struct window_choose_mode_data *data = wp->modedata;
683 struct screen *s = &data->screen;
684 struct window_choose_mode_item *item;
685 u_int idx;
687 if (~m->event & MOUSE_EVENT_CLICK)
688 return;
689 if (m->x >= screen_size_x(s))
690 return;
691 if (m->y >= screen_size_y(s))
692 return;
694 idx = data->top + m->y;
695 if (idx >= ARRAY_LENGTH(&data->list))
696 return;
697 data->selected = idx;
699 item = &ARRAY_ITEM(&data->list, data->selected);
700 window_choose_fire_callback(wp, item->wcd);
703 void
704 window_choose_write_line(
705 struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
707 struct window_choose_mode_data *data = wp->modedata;
708 struct window_choose_mode_item *item;
709 struct options *oo = &wp->window->options;
710 struct screen *s = &data->screen;
711 struct grid_cell gc;
712 size_t last, xoff = 0;
713 char hdr[32], label[32];
714 int utf8flag, key;
716 if (data->callbackfn == NULL)
717 fatalx("called before callback assigned");
719 last = screen_size_y(s) - 1;
720 utf8flag = options_get_number(&wp->window->options, "utf8");
721 memcpy(&gc, &grid_default_cell, sizeof gc);
722 if (data->selected == data->top + py)
723 window_mode_attrs(&gc, oo);
725 screen_write_cursormove(ctx, 0, py);
726 if (data->top + py < ARRAY_LENGTH(&data->list)) {
727 item = &ARRAY_ITEM(&data->list, data->top + py);
728 if (item->wcd->wl != NULL &&
729 item->wcd->wl->flags & WINLINK_ALERTFLAGS)
730 gc.attr |= GRID_ATTR_BRIGHT;
732 key = window_choose_key_index(data, data->top + py);
733 if (key != -1)
734 xsnprintf (label, sizeof label, "(%c)", key);
735 else
736 xsnprintf (label, sizeof label, "(%d)", item->pos);
737 screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
738 "%*s %s %s", data->width + 2, label,
740 * Add indication to tree if necessary about whether it's
741 * expanded or not.
743 (item->wcd->type & TREE_SESSION) ?
744 (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
746 while (s->cx < screen_size_x(s) - 1)
747 screen_write_putc(ctx, &gc, ' ');
749 if (data->input_type != WINDOW_CHOOSE_NORMAL) {
750 window_mode_attrs(&gc, oo);
752 xoff = xsnprintf(hdr, sizeof hdr,
753 "%s: %s", data->input_prompt, data->input_str);
754 screen_write_cursormove(ctx, 0, last);
755 screen_write_puts(ctx, &gc, "%s", hdr);
756 screen_write_cursormove(ctx, xoff, py);
757 memcpy(&gc, &grid_default_cell, sizeof gc);
763 window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
765 static const char keys[] = "0123456789"
766 "abcdefghijklmnopqrstuvwxyz"
767 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
768 const char *ptr;
769 int mkey;
771 for (ptr = keys; *ptr != '\0'; ptr++) {
772 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
773 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
774 continue;
775 if (idx-- == 0)
776 return (*ptr);
778 return (-1);
782 window_choose_index_key(struct window_choose_mode_data *data, int key)
784 static const char keys[] = "0123456789"
785 "abcdefghijklmnopqrstuvwxyz"
786 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
787 const char *ptr;
788 int mkey;
789 u_int idx = 0;
791 for (ptr = keys; *ptr != '\0'; ptr++) {
792 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
793 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
794 continue;
795 if (key == *ptr)
796 return (idx);
797 idx++;
799 return (-1);
802 void
803 window_choose_redraw_screen(struct window_pane *wp)
805 struct window_choose_mode_data *data = wp->modedata;
806 struct screen *s = &data->screen;
807 struct screen_write_ctx ctx;
808 u_int i;
810 screen_write_start(&ctx, wp, NULL);
811 for (i = 0; i < screen_size_y(s); i++)
812 window_choose_write_line(wp, &ctx, i);
813 screen_write_stop(&ctx);
816 void
817 window_choose_scroll_up(struct window_pane *wp)
819 struct window_choose_mode_data *data = wp->modedata;
820 struct screen_write_ctx ctx;
822 if (data->top == 0)
823 return;
824 data->top--;
826 screen_write_start(&ctx, wp, NULL);
827 screen_write_cursormove(&ctx, 0, 0);
828 screen_write_insertline(&ctx, 1);
829 window_choose_write_line(wp, &ctx, 0);
830 if (screen_size_y(&data->screen) > 1)
831 window_choose_write_line(wp, &ctx, 1);
832 screen_write_stop(&ctx);
835 void
836 window_choose_scroll_down(struct window_pane *wp)
838 struct window_choose_mode_data *data = wp->modedata;
839 struct screen *s = &data->screen;
840 struct screen_write_ctx ctx;
842 if (data->top >= ARRAY_LENGTH(&data->list))
843 return;
844 data->top++;
846 screen_write_start(&ctx, wp, NULL);
847 screen_write_cursormove(&ctx, 0, 0);
848 screen_write_deleteline(&ctx, 1);
849 window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
850 if (screen_size_y(&data->screen) > 1)
851 window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
852 screen_write_stop(&ctx);
855 struct window_choose_data *
856 window_choose_add_session(struct window_pane *wp, struct client *c,
857 struct session *s, const char *template, const char *action, u_int idx)
859 struct window_choose_data *wcd;
861 wcd = window_choose_data_create(TREE_SESSION, c, c->session);
862 wcd->idx = s->idx;
864 wcd->tree_session = s;
865 wcd->tree_session->references++;
867 wcd->ft_template = xstrdup(template);
868 format_add(wcd->ft, "line", "%u", idx);
869 format_session(wcd->ft, s);
871 wcd->command = cmd_template_replace(action, s->name, 1);
873 window_choose_add(wp, wcd);
875 return (wcd);
878 struct window_choose_data *
879 window_choose_add_item(struct window_pane *wp, struct client *c,
880 struct winlink *wl, const char *template, const char *action, u_int idx)
882 struct window_choose_data *wcd;
883 char *expanded;
885 wcd = window_choose_data_create(TREE_OTHER, c, c->session);
886 wcd->idx = wl->idx;
888 wcd->ft_template = xstrdup(template);
889 format_add(wcd->ft, "line", "%u", idx);
890 format_session(wcd->ft, wcd->start_session);
891 format_winlink(wcd->ft, wcd->start_session, wl);
892 format_window_pane(wcd->ft, wl->window->active);
895 * Interpolate action here, since the data we pass back is the expanded
896 * template itself.
898 xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
899 wcd->command = cmd_template_replace(action, expanded, 1);
900 free(expanded);
902 window_choose_add(wp, wcd);
904 return (wcd);
908 struct window_choose_data *
909 window_choose_add_window(struct window_pane *wp, struct client *c,
910 struct session *s, struct winlink *wl, const char *template,
911 const char *action, u_int idx)
913 struct window_choose_data *wcd;
914 char *expanded;
916 wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
917 wcd->idx = wl->idx;
919 wcd->wl = wl;
921 wcd->tree_session = s;
922 wcd->tree_session->references++;
924 wcd->ft_template = xstrdup(template);
925 format_add(wcd->ft, "line", "%u", idx);
926 format_session(wcd->ft, s);
927 format_winlink(wcd->ft, s, wl);
928 format_window_pane(wcd->ft, wl->window->active);
930 xasprintf(&expanded, "%s:%d", s->name, wl->idx);
931 wcd->command = cmd_template_replace(action, expanded, 1);
932 free(expanded);
934 window_choose_add(wp, wcd);
936 return (wcd);