Focus events can cause trouble if left on and they can't be turned off
[tmux-openbsd.git] / window-choose.c
blob3877360555f8b27f53d88c540f9e75efa4fd028f
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);
48 enum window_choose_input_type {
49 WINDOW_CHOOSE_NORMAL = -1,
50 WINDOW_CHOOSE_GOTO_ITEM,
53 const struct window_mode window_choose_mode = {
54 window_choose_init,
55 window_choose_free,
56 window_choose_resize,
57 window_choose_key,
58 window_choose_mouse,
59 NULL,
62 struct window_choose_mode_data {
63 struct screen screen;
65 struct mode_key_data mdata;
67 ARRAY_DECL(, struct window_choose_mode_item) list;
68 ARRAY_DECL(, struct window_choose_mode_item) old_list;
69 int width;
70 u_int top;
71 u_int selected;
72 enum window_choose_input_type input_type;
73 const char *input_prompt;
74 char *input_str;
76 void (*callbackfn)(struct window_choose_data *);
79 void window_choose_free1(struct window_choose_mode_data *);
80 int window_choose_key_index(struct window_choose_mode_data *, u_int);
81 int window_choose_index_key(struct window_choose_mode_data *, int);
82 void window_choose_prompt_input(enum window_choose_input_type,
83 const char *, struct window_pane *, int);
85 void
86 window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
88 struct window_choose_mode_data *data = wp->modedata;
89 struct window_choose_mode_item *item;
90 char tmp[10];
92 ARRAY_EXPAND(&data->list, 1);
93 item = &ARRAY_LAST(&data->list);
95 item->name = format_expand(wcd->ft, wcd->ft_template);
96 item->wcd = wcd;
97 item->pos = ARRAY_LENGTH(&data->list) - 1;
98 item->state = 0;
100 data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos);
103 void
104 window_choose_set_current(struct window_pane *wp, u_int cur)
106 struct window_choose_mode_data *data = wp->modedata;
107 struct screen *s = &data->screen;
109 data->selected = cur;
110 if (data->selected > screen_size_y(s) - 1)
111 data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
113 window_choose_redraw_screen(wp);
116 void
117 window_choose_ready(struct window_pane *wp, u_int cur,
118 void (*callbackfn)(struct window_choose_data *))
120 struct window_choose_mode_data *data = wp->modedata;
122 data->callbackfn = callbackfn;
123 if (data->callbackfn == NULL)
124 data->callbackfn = window_choose_default_callback;
126 ARRAY_CONCAT(&data->old_list, &data->list);
128 window_choose_set_current(wp, cur);
129 window_choose_collapse_all(wp);
132 struct screen *
133 window_choose_init(struct window_pane *wp)
135 struct window_choose_mode_data *data;
136 struct screen *s;
137 int keys;
139 wp->modedata = data = xmalloc(sizeof *data);
141 data->callbackfn = NULL;
142 data->input_type = WINDOW_CHOOSE_NORMAL;
143 data->input_str = xstrdup("");
144 data->input_prompt = NULL;
146 ARRAY_INIT(&data->list);
147 ARRAY_INIT(&data->old_list);
148 data->top = 0;
150 s = &data->screen;
151 screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
152 s->mode &= ~MODE_CURSOR;
153 if (options_get_number(&wp->window->options, "mode-mouse"))
154 s->mode |= MODE_MOUSE_STANDARD;
156 keys = options_get_number(&wp->window->options, "mode-keys");
157 if (keys == MODEKEY_EMACS)
158 mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
159 else
160 mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
162 return (s);
165 struct window_choose_data *
166 window_choose_data_create(int type, struct client *c, struct session *s)
168 struct window_choose_data *wcd;
170 wcd = xmalloc(sizeof *wcd);
171 wcd->type = type;
173 wcd->ft = format_create();
174 wcd->ft_template = NULL;
176 wcd->command = NULL;
178 wcd->wl = NULL;
179 wcd->pane_id = -1;
180 wcd->idx = -1;
182 wcd->tree_session = NULL;
184 wcd->start_client = c;
185 wcd->start_client->references++;
186 wcd->start_session = s;
187 wcd->start_session->references++;
189 return (wcd);
192 void
193 window_choose_data_free(struct window_choose_data *wcd)
195 wcd->start_client->references--;
196 wcd->start_session->references--;
198 if (wcd->tree_session != NULL)
199 wcd->tree_session->references--;
201 free(wcd->ft_template);
202 format_free(wcd->ft);
204 free(wcd->command);
205 free(wcd);
208 void
209 window_choose_data_run(struct window_choose_data *cdata)
211 struct cmd_list *cmdlist;
212 char *cause;
215 * The command template will have already been replaced. But if it's
216 * NULL, bail here.
218 if (cdata->command == NULL)
219 return;
221 if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) {
222 if (cause != NULL) {
223 *cause = toupper((u_char) *cause);
224 status_message_set(cdata->start_client, "%s", cause);
225 free(cause);
227 return;
230 cmdq_run(cdata->start_client->cmdq, cmdlist);
231 cmd_list_free(cmdlist);
234 void
235 window_choose_default_callback(struct window_choose_data *wcd)
237 if (wcd == NULL)
238 return;
239 if (wcd->start_client->flags & CLIENT_DEAD)
240 return;
242 window_choose_data_run(wcd);
245 void
246 window_choose_free(struct window_pane *wp)
248 if (wp->modedata != NULL)
249 window_choose_free1(wp->modedata);
252 void
253 window_choose_free1(struct window_choose_mode_data *data)
255 struct window_choose_mode_item *item;
256 u_int i;
258 if (data == NULL)
259 return;
261 for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
262 item = &ARRAY_ITEM(&data->old_list, i);
263 window_choose_data_free(item->wcd);
264 free(item->name);
266 ARRAY_FREE(&data->list);
267 ARRAY_FREE(&data->old_list);
268 free(data->input_str);
270 screen_free(&data->screen);
271 free(data);
274 void
275 window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
277 struct window_choose_mode_data *data = wp->modedata;
278 struct screen *s = &data->screen;
280 data->top = 0;
281 if (data->selected > sy - 1)
282 data->top = data->selected - (sy - 1);
284 screen_resize(s, sx, sy, 0);
285 window_choose_redraw_screen(wp);
288 void
289 window_choose_fire_callback(
290 struct window_pane *wp, struct window_choose_data *wcd)
292 struct window_choose_mode_data *data = wp->modedata;
294 wp->modedata = NULL;
295 window_pane_reset_mode(wp);
297 data->callbackfn(wcd);
299 window_choose_free1(data);
302 void
303 window_choose_prompt_input(enum window_choose_input_type input_type,
304 const char *prompt, struct window_pane *wp, int key)
306 struct window_choose_mode_data *data = wp->modedata;
307 size_t input_len;
309 data->input_type = input_type;
310 data->input_prompt = prompt;
311 input_len = strlen(data->input_str) + 2;
313 data->input_str = xrealloc(data->input_str, 1, input_len);
314 data->input_str[input_len - 2] = key;
315 data->input_str[input_len - 1] = '\0';
317 window_choose_redraw_screen(wp);
320 void
321 window_choose_collapse(struct window_pane *wp, struct session *s)
323 struct window_choose_mode_data *data = wp->modedata;
324 struct window_choose_mode_item *item, *chosen;
325 struct window_choose_data *wcd;
326 u_int i, pos;
328 ARRAY_DECL(, struct window_choose_mode_item) list_copy;
329 ARRAY_INIT(&list_copy);
331 pos = data->selected;
333 chosen = &ARRAY_ITEM(&data->list, pos);
334 chosen->state &= ~TREE_EXPANDED;
337 * Trying to mangle the &data->list in-place has lots of problems, so
338 * assign the actual result we want to render and copy the new one over
339 * the top of it.
341 for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
343 item = &ARRAY_ITEM(&data->list, i);
344 wcd = item->wcd;
346 if (s == wcd->tree_session) {
347 /* We only show the session when collapsed. */
348 if (wcd->type & TREE_SESSION) {
349 item->state &= ~TREE_EXPANDED;
351 ARRAY_ADD(&list_copy,
352 ARRAY_ITEM(&data->list, i));
354 * Update the selection to this session item so
355 * we don't end up highlighting a non-existent
356 * item.
358 data->selected = i;
360 } else
361 ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
364 if (!ARRAY_EMPTY(&list_copy)) {
365 ARRAY_FREE(&data->list);
366 ARRAY_CONCAT(&data->list, &list_copy);
367 ARRAY_FREE(&list_copy);
371 void
372 window_choose_collapse_all(struct window_pane *wp)
374 struct window_choose_mode_data *data = wp->modedata;
375 struct window_choose_mode_item *item;
376 struct session *s, *chosen;
377 u_int i;
379 chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
381 RB_FOREACH(s, sessions, &sessions)
382 window_choose_collapse(wp, s);
384 /* Reset the selection back to the starting session. */
385 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
386 item = &ARRAY_ITEM(&data->list, i);
388 if (chosen != item->wcd->tree_session)
389 continue;
391 if (item->wcd->type & TREE_SESSION)
392 data->selected = i;
394 window_choose_redraw_screen(wp);
397 void
398 window_choose_expand_all(struct window_pane *wp)
400 struct window_choose_mode_data *data = wp->modedata;
401 struct window_choose_mode_item *item;
402 struct session *s;
403 u_int i;
405 RB_FOREACH(s, sessions, &sessions) {
406 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
407 item = &ARRAY_ITEM(&data->list, i);
409 if (s != item->wcd->tree_session)
410 continue;
412 if (item->wcd->type & TREE_SESSION)
413 window_choose_expand(wp, s, i);
417 window_choose_redraw_screen(wp);
420 void
421 window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
423 struct window_choose_mode_data *data = wp->modedata;
424 struct window_choose_mode_item *item, *chosen;
425 struct window_choose_data *wcd;
426 u_int i, items;
428 chosen = &ARRAY_ITEM(&data->list, pos);
429 items = ARRAY_LENGTH(&data->old_list) - 1;
431 /* It's not possible to expand anything other than sessions. */
432 if (!(chosen->wcd->type & TREE_SESSION))
433 return;
435 /* Don't re-expand a session which is already expanded. */
436 if (chosen->state & TREE_EXPANDED)
437 return;
439 /* Mark the session entry as expanded. */
440 chosen->state |= TREE_EXPANDED;
443 * Go back through the original list of all sessions and windows, and
444 * pull out the windows where the session matches the selection chosen
445 * to expand.
447 for (i = items; i > 0; i--) {
448 item = &ARRAY_ITEM(&data->old_list, i);
449 item->state |= TREE_EXPANDED;
450 wcd = item->wcd;
452 if (s == wcd->tree_session) {
454 * Since the session is already displayed, we only care
455 * to add back in window for it.
457 if (wcd->type & TREE_WINDOW) {
459 * If the insertion point for adding the
460 * windows to the session falls inside the
461 * range of the list, then we insert these
462 * entries in order *AFTER* the selected
463 * session.
465 if (pos < i ) {
466 ARRAY_INSERT(&data->list,
467 pos + 1,
468 ARRAY_ITEM(&data->old_list,
469 i));
470 } else {
471 /* Ran out of room, add to the end. */
472 ARRAY_ADD(&data->list,
473 ARRAY_ITEM(&data->old_list,
474 i));
481 void
482 window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
484 struct window_choose_mode_data *data = wp->modedata;
485 struct screen *s = &data->screen;
486 struct screen_write_ctx ctx;
487 struct window_choose_mode_item *item;
488 size_t input_len;
489 u_int items, n;
490 int idx;
492 items = ARRAY_LENGTH(&data->list);
494 if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
495 switch (mode_key_lookup(&data->mdata, key, NULL)) {
496 case MODEKEYCHOICE_CANCEL:
497 data->input_type = WINDOW_CHOOSE_NORMAL;
498 window_choose_redraw_screen(wp);
499 break;
500 case MODEKEYCHOICE_CHOOSE:
501 n = strtonum(data->input_str, 0, INT_MAX, NULL);
502 if (n > items - 1) {
503 data->input_type = WINDOW_CHOOSE_NORMAL;
504 window_choose_redraw_screen(wp);
505 break;
507 item = &ARRAY_ITEM(&data->list, n);
508 window_choose_fire_callback(wp, item->wcd);
509 break;
510 case MODEKEYCHOICE_BACKSPACE:
511 input_len = strlen(data->input_str);
512 if (input_len > 0)
513 data->input_str[input_len - 1] = '\0';
514 window_choose_redraw_screen(wp);
515 break;
516 default:
517 if (key < '0' || key > '9')
518 break;
519 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
520 "Goto Item", wp, key);
521 break;
523 return;
526 switch (mode_key_lookup(&data->mdata, key, NULL)) {
527 case MODEKEYCHOICE_CANCEL:
528 window_choose_fire_callback(wp, NULL);
529 break;
530 case MODEKEYCHOICE_CHOOSE:
531 item = &ARRAY_ITEM(&data->list, data->selected);
532 window_choose_fire_callback(wp, item->wcd);
533 break;
534 case MODEKEYCHOICE_TREE_TOGGLE:
535 item = &ARRAY_ITEM(&data->list, data->selected);
536 if (item->state & TREE_EXPANDED)
537 window_choose_collapse(wp, item->wcd->tree_session);
538 else {
539 window_choose_expand(wp, item->wcd->tree_session,
540 data->selected);
542 window_choose_redraw_screen(wp);
543 break;
544 case MODEKEYCHOICE_TREE_COLLAPSE:
545 item = &ARRAY_ITEM(&data->list, data->selected);
546 if (item->state & TREE_EXPANDED) {
547 window_choose_collapse(wp, item->wcd->tree_session);
548 window_choose_redraw_screen(wp);
550 break;
551 case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
552 window_choose_collapse_all(wp);
553 break;
554 case MODEKEYCHOICE_TREE_EXPAND:
555 item = &ARRAY_ITEM(&data->list, data->selected);
556 if (!(item->state & TREE_EXPANDED)) {
557 window_choose_expand(wp, item->wcd->tree_session,
558 data->selected);
559 window_choose_redraw_screen(wp);
561 break;
562 case MODEKEYCHOICE_TREE_EXPAND_ALL:
563 window_choose_expand_all(wp);
564 break;
565 case MODEKEYCHOICE_UP:
566 if (items == 0)
567 break;
568 if (data->selected == 0) {
569 data->selected = items - 1;
570 if (data->selected > screen_size_y(s) - 1)
571 data->top = items - screen_size_y(s);
572 window_choose_redraw_screen(wp);
573 break;
575 data->selected--;
576 if (data->selected < data->top)
577 window_choose_scroll_up(wp);
578 else {
579 screen_write_start(&ctx, wp, NULL);
580 window_choose_write_line(
581 wp, &ctx, data->selected - data->top);
582 window_choose_write_line(
583 wp, &ctx, data->selected + 1 - data->top);
584 screen_write_stop(&ctx);
586 break;
587 case MODEKEYCHOICE_DOWN:
588 if (items == 0)
589 break;
590 if (data->selected == items - 1) {
591 data->selected = 0;
592 data->top = 0;
593 window_choose_redraw_screen(wp);
594 break;
596 data->selected++;
598 if (data->selected < data->top + screen_size_y(s)) {
599 screen_write_start(&ctx, wp, NULL);
600 window_choose_write_line(
601 wp, &ctx, data->selected - data->top);
602 window_choose_write_line(
603 wp, &ctx, data->selected - 1 - data->top);
604 screen_write_stop(&ctx);
605 } else
606 window_choose_scroll_down(wp);
607 break;
608 case MODEKEYCHOICE_SCROLLUP:
609 if (items == 0 || data->top == 0)
610 break;
611 if (data->selected == data->top + screen_size_y(s) - 1) {
612 data->selected--;
613 window_choose_scroll_up(wp);
614 screen_write_start(&ctx, wp, NULL);
615 window_choose_write_line(
616 wp, &ctx, screen_size_y(s) - 1);
617 screen_write_stop(&ctx);
618 } else
619 window_choose_scroll_up(wp);
620 break;
621 case MODEKEYCHOICE_SCROLLDOWN:
622 if (items == 0 ||
623 data->top + screen_size_y(&data->screen) >= items)
624 break;
625 if (data->selected == data->top) {
626 data->selected++;
627 window_choose_scroll_down(wp);
628 screen_write_start(&ctx, wp, NULL);
629 window_choose_write_line(wp, &ctx, 0);
630 screen_write_stop(&ctx);
631 } else
632 window_choose_scroll_down(wp);
633 break;
634 case MODEKEYCHOICE_PAGEUP:
635 if (data->selected < screen_size_y(s)) {
636 data->selected = 0;
637 data->top = 0;
638 } else {
639 data->selected -= screen_size_y(s);
640 if (data->top < screen_size_y(s))
641 data->top = 0;
642 else
643 data->top -= screen_size_y(s);
645 window_choose_redraw_screen(wp);
646 break;
647 case MODEKEYCHOICE_PAGEDOWN:
648 data->selected += screen_size_y(s);
649 if (data->selected > items - 1)
650 data->selected = items - 1;
651 data->top += screen_size_y(s);
652 if (screen_size_y(s) < items) {
653 if (data->top + screen_size_y(s) > items)
654 data->top = items - screen_size_y(s);
655 } else
656 data->top = 0;
657 if (data->selected < data->top)
658 data->top = data->selected;
659 window_choose_redraw_screen(wp);
660 break;
661 case MODEKEYCHOICE_BACKSPACE:
662 input_len = strlen(data->input_str);
663 if (input_len > 0)
664 data->input_str[input_len - 1] = '\0';
665 window_choose_redraw_screen(wp);
666 break;
667 case MODEKEYCHOICE_STARTNUMBERPREFIX:
668 key &= KEYC_MASK_KEY;
669 if (key < '0' || key > '9')
670 break;
671 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
672 "Goto Item", wp, key);
673 break;
674 default:
675 idx = window_choose_index_key(data, key);
676 if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
677 break;
678 data->selected = idx;
680 item = &ARRAY_ITEM(&data->list, data->selected);
681 window_choose_fire_callback(wp, item->wcd);
682 break;
686 void
687 window_choose_mouse(
688 struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
690 struct window_choose_mode_data *data = wp->modedata;
691 struct screen *s = &data->screen;
692 struct window_choose_mode_item *item;
693 u_int idx;
695 if (~m->event & MOUSE_EVENT_CLICK)
696 return;
697 if (m->x >= screen_size_x(s))
698 return;
699 if (m->y >= screen_size_y(s))
700 return;
702 idx = data->top + m->y;
703 if (idx >= ARRAY_LENGTH(&data->list))
704 return;
705 data->selected = idx;
707 item = &ARRAY_ITEM(&data->list, data->selected);
708 window_choose_fire_callback(wp, item->wcd);
711 void
712 window_choose_write_line(
713 struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
715 struct window_choose_mode_data *data = wp->modedata;
716 struct window_choose_mode_item *item;
717 struct options *oo = &wp->window->options;
718 struct screen *s = &data->screen;
719 struct grid_cell gc;
720 size_t last, xoff = 0;
721 char hdr[32], label[32];
722 int utf8flag, key;
724 if (data->callbackfn == NULL)
725 fatalx("called before callback assigned");
727 last = screen_size_y(s) - 1;
728 utf8flag = options_get_number(&wp->window->options, "utf8");
729 memcpy(&gc, &grid_default_cell, sizeof gc);
730 if (data->selected == data->top + py)
731 window_mode_attrs(&gc, oo);
733 screen_write_cursormove(ctx, 0, py);
734 if (data->top + py < ARRAY_LENGTH(&data->list)) {
735 item = &ARRAY_ITEM(&data->list, data->top + py);
736 if (item->wcd->wl != NULL &&
737 item->wcd->wl->flags & WINLINK_ALERTFLAGS)
738 gc.attr |= GRID_ATTR_BRIGHT;
740 key = window_choose_key_index(data, data->top + py);
741 if (key != -1)
742 xsnprintf (label, sizeof label, "(%c)", key);
743 else
744 xsnprintf (label, sizeof label, "(%d)", item->pos);
745 screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
746 "%*s %s %s", data->width + 2, label,
748 * Add indication to tree if necessary about whether it's
749 * expanded or not.
751 (item->wcd->type & TREE_SESSION) ?
752 (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
754 while (s->cx < screen_size_x(s) - 1)
755 screen_write_putc(ctx, &gc, ' ');
757 if (data->input_type != WINDOW_CHOOSE_NORMAL) {
758 window_mode_attrs(&gc, oo);
760 xoff = xsnprintf(hdr, sizeof hdr,
761 "%s: %s", data->input_prompt, data->input_str);
762 screen_write_cursormove(ctx, 0, last);
763 screen_write_puts(ctx, &gc, "%s", hdr);
764 screen_write_cursormove(ctx, xoff, py);
765 memcpy(&gc, &grid_default_cell, sizeof gc);
771 window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
773 static const char keys[] = "0123456789"
774 "abcdefghijklmnopqrstuvwxyz"
775 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
776 const char *ptr;
777 int mkey;
779 for (ptr = keys; *ptr != '\0'; ptr++) {
780 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
781 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
782 continue;
783 if (idx-- == 0)
784 return (*ptr);
786 return (-1);
790 window_choose_index_key(struct window_choose_mode_data *data, int key)
792 static const char keys[] = "0123456789"
793 "abcdefghijklmnopqrstuvwxyz"
794 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
795 const char *ptr;
796 int mkey;
797 u_int idx = 0;
799 for (ptr = keys; *ptr != '\0'; ptr++) {
800 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
801 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
802 continue;
803 if (key == *ptr)
804 return (idx);
805 idx++;
807 return (-1);
810 void
811 window_choose_redraw_screen(struct window_pane *wp)
813 struct window_choose_mode_data *data = wp->modedata;
814 struct screen *s = &data->screen;
815 struct screen_write_ctx ctx;
816 u_int i;
818 screen_write_start(&ctx, wp, NULL);
819 for (i = 0; i < screen_size_y(s); i++)
820 window_choose_write_line(wp, &ctx, i);
821 screen_write_stop(&ctx);
824 void
825 window_choose_scroll_up(struct window_pane *wp)
827 struct window_choose_mode_data *data = wp->modedata;
828 struct screen_write_ctx ctx;
830 if (data->top == 0)
831 return;
832 data->top--;
834 screen_write_start(&ctx, wp, NULL);
835 screen_write_cursormove(&ctx, 0, 0);
836 screen_write_insertline(&ctx, 1);
837 window_choose_write_line(wp, &ctx, 0);
838 if (screen_size_y(&data->screen) > 1)
839 window_choose_write_line(wp, &ctx, 1);
840 screen_write_stop(&ctx);
843 void
844 window_choose_scroll_down(struct window_pane *wp)
846 struct window_choose_mode_data *data = wp->modedata;
847 struct screen *s = &data->screen;
848 struct screen_write_ctx ctx;
850 if (data->top >= ARRAY_LENGTH(&data->list))
851 return;
852 data->top++;
854 screen_write_start(&ctx, wp, NULL);
855 screen_write_cursormove(&ctx, 0, 0);
856 screen_write_deleteline(&ctx, 1);
857 window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
858 if (screen_size_y(&data->screen) > 1)
859 window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
860 screen_write_stop(&ctx);
863 struct window_choose_data *
864 window_choose_add_session(struct window_pane *wp, struct client *c,
865 struct session *s, const char *template, const char *action, u_int idx)
867 struct window_choose_data *wcd;
869 wcd = window_choose_data_create(TREE_SESSION, c, c->session);
870 wcd->idx = s->id;
872 wcd->tree_session = s;
873 wcd->tree_session->references++;
875 wcd->ft_template = xstrdup(template);
876 format_add(wcd->ft, "line", "%u", idx);
877 format_session(wcd->ft, s);
879 wcd->command = cmd_template_replace(action, s->name, 1);
881 window_choose_add(wp, wcd);
883 return (wcd);
886 struct window_choose_data *
887 window_choose_add_item(struct window_pane *wp, struct client *c,
888 struct winlink *wl, const char *template, const char *action, u_int idx)
890 struct window_choose_data *wcd;
891 char *expanded;
893 wcd = window_choose_data_create(TREE_OTHER, c, c->session);
894 wcd->idx = wl->idx;
896 wcd->ft_template = xstrdup(template);
897 format_add(wcd->ft, "line", "%u", idx);
898 format_session(wcd->ft, wcd->start_session);
899 format_winlink(wcd->ft, wcd->start_session, wl);
900 format_window_pane(wcd->ft, wl->window->active);
903 * Interpolate action here, since the data we pass back is the expanded
904 * template itself.
906 xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
907 wcd->command = cmd_template_replace(action, expanded, 1);
908 free(expanded);
910 window_choose_add(wp, wcd);
912 return (wcd);
916 struct window_choose_data *
917 window_choose_add_window(struct window_pane *wp, struct client *c,
918 struct session *s, struct winlink *wl, const char *template,
919 const char *action, u_int idx)
921 struct window_choose_data *wcd;
922 char *expanded;
924 wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
925 wcd->idx = wl->idx;
927 wcd->wl = wl;
929 wcd->tree_session = s;
930 wcd->tree_session->references++;
932 wcd->ft_template = xstrdup(template);
933 format_add(wcd->ft, "line", "%u", idx);
934 format_session(wcd->ft, s);
935 format_winlink(wcd->ft, s, wl);
936 format_window_pane(wcd->ft, wl->window->active);
938 xasprintf(&expanded, "%s:%d", s->name, wl->idx);
939 wcd->command = cmd_template_replace(action, expanded, 1);
940 free(expanded);
942 window_choose_add(wp, wcd);
944 return (wcd);