Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.32
1.32 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.31 2012/12/24 12:34:32 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
1.19 nicm 21: #include <ctype.h>
1.21 nicm 22: #include <stdlib.h>
1.1 nicm 23: #include <string.h>
24:
25: #include "tmux.h"
26:
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);
1.16 nicm 30: void window_choose_key(struct window_pane *, struct session *, int);
1.1 nicm 31: void window_choose_mouse(
1.16 nicm 32: struct window_pane *, struct session *, struct mouse_event *);
1.1 nicm 33:
1.19 nicm 34: void window_choose_fire_callback(
35: struct window_pane *, struct window_choose_data *);
1.1 nicm 36: void window_choose_redraw_screen(struct window_pane *);
37: void window_choose_write_line(
1.13 nicm 38: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 39:
40: void window_choose_scroll_up(struct window_pane *);
41: void window_choose_scroll_down(struct window_pane *);
42:
1.27 nicm 43: void window_choose_collapse(struct window_pane *, struct session *);
44: void window_choose_expand(struct window_pane *, struct session *, u_int);
45: void window_choose_collapse_all(struct window_pane *);
46:
1.22 nicm 47: enum window_choose_input_type {
48: WINDOW_CHOOSE_NORMAL = -1,
49: WINDOW_CHOOSE_GOTO_ITEM,
50: };
51:
1.1 nicm 52: const struct window_mode window_choose_mode = {
53: window_choose_init,
54: window_choose_free,
55: window_choose_resize,
56: window_choose_key,
57: window_choose_mouse,
58: NULL,
59: };
60:
61: struct window_choose_mode_data {
62: struct screen screen;
63:
64: struct mode_key_data mdata;
65:
66: ARRAY_DECL(, struct window_choose_mode_item) list;
1.27 nicm 67: ARRAY_DECL(, struct window_choose_mode_item) old_list;
1.22 nicm 68: int width;
1.1 nicm 69: u_int top;
70: u_int selected;
1.22 nicm 71: enum window_choose_input_type input_type;
72: const char *input_prompt;
73: char *input_str;
1.1 nicm 74:
1.19 nicm 75: void (*callbackfn)(struct window_choose_data *);
76: void (*freefn)(struct window_choose_data *);
1.1 nicm 77: };
78:
1.25 nicm 79: int window_choose_key_index(struct window_choose_mode_data *, u_int);
80: int window_choose_index_key(struct window_choose_mode_data *, int);
1.22 nicm 81: void window_choose_prompt_input(enum window_choose_input_type,
82: const char *, struct window_pane *, int);
1.11 nicm 83:
1.1 nicm 84: void
1.19 nicm 85: window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
1.1 nicm 86: {
87: struct window_choose_mode_data *data = wp->modedata;
88: struct window_choose_mode_item *item;
1.22 nicm 89: char tmp[10];
1.1 nicm 90:
91: ARRAY_EXPAND(&data->list, 1);
92: item = &ARRAY_LAST(&data->list);
93:
1.19 nicm 94: item->name = format_expand(wcd->ft, wcd->ft_template);
95: item->wcd = wcd;
1.22 nicm 96: item->pos = ARRAY_LENGTH(&data->list) - 1;
1.27 nicm 97: item->state = 0;
1.22 nicm 98:
1.25 nicm 99: data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos);
1.1 nicm 100: }
101:
102: void
1.3 nicm 103: window_choose_ready(struct window_pane *wp, u_int cur,
1.19 nicm 104: void (*callbackfn)(struct window_choose_data *),
105: void (*freefn)(struct window_choose_data *))
1.1 nicm 106: {
107: struct window_choose_mode_data *data = wp->modedata;
108: struct screen *s = &data->screen;
109:
110: data->selected = cur;
111: if (data->selected > screen_size_y(s) - 1)
112: data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
113:
1.3 nicm 114: data->callbackfn = callbackfn;
115: data->freefn = freefn;
1.1 nicm 116:
1.27 nicm 117: ARRAY_CONCAT(&data->old_list, &data->list);
118:
119: window_choose_collapse_all(wp);
1.1 nicm 120: }
121:
122: struct screen *
123: window_choose_init(struct window_pane *wp)
124: {
125: struct window_choose_mode_data *data;
126: struct screen *s;
1.5 nicm 127: int keys;
1.1 nicm 128:
129: wp->modedata = data = xmalloc(sizeof *data);
1.3 nicm 130:
131: data->callbackfn = NULL;
132: data->freefn = NULL;
1.22 nicm 133: data->input_type = WINDOW_CHOOSE_NORMAL;
134: data->input_str = xstrdup("");
135: data->input_prompt = NULL;
1.3 nicm 136:
1.1 nicm 137: ARRAY_INIT(&data->list);
1.27 nicm 138: ARRAY_INIT(&data->old_list);
1.1 nicm 139: data->top = 0;
140:
141: s = &data->screen;
142: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
143: s->mode &= ~MODE_CURSOR;
1.7 nicm 144: if (options_get_number(&wp->window->options, "mode-mouse"))
1.17 nicm 145: s->mode |= MODE_MOUSE_STANDARD;
1.1 nicm 146:
1.5 nicm 147: keys = options_get_number(&wp->window->options, "mode-keys");
148: if (keys == MODEKEY_EMACS)
1.6 nicm 149: mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
1.5 nicm 150: else
1.6 nicm 151: mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
1.1 nicm 152:
153: return (s);
154: }
155:
1.19 nicm 156: struct window_choose_data *
157: window_choose_data_create(struct cmd_ctx *ctx)
158: {
159: struct window_choose_data *wcd;
160:
161: wcd = xmalloc(sizeof *wcd);
162: wcd->ft = format_create();
163: wcd->ft_template = NULL;
1.20 nicm 164: wcd->command = NULL;
1.24 nicm 165: wcd->wl = NULL;
1.27 nicm 166: wcd->tree_session = NULL;
1.19 nicm 167: wcd->client = ctx->curclient;
168: wcd->session = ctx->curclient->session;
169: wcd->idx = -1;
1.27 nicm 170: wcd->type = 0;
1.19 nicm 171:
172: return (wcd);
173: }
174:
1.1 nicm 175: void
176: window_choose_free(struct window_pane *wp)
177: {
178: struct window_choose_mode_data *data = wp->modedata;
1.19 nicm 179: struct window_choose_mode_item *item;
1.1 nicm 180: u_int i;
181:
1.28 nicm 182: for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
183: item = &ARRAY_ITEM(&data->old_list, i);
1.19 nicm 184: if (data->freefn != NULL && item->wcd != NULL)
185: data->freefn(item->wcd);
1.21 nicm 186: free(item->name);
1.19 nicm 187: }
1.1 nicm 188: ARRAY_FREE(&data->list);
1.27 nicm 189: ARRAY_FREE(&data->old_list);
1.22 nicm 190: free(data->input_str);
1.1 nicm 191:
192: screen_free(&data->screen);
1.21 nicm 193: free(data);
1.1 nicm 194: }
195:
196: void
197: window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
198: {
199: struct window_choose_mode_data *data = wp->modedata;
200: struct screen *s = &data->screen;
201:
202: data->top = 0;
203: if (data->selected > sy - 1)
204: data->top = data->selected - (sy - 1);
205:
1.32 ! nicm 206: screen_resize(s, sx, sy, 0);
1.1 nicm 207: window_choose_redraw_screen(wp);
208: }
209:
1.18 nicm 210: void
1.19 nicm 211: window_choose_fire_callback(
212: struct window_pane *wp, struct window_choose_data *wcd)
1.18 nicm 213: {
214: struct window_choose_mode_data *data = wp->modedata;
215: const struct window_mode *oldmode;
216:
217: oldmode = wp->mode;
218: wp->mode = NULL;
219:
1.19 nicm 220: data->callbackfn(wcd);
1.18 nicm 221:
222: wp->mode = oldmode;
223: }
224:
1.22 nicm 225: void
226: window_choose_prompt_input(enum window_choose_input_type input_type,
227: const char *prompt, struct window_pane *wp, int key)
228: {
229: struct window_choose_mode_data *data = wp->modedata;
230: size_t input_len;
231:
232: data->input_type = input_type;
233: data->input_prompt = prompt;
234: input_len = strlen(data->input_str) + 2;
235:
236: data->input_str = xrealloc(data->input_str, 1, input_len);
237: data->input_str[input_len - 2] = key;
238: data->input_str[input_len - 1] = '\0';
239:
240: window_choose_redraw_screen(wp);
241: }
242:
1.27 nicm 243: void
244: window_choose_collapse(struct window_pane *wp, struct session *s)
245: {
246: struct window_choose_mode_data *data = wp->modedata;
247: struct window_choose_mode_item *item, *chosen;
248: struct window_choose_data *wcd;
249: u_int i, pos;
250:
251: ARRAY_DECL(, struct window_choose_mode_item) list_copy;
252: ARRAY_INIT(&list_copy);
253:
254: pos = data->selected;
255:
256: chosen = &ARRAY_ITEM(&data->list, pos);
257: chosen->state &= ~TREE_EXPANDED;
258:
259: /*
260: * Trying to mangle the &data->list in-place has lots of problems, so
261: * assign the actual result we want to render and copy the new one over
262: * the top of it.
263: */
264: for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
265: {
266: item = &ARRAY_ITEM(&data->list, i);
267: wcd = item->wcd;
268:
269: if (s == wcd->tree_session) {
270: /* We only show the session when collapsed. */
271: if (wcd->type & TREE_SESSION) {
272: item->state &= ~TREE_EXPANDED;
273:
274: ARRAY_ADD(&list_copy,
275: ARRAY_ITEM(&data->list, i));
276: /*
277: * Update the selection to this session item so
278: * we don't end up highlighting a non-existent
279: * item.
280: */
281: data->selected = i;
282: }
283: } else
284: ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
285: }
286:
287: if (!ARRAY_EMPTY(&list_copy)) {
288: ARRAY_FREE(&data->list);
289: ARRAY_CONCAT(&data->list, &list_copy);
1.28 nicm 290: ARRAY_FREE(&list_copy);
1.27 nicm 291: }
292: }
293:
294: void
295: window_choose_collapse_all(struct window_pane *wp)
296: {
297: struct window_choose_mode_data *data = wp->modedata;
1.28 nicm 298: struct window_choose_mode_item *item;
299: struct session *s, *chosen;
1.27 nicm 300: u_int i;
301:
1.28 nicm 302: chosen = ARRAY_ITEM(&data->list, data->selected).wcd->session;
1.27 nicm 303:
304: RB_FOREACH(s, sessions, &sessions)
305: window_choose_collapse(wp, s);
306:
307: /* Reset the selection back to the starting session. */
308: for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
309: item = &ARRAY_ITEM(&data->list, i);
310:
1.28 nicm 311: if (chosen != item->wcd->tree_session)
1.27 nicm 312: continue;
313:
314: if (item->wcd->type & TREE_SESSION)
315: data->selected = i;
316: }
317: window_choose_redraw_screen(wp);
318: }
319:
320: void
321: window_choose_expand_all(struct window_pane *wp)
322: {
323: struct window_choose_mode_data *data = wp->modedata;
324: struct window_choose_mode_item *item;
325: struct session *s;
326: u_int i;
327:
328: RB_FOREACH(s, sessions, &sessions) {
329: for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
330: item = &ARRAY_ITEM(&data->list, i);
331:
332: if (s != item->wcd->tree_session)
333: continue;
334:
335: if (item->wcd->type & TREE_SESSION)
336: window_choose_expand(wp, s, i);
337: }
338: }
339:
340: window_choose_redraw_screen(wp);
341: }
342:
343: void
344: window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
345: {
346: struct window_choose_mode_data *data = wp->modedata;
347: struct window_choose_mode_item *item, *chosen;
348: struct window_choose_data *wcd;
349: u_int i, items;
350:
351: chosen = &ARRAY_ITEM(&data->list, pos);
352: items = ARRAY_LENGTH(&data->old_list) - 1;
353:
354: /* It's not possible to expand anything other than sessions. */
355: if (!(chosen->wcd->type & TREE_SESSION))
356: return;
357:
358: /* Don't re-expand a session which is already expanded. */
359: if (chosen->state & TREE_EXPANDED)
360: return;
361:
362: /* Mark the session entry as expanded. */
363: chosen->state |= TREE_EXPANDED;
364:
365: /*
366: * Go back through the original list of all sessions and windows, and
367: * pull out the windows where the session matches the selection chosen
368: * to expand.
369: */
370: for (i = items; i > 0; i--) {
371: item = &ARRAY_ITEM(&data->old_list, i);
372: item->state |= TREE_EXPANDED;
373: wcd = item->wcd;
374:
375: if (s == wcd->tree_session) {
376: /*
377: * Since the session is already displayed, we only care
378: * to add back in window for it.
379: */
380: if (wcd->type & TREE_WINDOW) {
381: /*
382: * If the insertion point for adding the
383: * windows to the session falls inside the
384: * range of the list, then we insert these
385: * entries in order *AFTER* the selected
386: * session.
387: */
388: if (pos < i ) {
389: ARRAY_INSERT(&data->list,
390: pos + 1,
391: ARRAY_ITEM(&data->old_list,
392: i));
393: } else {
394: /* Ran out of room, add to the end. */
395: ARRAY_ADD(&data->list,
396: ARRAY_ITEM(&data->old_list,
397: i));
398: }
399: }
400: }
401: }
402: }
403:
1.12 nicm 404: /* ARGSUSED */
1.1 nicm 405: void
1.16 nicm 406: window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
1.1 nicm 407: {
408: struct window_choose_mode_data *data = wp->modedata;
409: struct screen *s = &data->screen;
410: struct screen_write_ctx ctx;
411: struct window_choose_mode_item *item;
1.22 nicm 412: size_t input_len;
1.27 nicm 413: u_int items, n;
1.11 nicm 414: int idx;
1.1 nicm 415:
416: items = ARRAY_LENGTH(&data->list);
417:
1.25 nicm 418: if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
419: switch (mode_key_lookup(&data->mdata, key)) {
420: case MODEKEYCHOICE_CANCEL:
421: data->input_type = WINDOW_CHOOSE_NORMAL;
422: window_choose_redraw_screen(wp);
1.22 nicm 423: break;
1.25 nicm 424: case MODEKEYCHOICE_CHOOSE:
1.22 nicm 425: n = strtonum(data->input_str, 0, INT_MAX, NULL);
1.25 nicm 426: if (n > items - 1) {
427: data->input_type = WINDOW_CHOOSE_NORMAL;
428: window_choose_redraw_screen(wp);
1.22 nicm 429: break;
1.25 nicm 430: }
1.22 nicm 431: item = &ARRAY_ITEM(&data->list, n);
432: window_choose_fire_callback(wp, item->wcd);
433: window_pane_reset_mode(wp);
434: break;
1.25 nicm 435: case MODEKEYCHOICE_BACKSPACE:
436: input_len = strlen(data->input_str);
437: if (input_len > 0)
438: data->input_str[input_len - 1] = '\0';
439: window_choose_redraw_screen(wp);
440: break;
441: default:
442: if (key < '0' || key > '9')
443: break;
444: window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
445: "Goto Item", wp, key);
446: break;
1.22 nicm 447: }
1.25 nicm 448: return;
449: }
450:
451: switch (mode_key_lookup(&data->mdata, key)) {
452: case MODEKEYCHOICE_CANCEL:
453: window_choose_fire_callback(wp, NULL);
454: window_pane_reset_mode(wp);
455: break;
456: case MODEKEYCHOICE_CHOOSE:
457: item = &ARRAY_ITEM(&data->list, data->selected);
458: window_choose_fire_callback(wp, item->wcd);
459: window_pane_reset_mode(wp);
1.1 nicm 460: break;
1.27 nicm 461: case MODEKEYCHOICE_TREE_TOGGLE:
462: item = &ARRAY_ITEM(&data->list, data->selected);
463: if (item->state & TREE_EXPANDED)
464: window_choose_collapse(wp, item->wcd->tree_session);
465: else {
466: window_choose_expand(wp, item->wcd->tree_session,
467: data->selected);
468: }
469: window_choose_redraw_screen(wp);
470: break;
471: case MODEKEYCHOICE_TREE_COLLAPSE:
472: item = &ARRAY_ITEM(&data->list, data->selected);
473: if (item->state & TREE_EXPANDED) {
474: window_choose_collapse(wp, item->wcd->tree_session);
475: window_choose_redraw_screen(wp);
476: }
477: break;
478: case MODEKEYCHOICE_TREE_COLLAPSE_ALL:
479: window_choose_collapse_all(wp);
480: break;
481: case MODEKEYCHOICE_TREE_EXPAND:
482: item = &ARRAY_ITEM(&data->list, data->selected);
483: if (!(item->state & TREE_EXPANDED)) {
484: window_choose_expand(wp, item->wcd->tree_session,
485: data->selected);
486: window_choose_redraw_screen(wp);
487: }
488: break;
489: case MODEKEYCHOICE_TREE_EXPAND_ALL:
490: window_choose_expand_all(wp);
491: break;
1.5 nicm 492: case MODEKEYCHOICE_UP:
1.1 nicm 493: if (items == 0)
494: break;
495: if (data->selected == 0) {
496: data->selected = items - 1;
497: if (data->selected > screen_size_y(s) - 1)
498: data->top = items - screen_size_y(s);
499: window_choose_redraw_screen(wp);
500: break;
501: }
502: data->selected--;
503: if (data->selected < data->top)
504: window_choose_scroll_up(wp);
505: else {
506: screen_write_start(&ctx, wp, NULL);
507: window_choose_write_line(
508: wp, &ctx, data->selected - data->top);
509: window_choose_write_line(
510: wp, &ctx, data->selected + 1 - data->top);
511: screen_write_stop(&ctx);
512: }
513: break;
1.5 nicm 514: case MODEKEYCHOICE_DOWN:
1.1 nicm 515: if (items == 0)
516: break;
517: if (data->selected == items - 1) {
518: data->selected = 0;
519: data->top = 0;
520: window_choose_redraw_screen(wp);
521: break;
522: }
523: data->selected++;
1.5 nicm 524:
1.15 nicm 525: if (data->selected < data->top + screen_size_y(s)) {
1.1 nicm 526: screen_write_start(&ctx, wp, NULL);
527: window_choose_write_line(
528: wp, &ctx, data->selected - data->top);
529: window_choose_write_line(
530: wp, &ctx, data->selected - 1 - data->top);
531: screen_write_stop(&ctx);
1.15 nicm 532: } else
533: window_choose_scroll_down(wp);
534: break;
535: case MODEKEYCHOICE_SCROLLUP:
536: if (items == 0 || data->top == 0)
537: break;
538: if (data->selected == data->top + screen_size_y(s) - 1) {
539: data->selected--;
540: window_choose_scroll_up(wp);
541: screen_write_start(&ctx, wp, NULL);
542: window_choose_write_line(
543: wp, &ctx, screen_size_y(s) - 1);
544: screen_write_stop(&ctx);
545: } else
546: window_choose_scroll_up(wp);
547: break;
548: case MODEKEYCHOICE_SCROLLDOWN:
549: if (items == 0 ||
550: data->top + screen_size_y(&data->screen) >= items)
551: break;
552: if (data->selected == data->top) {
553: data->selected++;
554: window_choose_scroll_down(wp);
555: screen_write_start(&ctx, wp, NULL);
556: window_choose_write_line(wp, &ctx, 0);
557: screen_write_stop(&ctx);
558: } else
559: window_choose_scroll_down(wp);
1.1 nicm 560: break;
1.5 nicm 561: case MODEKEYCHOICE_PAGEUP:
1.1 nicm 562: if (data->selected < screen_size_y(s)) {
563: data->selected = 0;
564: data->top = 0;
565: } else {
566: data->selected -= screen_size_y(s);
567: if (data->top < screen_size_y(s))
568: data->top = 0;
569: else
570: data->top -= screen_size_y(s);
571: }
1.13 nicm 572: window_choose_redraw_screen(wp);
1.1 nicm 573: break;
1.5 nicm 574: case MODEKEYCHOICE_PAGEDOWN:
1.1 nicm 575: data->selected += screen_size_y(s);
576: if (data->selected > items - 1)
577: data->selected = items - 1;
578: data->top += screen_size_y(s);
579: if (screen_size_y(s) < items) {
580: if (data->top + screen_size_y(s) > items)
581: data->top = items - screen_size_y(s);
582: } else
583: data->top = 0;
584: if (data->selected < data->top)
585: data->top = data->selected;
586: window_choose_redraw_screen(wp);
587: break;
1.22 nicm 588: case MODEKEYCHOICE_BACKSPACE:
589: input_len = strlen(data->input_str);
590: if (input_len > 0)
591: data->input_str[input_len - 1] = '\0';
592: window_choose_redraw_screen(wp);
593: break;
594: case MODEKEYCHOICE_STARTNUMBERPREFIX:
1.25 nicm 595: key &= KEYC_MASK_KEY;
596: if (key < '0' || key > '9')
1.11 nicm 597: break;
1.25 nicm 598: window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
599: "Goto Item", wp, key);
1.22 nicm 600: break;
601: default:
1.25 nicm 602: idx = window_choose_index_key(data, key);
603: if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
604: break;
605: data->selected = idx;
606:
607: item = &ARRAY_ITEM(&data->list, data->selected);
608: window_choose_fire_callback(wp, item->wcd);
609: window_pane_reset_mode(wp);
1.1 nicm 610: break;
611: }
612: }
613:
1.12 nicm 614: /* ARGSUSED */
1.1 nicm 615: void
1.10 nicm 616: window_choose_mouse(
1.16 nicm 617: struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
1.1 nicm 618: {
619: struct window_choose_mode_data *data = wp->modedata;
620: struct screen *s = &data->screen;
621: struct window_choose_mode_item *item;
622: u_int idx;
623:
1.29 nicm 624: if (~m->event & MOUSE_EVENT_CLICK)
1.1 nicm 625: return;
1.10 nicm 626: if (m->x >= screen_size_x(s))
1.1 nicm 627: return;
1.10 nicm 628: if (m->y >= screen_size_y(s))
1.1 nicm 629: return;
630:
1.10 nicm 631: idx = data->top + m->y;
1.1 nicm 632: if (idx >= ARRAY_LENGTH(&data->list))
633: return;
634: data->selected = idx;
635:
636: item = &ARRAY_ITEM(&data->list, data->selected);
1.19 nicm 637: window_choose_fire_callback(wp, item->wcd);
1.1 nicm 638: window_pane_reset_mode(wp);
639: }
640:
641: void
642: window_choose_write_line(
643: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
644: {
645: struct window_choose_mode_data *data = wp->modedata;
646: struct window_choose_mode_item *item;
1.9 nicm 647: struct options *oo = &wp->window->options;
1.1 nicm 648: struct screen *s = &data->screen;
649: struct grid_cell gc;
1.22 nicm 650: size_t last, xoff = 0;
1.25 nicm 651: char hdr[32], label[32];
652: int utf8flag, key;
1.1 nicm 653:
1.3 nicm 654: if (data->callbackfn == NULL)
1.1 nicm 655: fatalx("called before callback assigned");
656:
1.22 nicm 657: last = screen_size_y(s) - 1;
1.2 nicm 658: utf8flag = options_get_number(&wp->window->options, "utf8");
1.1 nicm 659: memcpy(&gc, &grid_default_cell, sizeof gc);
1.22 nicm 660: if (data->selected == data->top + py)
661: window_mode_attrs(&gc, oo);
1.1 nicm 662:
663: screen_write_cursormove(ctx, 0, py);
664: if (data->top + py < ARRAY_LENGTH(&data->list)) {
665: item = &ARRAY_ITEM(&data->list, data->top + py);
1.24 nicm 666: if (item->wcd->wl != NULL &&
667: item->wcd->wl->flags & WINLINK_ALERTFLAGS)
668: gc.attr |= GRID_ATTR_BRIGHT;
1.11 nicm 669:
1.25 nicm 670: key = window_choose_key_index(data, data->top + py);
671: if (key != -1)
672: xsnprintf (label, sizeof label, "(%c)", key);
673: else
674: xsnprintf (label, sizeof label, "(%d)", item->pos);
675: screen_write_nputs(ctx, screen_size_x(s) - 1, &gc, utf8flag,
1.27 nicm 676: "%*s %s %s", data->width + 2, label,
677: /*
678: * Add indication to tree if necessary about whether it's
679: * expanded or not.
680: */
681: (item->wcd->type & TREE_SESSION) ?
682: (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
1.1 nicm 683: }
684: while (s->cx < screen_size_x(s))
685: screen_write_putc(ctx, &gc, ' ');
1.11 nicm 686:
1.22 nicm 687: if (data->input_type != WINDOW_CHOOSE_NORMAL) {
688: window_mode_attrs(&gc, oo);
1.11 nicm 689:
1.22 nicm 690: xoff = xsnprintf(hdr, sizeof hdr,
691: "%s: %s", data->input_prompt, data->input_str);
692: screen_write_cursormove(ctx, 0, last);
693: screen_write_puts(ctx, &gc, "%s", hdr);
694: screen_write_cursormove(ctx, xoff, py);
695: memcpy(&gc, &grid_default_cell, sizeof gc);
1.11 nicm 696: }
1.22 nicm 697:
1.11 nicm 698: }
699:
700: int
1.25 nicm 701: window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
702: {
703: static const char keys[] = "0123456789"
704: "abcdefghijklmnopqrstuvwxyz"
705: "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
706: const char *ptr;
707: int mkey;
708:
709: for (ptr = keys; *ptr != '\0'; ptr++) {
710: mkey = mode_key_lookup(&data->mdata, *ptr);
711: if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
712: continue;
713: if (idx-- == 0)
714: return (*ptr);
715: }
716: return (-1);
717: }
718:
719: int
720: window_choose_index_key(struct window_choose_mode_data *data, int key)
1.11 nicm 721: {
1.25 nicm 722: static const char keys[] = "0123456789"
723: "abcdefghijklmnopqrstuvwxyz"
724: "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1.11 nicm 725: const char *ptr;
1.25 nicm 726: int mkey;
1.11 nicm 727: u_int idx = 0;
728:
729: for (ptr = keys; *ptr != '\0'; ptr++) {
1.25 nicm 730: mkey = mode_key_lookup(&data->mdata, *ptr);
731: if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
732: continue;
1.11 nicm 733: if (key == *ptr)
734: return (idx);
735: idx++;
736: }
737: return (-1);
1.1 nicm 738: }
739:
740: void
741: window_choose_redraw_screen(struct window_pane *wp)
742: {
743: struct window_choose_mode_data *data = wp->modedata;
744: struct screen *s = &data->screen;
745: struct screen_write_ctx ctx;
746: u_int i;
747:
748: screen_write_start(&ctx, wp, NULL);
749: for (i = 0; i < screen_size_y(s); i++)
750: window_choose_write_line(wp, &ctx, i);
751: screen_write_stop(&ctx);
752: }
753:
754: void
755: window_choose_scroll_up(struct window_pane *wp)
756: {
757: struct window_choose_mode_data *data = wp->modedata;
758: struct screen_write_ctx ctx;
759:
760: if (data->top == 0)
761: return;
762: data->top--;
763:
764: screen_write_start(&ctx, wp, NULL);
765: screen_write_cursormove(&ctx, 0, 0);
766: screen_write_insertline(&ctx, 1);
767: window_choose_write_line(wp, &ctx, 0);
768: if (screen_size_y(&data->screen) > 1)
769: window_choose_write_line(wp, &ctx, 1);
770: screen_write_stop(&ctx);
771: }
772:
773: void
774: window_choose_scroll_down(struct window_pane *wp)
775: {
776: struct window_choose_mode_data *data = wp->modedata;
777: struct screen *s = &data->screen;
778: struct screen_write_ctx ctx;
779:
780: if (data->top >= ARRAY_LENGTH(&data->list))
781: return;
782: data->top++;
783:
784: screen_write_start(&ctx, wp, NULL);
785: screen_write_cursormove(&ctx, 0, 0);
786: screen_write_deleteline(&ctx, 1);
787: window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
788: if (screen_size_y(&data->screen) > 1)
789: window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
790: screen_write_stop(&ctx);
1.19 nicm 791: }
792:
793: void
794: window_choose_ctx(struct window_choose_data *cdata)
795: {
796: struct cmd_ctx ctx;
797: struct cmd_list *cmdlist;
1.20 nicm 798: char *cause;
1.19 nicm 799:
1.20 nicm 800: /* The command template will have already been replaced. But if it's
801: * NULL, bail here.
802: */
803: if (cdata->command == NULL)
804: return;
1.19 nicm 805:
1.20 nicm 806: if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) {
1.19 nicm 807: if (cause != NULL) {
808: *cause = toupper((u_char) *cause);
809: status_message_set(cdata->client, "%s", cause);
1.21 nicm 810: free(cause);
1.19 nicm 811: }
812: return;
813: }
814:
815: ctx.msgdata = NULL;
816: ctx.curclient = cdata->client;
817:
818: ctx.error = key_bindings_error;
819: ctx.print = key_bindings_print;
820: ctx.info = key_bindings_info;
821:
822: ctx.cmdclient = NULL;
823:
824: cmd_list_exec(cmdlist, &ctx);
825: cmd_list_free(cmdlist);
1.20 nicm 826: }
827:
828: struct window_choose_data *
829: window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx,
1.22 nicm 830: struct session *s, const char *template, char *action, u_int idx)
1.20 nicm 831: {
832: struct window_choose_data *wcd;
833:
834: wcd = window_choose_data_create(ctx);
835: wcd->idx = s->idx;
1.27 nicm 836: wcd->tree_session = s;
837: wcd->type = TREE_SESSION;
1.20 nicm 838: wcd->command = cmd_template_replace(action, s->name, 1);
839: wcd->ft_template = xstrdup(template);
840: format_add(wcd->ft, "line", "%u", idx);
841: format_session(wcd->ft, s);
842:
843: wcd->client->references++;
844: wcd->session->references++;
845:
846: window_choose_add(wp, wcd);
847:
848: return (wcd);
1.26 nicm 849: }
850:
851: struct window_choose_data *
852: window_choose_add_item(struct window_pane *wp, struct cmd_ctx *ctx,
853: struct winlink *wl, const char *template, char *action, u_int idx)
854: {
855: struct window_choose_data *wcd;
856: char *action_data;
857:
858: wcd = window_choose_data_create(ctx);
859: wcd->idx = wl->idx;
860: wcd->ft_template = xstrdup(template);
861: format_add(wcd->ft, "line", "%u", idx);
862: format_session(wcd->ft, wcd->session);
863: format_winlink(wcd->ft, wcd->session, wl);
864: format_window_pane(wcd->ft, wl->window->active);
865:
866: wcd->client->references++;
867: wcd->session->references++;
868:
869: window_choose_add(wp, wcd);
870:
871: /*
872: * Interpolate action_data here, since the data we pass back is the
873: * expanded template itself.
874: */
875: xasprintf(&action_data, "%s", format_expand(wcd->ft, wcd->ft_template));
876: wcd->command = cmd_template_replace(action, action_data, 1);
877: free(action_data);
878:
879: return (wcd);
880:
1.20 nicm 881: }
882:
883: struct window_choose_data *
884: window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx,
1.22 nicm 885: struct session *s, struct winlink *wl, const char *template,
886: char *action, u_int idx)
1.20 nicm 887: {
888: struct window_choose_data *wcd;
889: char *action_data;
890:
891: wcd = window_choose_data_create(ctx);
892:
893: xasprintf(&action_data, "%s:%d", s->name, wl->idx);
894: wcd->command = cmd_template_replace(action, action_data, 1);
1.21 nicm 895: free(action_data);
1.20 nicm 896:
897: wcd->idx = wl->idx;
1.24 nicm 898: wcd->wl = wl;
1.27 nicm 899: wcd->tree_session = s;
900: wcd->type = TREE_WINDOW;
1.20 nicm 901: wcd->ft_template = xstrdup(template);
902: format_add(wcd->ft, "line", "%u", idx);
903: format_session(wcd->ft, s);
904: format_winlink(wcd->ft, s, wl);
905: format_window_pane(wcd->ft, wl->window->active);
906:
907: wcd->client->references++;
908: wcd->session->references++;
909:
910: window_choose_add(wp, wcd);
911:
912: return (wcd);
1.1 nicm 913: }