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