Do not attempt to read .tmux.conf if we can't figure out a home
[tmux-openbsd.git] / window-choose.c
blob77add5e447175242979e30c59c2ff8f508b284ff
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);
84 void window_choose_reset_top(struct window_pane *, u_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_set_current(struct window_pane *wp, u_int cur)
107 struct window_choose_mode_data *data = wp->modedata;
108 struct screen *s = &data->screen;
110 data->selected = cur;
111 window_choose_reset_top(wp, screen_size_y(s));
114 void
115 window_choose_reset_top(struct window_pane *wp, u_int sy)
117 struct window_choose_mode_data *data = wp->modedata;
119 data->top = 0;
120 if (data->selected > sy - 1)
121 data->top = data->selected - (sy - 1);
123 window_choose_redraw_screen(wp);
126 void
127 window_choose_ready(struct window_pane *wp, u_int cur,
128 void (*callbackfn)(struct window_choose_data *))
130 struct window_choose_mode_data *data = wp->modedata;
132 data->callbackfn = callbackfn;
133 if (data->callbackfn == NULL)
134 data->callbackfn = window_choose_default_callback;
136 ARRAY_CONCAT(&data->old_list, &data->list);
138 window_choose_set_current(wp, cur);
139 window_choose_collapse_all(wp);
142 struct screen *
143 window_choose_init(struct window_pane *wp)
145 struct window_choose_mode_data *data;
146 struct screen *s;
147 int keys;
149 wp->modedata = data = xmalloc(sizeof *data);
151 data->callbackfn = NULL;
152 data->input_type = WINDOW_CHOOSE_NORMAL;
153 data->input_str = xstrdup("");
154 data->input_prompt = NULL;
156 ARRAY_INIT(&data->list);
157 ARRAY_INIT(&data->old_list);
158 data->top = 0;
160 s = &data->screen;
161 screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
162 s->mode &= ~MODE_CURSOR;
163 if (options_get_number(&wp->window->options, "mode-mouse"))
164 s->mode |= MODE_MOUSE_STANDARD;
166 keys = options_get_number(&wp->window->options, "mode-keys");
167 if (keys == MODEKEY_EMACS)
168 mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
169 else
170 mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
172 return (s);
175 struct window_choose_data *
176 window_choose_data_create(int type, struct client *c, struct session *s)
178 struct window_choose_data *wcd;
180 wcd = xmalloc(sizeof *wcd);
181 wcd->type = type;
183 wcd->ft = format_create();
184 wcd->ft_template = NULL;
186 wcd->command = NULL;
188 wcd->wl = NULL;
189 wcd->pane_id = -1;
190 wcd->idx = -1;
192 wcd->tree_session = NULL;
194 wcd->start_client = c;
195 wcd->start_client->references++;
196 wcd->start_session = s;
197 wcd->start_session->references++;
199 return (wcd);
202 void
203 window_choose_data_free(struct window_choose_data *wcd)
205 wcd->start_client->references--;
206 wcd->start_session->references--;
208 if (wcd->tree_session != NULL)
209 wcd->tree_session->references--;
211 free(wcd->ft_template);
212 format_free(wcd->ft);
214 free(wcd->command);
215 free(wcd);
218 void
219 window_choose_data_run(struct window_choose_data *cdata)
221 struct cmd_list *cmdlist;
222 char *cause;
225 * The command template will have already been replaced. But if it's
226 * NULL, bail here.
228 if (cdata->command == NULL)
229 return;
231 if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) {
232 if (cause != NULL) {
233 *cause = toupper((u_char) *cause);
234 status_message_set(cdata->start_client, "%s", cause);
235 free(cause);
237 return;
240 cmdq_run(cdata->start_client->cmdq, cmdlist);
241 cmd_list_free(cmdlist);
244 void
245 window_choose_default_callback(struct window_choose_data *wcd)
247 if (wcd == NULL)
248 return;
249 if (wcd->start_client->flags & CLIENT_DEAD)
250 return;
252 window_choose_data_run(wcd);
255 void
256 window_choose_free(struct window_pane *wp)
258 if (wp->modedata != NULL)
259 window_choose_free1(wp->modedata);
262 void
263 window_choose_free1(struct window_choose_mode_data *data)
265 struct window_choose_mode_item *item;
266 u_int i;
268 if (data == NULL)
269 return;
271 for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
272 item = &ARRAY_ITEM(&data->old_list, i);
273 window_choose_data_free(item->wcd);
274 free(item->name);
276 ARRAY_FREE(&data->list);
277 ARRAY_FREE(&data->old_list);
278 free(data->input_str);
280 screen_free(&data->screen);
281 free(data);
284 void
285 window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
287 struct window_choose_mode_data *data = wp->modedata;
288 struct screen *s = &data->screen;
290 window_choose_reset_top(wp, sy);
291 screen_resize(s, sx, sy, 0);
292 window_choose_redraw_screen(wp);
295 void
296 window_choose_fire_callback(
297 struct window_pane *wp, struct window_choose_data *wcd)
299 struct window_choose_mode_data *data = wp->modedata;
301 wp->modedata = NULL;
302 window_pane_reset_mode(wp);
304 data->callbackfn(wcd);
306 window_choose_free1(data);
309 void
310 window_choose_prompt_input(enum window_choose_input_type input_type,
311 const char *prompt, struct window_pane *wp, int key)
313 struct window_choose_mode_data *data = wp->modedata;
314 size_t input_len;
316 data->input_type = input_type;
317 data->input_prompt = prompt;
318 input_len = strlen(data->input_str) + 2;
320 data->input_str = xrealloc(data->input_str, 1, input_len);
321 data->input_str[input_len - 2] = key;
322 data->input_str[input_len - 1] = '\0';
324 window_choose_redraw_screen(wp);
327 void
328 window_choose_collapse(struct window_pane *wp, struct session *s)
330 struct window_choose_mode_data *data = wp->modedata;
331 struct window_choose_mode_item *item, *chosen;
332 struct window_choose_data *wcd;
333 u_int i, pos;
335 ARRAY_DECL(, struct window_choose_mode_item) list_copy;
336 ARRAY_INIT(&list_copy);
338 pos = data->selected;
340 chosen = &ARRAY_ITEM(&data->list, pos);
341 chosen->state &= ~TREE_EXPANDED;
344 * Trying to mangle the &data->list in-place has lots of problems, so
345 * assign the actual result we want to render and copy the new one over
346 * the top of it.
348 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
349 item = &ARRAY_ITEM(&data->list, i);
350 wcd = item->wcd;
352 if (s == wcd->tree_session) {
353 /* We only show the session when collapsed. */
354 if (wcd->type & TREE_SESSION) {
355 item->state &= ~TREE_EXPANDED;
357 ARRAY_ADD(&list_copy,
358 ARRAY_ITEM(&data->list, i));
360 * Update the selection to this session item so
361 * we don't end up highlighting a non-existent
362 * item.
364 data->selected = i;
366 } else
367 ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
370 if (!ARRAY_EMPTY(&list_copy)) {
371 ARRAY_FREE(&data->list);
372 ARRAY_CONCAT(&data->list, &list_copy);
373 ARRAY_FREE(&list_copy);
377 void
378 window_choose_collapse_all(struct window_pane *wp)
380 struct window_choose_mode_data *data = wp->modedata;
381 struct window_choose_mode_item *item;
382 struct screen *scr = &data->screen;
383 struct session *s, *chosen;
384 u_int i;
386 chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
388 RB_FOREACH(s, sessions, &sessions)
389 window_choose_collapse(wp, s);
391 /* Reset the selection back to the starting session. */
392 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
393 item = &ARRAY_ITEM(&data->list, i);
395 if (chosen != item->wcd->tree_session)
396 continue;
398 if (item->wcd->type & TREE_SESSION)
399 data->selected = i;
401 window_choose_reset_top(wp, screen_size_y(scr));
404 void
405 window_choose_expand_all(struct window_pane *wp)
407 struct window_choose_mode_data *data = wp->modedata;
408 struct window_choose_mode_item *item;
409 struct screen *scr = &data->screen;
410 struct session *s;
411 u_int i;
413 RB_FOREACH(s, sessions, &sessions) {
414 for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
415 item = &ARRAY_ITEM(&data->list, i);
417 if (s != item->wcd->tree_session)
418 continue;
420 if (item->wcd->type & TREE_SESSION)
421 window_choose_expand(wp, s, i);
425 window_choose_reset_top(wp, screen_size_y(scr));
428 void
429 window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
431 struct window_choose_mode_data *data = wp->modedata;
432 struct window_choose_mode_item *item, *chosen;
433 struct window_choose_data *wcd;
434 u_int i, items;
436 chosen = &ARRAY_ITEM(&data->list, pos);
437 items = ARRAY_LENGTH(&data->old_list) - 1;
439 /* It's not possible to expand anything other than sessions. */
440 if (!(chosen->wcd->type & TREE_SESSION))
441 return;
443 /* Don't re-expand a session which is already expanded. */
444 if (chosen->state & TREE_EXPANDED)
445 return;
447 /* Mark the session entry as expanded. */
448 chosen->state |= TREE_EXPANDED;
451 * Go back through the original list of all sessions and windows, and
452 * pull out the windows where the session matches the selection chosen
453 * to expand.
455 for (i = items; i > 0; i--) {
456 item = &ARRAY_ITEM(&data->old_list, i);
457 item->state |= TREE_EXPANDED;
458 wcd = item->wcd;
460 if (s == wcd->tree_session) {
462 * Since the session is already displayed, we only care
463 * to add back in window for it.
465 if (wcd->type & TREE_WINDOW) {
467 * If the insertion point for adding the
468 * windows to the session falls inside the
469 * range of the list, then we insert these
470 * entries in order *AFTER* the selected
471 * session.
473 if (pos < i ) {
474 ARRAY_INSERT(&data->list,
475 pos + 1,
476 ARRAY_ITEM(&data->old_list,
477 i));
478 } else {
479 /* Ran out of room, add to the end. */
480 ARRAY_ADD(&data->list,
481 ARRAY_ITEM(&data->old_list,
482 i));
489 void
490 window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
492 struct window_choose_mode_data *data = wp->modedata;
493 struct screen *s = &data->screen;
494 struct screen_write_ctx ctx;
495 struct window_choose_mode_item *item;
496 size_t input_len;
497 u_int items, n;
498 int idx;
500 items = ARRAY_LENGTH(&data->list);
502 if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
503 switch (mode_key_lookup(&data->mdata, key, NULL)) {
504 case MODEKEYCHOICE_CANCEL:
505 data->input_type = WINDOW_CHOOSE_NORMAL;
506 window_choose_redraw_screen(wp);
507 break;
508 case MODEKEYCHOICE_CHOOSE:
509 n = strtonum(data->input_str, 0, INT_MAX, NULL);
510 if (n > items - 1) {
511 data->input_type = WINDOW_CHOOSE_NORMAL;
512 window_choose_redraw_screen(wp);
513 break;
515 item = &ARRAY_ITEM(&data->list, n);
516 window_choose_fire_callback(wp, item->wcd);
517 break;
518 case MODEKEYCHOICE_BACKSPACE:
519 input_len = strlen(data->input_str);
520 if (input_len > 0)
521 data->input_str[input_len - 1] = '\0';
522 window_choose_redraw_screen(wp);
523 break;
524 default:
525 if (key < '0' || key > '9')
526 break;
527 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
528 "Goto Item", wp, key);
529 break;
531 return;
534 switch (mode_key_lookup(&data->mdata, key, NULL)) {
535 case MODEKEYCHOICE_CANCEL:
536 window_choose_fire_callback(wp, NULL);
537 break;
538 case MODEKEYCHOICE_CHOOSE:
539 item = &ARRAY_ITEM(&data->list, data->selected);
540 window_choose_fire_callback(wp, item->wcd);
541 break;
542 case MODEKEYCHOICE_TREE_TOGGLE:
543 item = &ARRAY_ITEM(&data->list, data->selected);
544 if (item->state & TREE_EXPANDED)
545 window_choose_collapse(wp, item->wcd->tree_session);
546 else {
547 window_choose_expand(wp, item->wcd->tree_session,
548 data->selected);
550 window_choose_redraw_screen(wp);
551 break;
552 case MODEKEYCHOICE_TREE_COLLAPSE:
553 item = &ARRAY_ITEM(&data->list, data->selected);
554 if (item->state & TREE_EXPANDED) {
555 window_choose_collapse(wp, item->wcd->tree_session);
556 window_choose_redraw_screen(wp);
558 break;
559 case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
560 window_choose_collapse_all(wp);
561 break;
562 case MODEKEYCHOICE_TREE_EXPAND:
563 item = &ARRAY_ITEM(&data->list, data->selected);
564 if (!(item->state & TREE_EXPANDED)) {
565 window_choose_expand(wp, item->wcd->tree_session,
566 data->selected);
567 window_choose_redraw_screen(wp);
569 break;
570 case MODEKEYCHOICE_TREE_EXPAND_ALL:
571 window_choose_expand_all(wp);
572 break;
573 case MODEKEYCHOICE_UP:
574 if (items == 0)
575 break;
576 if (data->selected == 0) {
577 data->selected = items - 1;
578 if (data->selected > screen_size_y(s) - 1)
579 data->top = items - screen_size_y(s);
580 window_choose_redraw_screen(wp);
581 break;
583 data->selected--;
584 if (data->selected < data->top)
585 window_choose_scroll_up(wp);
586 else {
587 screen_write_start(&ctx, wp, NULL);
588 window_choose_write_line(
589 wp, &ctx, data->selected - data->top);
590 window_choose_write_line(
591 wp, &ctx, data->selected + 1 - data->top);
592 screen_write_stop(&ctx);
594 break;
595 case MODEKEYCHOICE_DOWN:
596 if (items == 0)
597 break;
598 if (data->selected == items - 1) {
599 data->selected = 0;
600 data->top = 0;
601 window_choose_redraw_screen(wp);
602 break;
604 data->selected++;
606 if (data->selected < data->top + screen_size_y(s)) {
607 screen_write_start(&ctx, wp, NULL);
608 window_choose_write_line(
609 wp, &ctx, data->selected - data->top);
610 window_choose_write_line(
611 wp, &ctx, data->selected - 1 - data->top);
612 screen_write_stop(&ctx);
613 } else
614 window_choose_scroll_down(wp);
615 break;
616 case MODEKEYCHOICE_SCROLLUP:
617 if (items == 0 || data->top == 0)
618 break;
619 if (data->selected == data->top + screen_size_y(s) - 1) {
620 data->selected--;
621 window_choose_scroll_up(wp);
622 screen_write_start(&ctx, wp, NULL);
623 window_choose_write_line(
624 wp, &ctx, screen_size_y(s) - 1);
625 screen_write_stop(&ctx);
626 } else
627 window_choose_scroll_up(wp);
628 break;
629 case MODEKEYCHOICE_SCROLLDOWN:
630 if (items == 0 ||
631 data->top + screen_size_y(&data->screen) >= items)
632 break;
633 if (data->selected == data->top) {
634 data->selected++;
635 window_choose_scroll_down(wp);
636 screen_write_start(&ctx, wp, NULL);
637 window_choose_write_line(wp, &ctx, 0);
638 screen_write_stop(&ctx);
639 } else
640 window_choose_scroll_down(wp);
641 break;
642 case MODEKEYCHOICE_PAGEUP:
643 if (data->selected < screen_size_y(s)) {
644 data->selected = 0;
645 data->top = 0;
646 } else {
647 data->selected -= screen_size_y(s);
648 if (data->top < screen_size_y(s))
649 data->top = 0;
650 else
651 data->top -= screen_size_y(s);
653 window_choose_redraw_screen(wp);
654 break;
655 case MODEKEYCHOICE_PAGEDOWN:
656 data->selected += screen_size_y(s);
657 if (data->selected > items - 1)
658 data->selected = items - 1;
659 data->top += screen_size_y(s);
660 if (screen_size_y(s) < items) {
661 if (data->top + screen_size_y(s) > items)
662 data->top = items - screen_size_y(s);
663 } else
664 data->top = 0;
665 if (data->selected < data->top)
666 data->top = data->selected;
667 window_choose_redraw_screen(wp);
668 break;
669 case MODEKEYCHOICE_BACKSPACE:
670 input_len = strlen(data->input_str);
671 if (input_len > 0)
672 data->input_str[input_len - 1] = '\0';
673 window_choose_redraw_screen(wp);
674 break;
675 case MODEKEYCHOICE_STARTNUMBERPREFIX:
676 key &= KEYC_MASK_KEY;
677 if (key < '0' || key > '9')
678 break;
679 window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
680 "Goto Item", wp, key);
681 break;
682 default:
683 idx = window_choose_index_key(data, key);
684 if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
685 break;
686 data->selected = idx;
688 item = &ARRAY_ITEM(&data->list, data->selected);
689 window_choose_fire_callback(wp, item->wcd);
690 break;
694 void
695 window_choose_mouse(
696 struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
698 struct window_choose_mode_data *data = wp->modedata;
699 struct screen *s = &data->screen;
700 struct window_choose_mode_item *item;
701 u_int idx;
703 if (~m->event & MOUSE_EVENT_CLICK)
704 return;
705 if (m->x >= screen_size_x(s))
706 return;
707 if (m->y >= screen_size_y(s))
708 return;
710 idx = data->top + m->y;
711 if (idx >= ARRAY_LENGTH(&data->list))
712 return;
713 data->selected = idx;
715 item = &ARRAY_ITEM(&data->list, data->selected);
716 window_choose_fire_callback(wp, item->wcd);
719 void
720 window_choose_write_line(
721 struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
723 struct window_choose_mode_data *data = wp->modedata;
724 struct window_choose_mode_item *item;
725 struct options *oo = &wp->window->options;
726 struct screen *s = &data->screen;
727 struct grid_cell gc;
728 size_t last, xoff = 0;
729 char hdr[32], label[32];
730 int utf8flag, key;
732 if (data->callbackfn == NULL)
733 fatalx("called before callback assigned");
735 last = screen_size_y(s) - 1;
736 utf8flag = options_get_number(&wp->window->options, "utf8");
737 memcpy(&gc, &grid_default_cell, sizeof gc);
738 if (data->selected == data->top + py)
739 window_mode_attrs(&gc, oo);
741 screen_write_cursormove(ctx, 0, py);
742 if (data->top + py < ARRAY_LENGTH(&data->list)) {
743 item = &ARRAY_ITEM(&data->list, data->top + py);
744 if (item->wcd->wl != NULL &&
745 item->wcd->wl->flags & WINLINK_ALERTFLAGS)
746 gc.attr |= GRID_ATTR_BRIGHT;
748 key = window_choose_key_index(data, data->top + py);
749 if (key != -1)
750 xsnprintf (label, sizeof label, "(%c)", key);
751 else
752 xsnprintf (label, sizeof label, "(%d)", item->pos);
753 screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
754 "%*s %s %s", data->width + 2, label,
756 * Add indication to tree if necessary about whether it's
757 * expanded or not.
759 (item->wcd->type & TREE_SESSION) ?
760 (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
762 while (s->cx < screen_size_x(s) - 1)
763 screen_write_putc(ctx, &gc, ' ');
765 if (data->input_type != WINDOW_CHOOSE_NORMAL) {
766 window_mode_attrs(&gc, oo);
768 xoff = xsnprintf(hdr, sizeof hdr,
769 "%s: %s", data->input_prompt, data->input_str);
770 screen_write_cursormove(ctx, 0, last);
771 screen_write_puts(ctx, &gc, "%s", hdr);
772 screen_write_cursormove(ctx, xoff, py);
773 memcpy(&gc, &grid_default_cell, sizeof gc);
779 window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
781 static const char keys[] = "0123456789"
782 "abcdefghijklmnopqrstuvwxyz"
783 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
784 const char *ptr;
785 int mkey;
787 for (ptr = keys; *ptr != '\0'; ptr++) {
788 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
789 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
790 continue;
791 if (idx-- == 0)
792 return (*ptr);
794 return (-1);
798 window_choose_index_key(struct window_choose_mode_data *data, int key)
800 static const char keys[] = "0123456789"
801 "abcdefghijklmnopqrstuvwxyz"
802 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
803 const char *ptr;
804 int mkey;
805 u_int idx = 0;
807 for (ptr = keys; *ptr != '\0'; ptr++) {
808 mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
809 if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
810 continue;
811 if (key == *ptr)
812 return (idx);
813 idx++;
815 return (-1);
818 void
819 window_choose_redraw_screen(struct window_pane *wp)
821 struct window_choose_mode_data *data = wp->modedata;
822 struct screen *s = &data->screen;
823 struct screen_write_ctx ctx;
824 u_int i;
826 screen_write_start(&ctx, wp, NULL);
827 for (i = 0; i < screen_size_y(s); i++)
828 window_choose_write_line(wp, &ctx, i);
829 screen_write_stop(&ctx);
832 void
833 window_choose_scroll_up(struct window_pane *wp)
835 struct window_choose_mode_data *data = wp->modedata;
836 struct screen_write_ctx ctx;
838 if (data->top == 0)
839 return;
840 data->top--;
842 screen_write_start(&ctx, wp, NULL);
843 screen_write_cursormove(&ctx, 0, 0);
844 screen_write_insertline(&ctx, 1);
845 window_choose_write_line(wp, &ctx, 0);
846 if (screen_size_y(&data->screen) > 1)
847 window_choose_write_line(wp, &ctx, 1);
848 screen_write_stop(&ctx);
851 void
852 window_choose_scroll_down(struct window_pane *wp)
854 struct window_choose_mode_data *data = wp->modedata;
855 struct screen *s = &data->screen;
856 struct screen_write_ctx ctx;
858 if (data->top >= ARRAY_LENGTH(&data->list))
859 return;
860 data->top++;
862 screen_write_start(&ctx, wp, NULL);
863 screen_write_cursormove(&ctx, 0, 0);
864 screen_write_deleteline(&ctx, 1);
865 window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
866 if (screen_size_y(&data->screen) > 1)
867 window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
868 screen_write_stop(&ctx);
871 struct window_choose_data *
872 window_choose_add_session(struct window_pane *wp, struct client *c,
873 struct session *s, const char *template, const char *action, u_int idx)
875 struct window_choose_data *wcd;
877 wcd = window_choose_data_create(TREE_SESSION, c, c->session);
878 wcd->idx = s->id;
880 wcd->tree_session = s;
881 wcd->tree_session->references++;
883 wcd->ft_template = xstrdup(template);
884 format_add(wcd->ft, "line", "%u", idx);
885 format_session(wcd->ft, s);
887 wcd->command = cmd_template_replace(action, s->name, 1);
889 window_choose_add(wp, wcd);
891 return (wcd);
894 struct window_choose_data *
895 window_choose_add_item(struct window_pane *wp, struct client *c,
896 struct winlink *wl, const char *template, const char *action, u_int idx)
898 struct window_choose_data *wcd;
899 char *expanded;
901 wcd = window_choose_data_create(TREE_OTHER, c, c->session);
902 wcd->idx = wl->idx;
904 wcd->ft_template = xstrdup(template);
905 format_add(wcd->ft, "line", "%u", idx);
906 format_session(wcd->ft, wcd->start_session);
907 format_winlink(wcd->ft, wcd->start_session, wl);
908 format_window_pane(wcd->ft, wl->window->active);
911 * Interpolate action here, since the data we pass back is the expanded
912 * template itself.
914 xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
915 wcd->command = cmd_template_replace(action, expanded, 1);
916 free(expanded);
918 window_choose_add(wp, wcd);
920 return (wcd);
924 struct window_choose_data *
925 window_choose_add_window(struct window_pane *wp, struct client *c,
926 struct session *s, struct winlink *wl, const char *template,
927 const char *action, u_int idx)
929 struct window_choose_data *wcd;
930 char *expanded;
932 wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
933 wcd->idx = wl->idx;
935 wcd->wl = wl;
937 wcd->tree_session = s;
938 wcd->tree_session->references++;
940 wcd->ft_template = xstrdup(template);
941 format_add(wcd->ft, "line", "%u", idx);
942 format_session(wcd->ft, s);
943 format_winlink(wcd->ft, s, wl);
944 format_window_pane(wcd->ft, wl->window->active);
946 xasprintf(&expanded, "%s:%d", s->name, wl->idx);
947 wcd->command = cmd_template_replace(action, expanded, 1);
948 free(expanded);
950 window_choose_add(wp, wcd);
952 return (wcd);