Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.42
1.42 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.41 2013/03/22 15:49:55 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.33 nicm 34: void window_choose_default_callback(struct window_choose_data *);
35:
1.19 nicm 36: void window_choose_fire_callback(
37: struct window_pane *, struct window_choose_data *);
1.1 nicm 38: void window_choose_redraw_screen(struct window_pane *);
39: void window_choose_write_line(
1.13 nicm 40: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 41:
42: void window_choose_scroll_up(struct window_pane *);
43: void window_choose_scroll_down(struct window_pane *);
44:
1.27 nicm 45: void window_choose_collapse(struct window_pane *, struct session *);
46: void window_choose_expand(struct window_pane *, struct session *, u_int);
47: void window_choose_collapse_all(struct window_pane *);
48:
1.22 nicm 49: enum window_choose_input_type {
50: WINDOW_CHOOSE_NORMAL = -1,
51: WINDOW_CHOOSE_GOTO_ITEM,
52: };
53:
1.1 nicm 54: const struct window_mode window_choose_mode = {
55: window_choose_init,
56: window_choose_free,
57: window_choose_resize,
58: window_choose_key,
59: window_choose_mouse,
60: NULL,
61: };
62:
63: struct window_choose_mode_data {
64: struct screen screen;
65:
66: struct mode_key_data mdata;
67:
68: ARRAY_DECL(, struct window_choose_mode_item) list;
1.27 nicm 69: ARRAY_DECL(, struct window_choose_mode_item) old_list;
1.22 nicm 70: int width;
1.1 nicm 71: u_int top;
72: u_int selected;
1.22 nicm 73: enum window_choose_input_type input_type;
74: const char *input_prompt;
75: char *input_str;
1.1 nicm 76:
1.19 nicm 77: void (*callbackfn)(struct window_choose_data *);
1.1 nicm 78: };
79:
1.38 nicm 80: void window_choose_free1(struct window_choose_mode_data *);
1.25 nicm 81: int window_choose_key_index(struct window_choose_mode_data *, u_int);
82: int window_choose_index_key(struct window_choose_mode_data *, int);
1.22 nicm 83: void window_choose_prompt_input(enum window_choose_input_type,
84: const char *, struct window_pane *, int);
1.11 nicm 85:
1.1 nicm 86: void
1.19 nicm 87: window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
1.1 nicm 88: {
89: struct window_choose_mode_data *data = wp->modedata;
90: struct window_choose_mode_item *item;
1.22 nicm 91: char tmp[10];
1.1 nicm 92:
93: ARRAY_EXPAND(&data->list, 1);
94: item = &ARRAY_LAST(&data->list);
95:
1.19 nicm 96: item->name = format_expand(wcd->ft, wcd->ft_template);
97: item->wcd = wcd;
1.22 nicm 98: item->pos = ARRAY_LENGTH(&data->list) - 1;
1.27 nicm 99: item->state = 0;
1.22 nicm 100:
1.25 nicm 101: data->width = xsnprintf (tmp, sizeof tmp , "%u", item->pos);
1.1 nicm 102: }
103:
104: void
1.3 nicm 105: window_choose_ready(struct window_pane *wp, u_int cur,
1.34 nicm 106: void (*callbackfn)(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;
1.33 nicm 116: if (data->callbackfn == NULL)
117: data->callbackfn = window_choose_default_callback;
1.1 nicm 118:
1.27 nicm 119: ARRAY_CONCAT(&data->old_list, &data->list);
120:
121: window_choose_collapse_all(wp);
1.1 nicm 122: }
123:
124: struct screen *
125: window_choose_init(struct window_pane *wp)
126: {
127: struct window_choose_mode_data *data;
128: struct screen *s;
1.5 nicm 129: int keys;
1.1 nicm 130:
131: wp->modedata = data = xmalloc(sizeof *data);
1.3 nicm 132:
133: data->callbackfn = 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 *
1.33 nicm 158: window_choose_data_create(int type, struct client *c, struct session *s)
1.19 nicm 159: {
160: struct window_choose_data *wcd;
161:
162: wcd = xmalloc(sizeof *wcd);
1.33 nicm 163: wcd->type = type;
164:
1.19 nicm 165: wcd->ft = format_create();
166: wcd->ft_template = NULL;
1.33 nicm 167:
1.20 nicm 168: wcd->command = NULL;
1.33 nicm 169:
1.24 nicm 170: wcd->wl = NULL;
1.33 nicm 171: wcd->pane_id = -1;
172: wcd->idx = -1;
173:
1.27 nicm 174: wcd->tree_session = NULL;
1.33 nicm 175:
176: wcd->start_client = c;
177: wcd->start_client->references++;
178: wcd->start_session = s;
179: wcd->start_session->references++;
1.19 nicm 180:
181: return (wcd);
182: }
183:
1.1 nicm 184: void
1.33 nicm 185: window_choose_data_free(struct window_choose_data *wcd)
186: {
187: wcd->start_client->references--;
188: wcd->start_session->references--;
189:
190: if (wcd->tree_session != NULL)
191: wcd->tree_session->references--;
192:
193: free(wcd->ft_template);
194: format_free(wcd->ft);
195:
196: free(wcd->command);
197: free(wcd);
198: }
199:
200: void
201: window_choose_data_run(struct window_choose_data *cdata)
202: {
1.41 nicm 203: struct cmd_ctx *ctx;
1.33 nicm 204: struct cmd_list *cmdlist;
205: char *cause;
206:
207: /*
208: * The command template will have already been replaced. But if it's
209: * NULL, bail here.
210: */
211: if (cdata->command == NULL)
212: return;
213:
214: if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) {
215: if (cause != NULL) {
216: *cause = toupper((u_char) *cause);
217: status_message_set(cdata->start_client, "%s", cause);
218: free(cause);
219: }
220: return;
221: }
222:
1.41 nicm 223: ctx = cmd_get_ctx();
224: ctx->curclient = cdata->start_client;
225: ctx->error = key_bindings_error;
226: ctx->print = key_bindings_print;
227: ctx->info = key_bindings_info;
1.33 nicm 228:
1.41 nicm 229: cmd_list_exec(cmdlist, ctx);
1.33 nicm 230: cmd_list_free(cmdlist);
1.41 nicm 231: cmd_free_ctx(ctx);
1.33 nicm 232: }
233:
234: void
235: window_choose_default_callback(struct window_choose_data *wcd)
236: {
237: if (wcd == NULL)
238: return;
239: if (wcd->start_client->flags & CLIENT_DEAD)
240: return;
241:
242: window_choose_data_run(wcd);
243: }
244:
245: void
1.1 nicm 246: window_choose_free(struct window_pane *wp)
247: {
1.38 nicm 248: if (wp->modedata != NULL)
249: window_choose_free1(wp->modedata);
250: }
251:
252: void
253: window_choose_free1(struct window_choose_mode_data *data)
254: {
1.19 nicm 255: struct window_choose_mode_item *item;
1.1 nicm 256: u_int i;
257:
1.38 nicm 258: if (data == NULL)
259: return;
260:
1.28 nicm 261: for (i = 0; i < ARRAY_LENGTH(&data->old_list); i++) {
262: item = &ARRAY_ITEM(&data->old_list, i);
1.33 nicm 263: window_choose_data_free(item->wcd);
1.21 nicm 264: free(item->name);
1.19 nicm 265: }
1.1 nicm 266: ARRAY_FREE(&data->list);
1.27 nicm 267: ARRAY_FREE(&data->old_list);
1.22 nicm 268: free(data->input_str);
1.1 nicm 269:
270: screen_free(&data->screen);
1.21 nicm 271: free(data);
1.1 nicm 272: }
273:
274: void
275: window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
276: {
277: struct window_choose_mode_data *data = wp->modedata;
278: struct screen *s = &data->screen;
279:
280: data->top = 0;
281: if (data->selected > sy - 1)
282: data->top = data->selected - (sy - 1);
283:
1.32 nicm 284: screen_resize(s, sx, sy, 0);
1.1 nicm 285: window_choose_redraw_screen(wp);
286: }
287:
1.18 nicm 288: void
1.19 nicm 289: window_choose_fire_callback(
1.33 nicm 290: struct window_pane *wp, struct window_choose_data *wcd)
1.18 nicm 291: {
292: struct window_choose_mode_data *data = wp->modedata;
293:
1.38 nicm 294: wp->modedata = NULL;
295: window_pane_reset_mode(wp);
1.18 nicm 296:
1.19 nicm 297: data->callbackfn(wcd);
1.18 nicm 298:
1.38 nicm 299: window_choose_free1(data);
1.18 nicm 300: }
301:
1.22 nicm 302: void
303: window_choose_prompt_input(enum window_choose_input_type input_type,
304: const char *prompt, struct window_pane *wp, int key)
305: {
306: struct window_choose_mode_data *data = wp->modedata;
307: size_t input_len;
308:
309: data->input_type = input_type;
310: data->input_prompt = prompt;
311: input_len = strlen(data->input_str) + 2;
312:
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';
316:
317: window_choose_redraw_screen(wp);
318: }
319:
1.27 nicm 320: void
321: window_choose_collapse(struct window_pane *wp, struct session *s)
322: {
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;
327:
328: ARRAY_DECL(, struct window_choose_mode_item) list_copy;
329: ARRAY_INIT(&list_copy);
330:
331: pos = data->selected;
332:
333: chosen = &ARRAY_ITEM(&data->list, pos);
334: chosen->state &= ~TREE_EXPANDED;
335:
336: /*
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.
340: */
341: for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
342: {
343: item = &ARRAY_ITEM(&data->list, i);
344: wcd = item->wcd;
345:
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;
350:
351: ARRAY_ADD(&list_copy,
352: ARRAY_ITEM(&data->list, i));
353: /*
354: * Update the selection to this session item so
355: * we don't end up highlighting a non-existent
356: * item.
357: */
358: data->selected = i;
359: }
360: } else
361: ARRAY_ADD(&list_copy, ARRAY_ITEM(&data->list, i));
362: }
363:
364: if (!ARRAY_EMPTY(&list_copy)) {
365: ARRAY_FREE(&data->list);
366: ARRAY_CONCAT(&data->list, &list_copy);
1.28 nicm 367: ARRAY_FREE(&list_copy);
1.27 nicm 368: }
369: }
370:
371: void
372: window_choose_collapse_all(struct window_pane *wp)
373: {
374: struct window_choose_mode_data *data = wp->modedata;
1.28 nicm 375: struct window_choose_mode_item *item;
376: struct session *s, *chosen;
1.27 nicm 377: u_int i;
378:
1.33 nicm 379: chosen = ARRAY_ITEM(&data->list, data->selected).wcd->start_session;
1.27 nicm 380:
381: RB_FOREACH(s, sessions, &sessions)
382: window_choose_collapse(wp, s);
383:
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);
387:
1.28 nicm 388: if (chosen != item->wcd->tree_session)
1.27 nicm 389: continue;
390:
391: if (item->wcd->type & TREE_SESSION)
392: data->selected = i;
393: }
394: window_choose_redraw_screen(wp);
395: }
396:
397: void
398: window_choose_expand_all(struct window_pane *wp)
399: {
400: struct window_choose_mode_data *data = wp->modedata;
401: struct window_choose_mode_item *item;
402: struct session *s;
403: u_int i;
404:
405: RB_FOREACH(s, sessions, &sessions) {
406: for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
407: item = &ARRAY_ITEM(&data->list, i);
408:
409: if (s != item->wcd->tree_session)
410: continue;
411:
412: if (item->wcd->type & TREE_SESSION)
413: window_choose_expand(wp, s, i);
414: }
415: }
416:
417: window_choose_redraw_screen(wp);
418: }
419:
420: void
421: window_choose_expand(struct window_pane *wp, struct session *s, u_int pos)
422: {
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;
427:
428: chosen = &ARRAY_ITEM(&data->list, pos);
429: items = ARRAY_LENGTH(&data->old_list) - 1;
430:
431: /* It's not possible to expand anything other than sessions. */
432: if (!(chosen->wcd->type & TREE_SESSION))
433: return;
434:
435: /* Don't re-expand a session which is already expanded. */
436: if (chosen->state & TREE_EXPANDED)
437: return;
438:
439: /* Mark the session entry as expanded. */
440: chosen->state |= TREE_EXPANDED;
441:
442: /*
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.
446: */
447: for (i = items; i > 0; i--) {
448: item = &ARRAY_ITEM(&data->old_list, i);
449: item->state |= TREE_EXPANDED;
450: wcd = item->wcd;
451:
452: if (s == wcd->tree_session) {
453: /*
454: * Since the session is already displayed, we only care
455: * to add back in window for it.
456: */
457: if (wcd->type & TREE_WINDOW) {
458: /*
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.
464: */
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));
475: }
476: }
477: }
478: }
479: }
480:
1.1 nicm 481: void
1.16 nicm 482: window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
1.1 nicm 483: {
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;
1.22 nicm 488: size_t input_len;
1.27 nicm 489: u_int items, n;
1.11 nicm 490: int idx;
1.1 nicm 491:
492: items = ARRAY_LENGTH(&data->list);
493:
1.25 nicm 494: if (data->input_type == WINDOW_CHOOSE_GOTO_ITEM) {
495: switch (mode_key_lookup(&data->mdata, key)) {
496: case MODEKEYCHOICE_CANCEL:
497: data->input_type = WINDOW_CHOOSE_NORMAL;
498: window_choose_redraw_screen(wp);
1.22 nicm 499: break;
1.25 nicm 500: case MODEKEYCHOICE_CHOOSE:
1.22 nicm 501: n = strtonum(data->input_str, 0, INT_MAX, NULL);
1.25 nicm 502: if (n > items - 1) {
503: data->input_type = WINDOW_CHOOSE_NORMAL;
504: window_choose_redraw_screen(wp);
1.22 nicm 505: break;
1.25 nicm 506: }
1.22 nicm 507: item = &ARRAY_ITEM(&data->list, n);
508: window_choose_fire_callback(wp, item->wcd);
509: break;
1.25 nicm 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;
1.22 nicm 522: }
1.25 nicm 523: return;
524: }
525:
526: switch (mode_key_lookup(&data->mdata, key)) {
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);
1.1 nicm 533: break;
1.27 nicm 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);
541: }
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);
549: }
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);
560: }
561: break;
562: case MODEKEYCHOICE_TREE_EXPAND_ALL:
563: window_choose_expand_all(wp);
564: break;
1.5 nicm 565: case MODEKEYCHOICE_UP:
1.1 nicm 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;
574: }
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);
585: }
586: break;
1.5 nicm 587: case MODEKEYCHOICE_DOWN:
1.1 nicm 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;
595: }
596: data->selected++;
1.5 nicm 597:
1.15 nicm 598: if (data->selected < data->top + screen_size_y(s)) {
1.1 nicm 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);
1.15 nicm 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);
1.1 nicm 633: break;
1.5 nicm 634: case MODEKEYCHOICE_PAGEUP:
1.1 nicm 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);
644: }
1.13 nicm 645: window_choose_redraw_screen(wp);
1.1 nicm 646: break;
1.5 nicm 647: case MODEKEYCHOICE_PAGEDOWN:
1.1 nicm 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;
1.22 nicm 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:
1.25 nicm 668: key &= KEYC_MASK_KEY;
669: if (key < '0' || key > '9')
1.11 nicm 670: break;
1.25 nicm 671: window_choose_prompt_input(WINDOW_CHOOSE_GOTO_ITEM,
672: "Goto Item", wp, key);
1.22 nicm 673: break;
674: default:
1.25 nicm 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;
679:
680: item = &ARRAY_ITEM(&data->list, data->selected);
681: window_choose_fire_callback(wp, item->wcd);
1.1 nicm 682: break;
683: }
684: }
685:
686: void
1.10 nicm 687: window_choose_mouse(
1.16 nicm 688: struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
1.1 nicm 689: {
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;
694:
1.29 nicm 695: if (~m->event & MOUSE_EVENT_CLICK)
1.1 nicm 696: return;
1.10 nicm 697: if (m->x >= screen_size_x(s))
1.1 nicm 698: return;
1.10 nicm 699: if (m->y >= screen_size_y(s))
1.1 nicm 700: return;
701:
1.10 nicm 702: idx = data->top + m->y;
1.1 nicm 703: if (idx >= ARRAY_LENGTH(&data->list))
704: return;
705: data->selected = idx;
706:
707: item = &ARRAY_ITEM(&data->list, data->selected);
1.19 nicm 708: window_choose_fire_callback(wp, item->wcd);
1.1 nicm 709: }
710:
711: void
712: window_choose_write_line(
713: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
714: {
715: struct window_choose_mode_data *data = wp->modedata;
716: struct window_choose_mode_item *item;
1.9 nicm 717: struct options *oo = &wp->window->options;
1.1 nicm 718: struct screen *s = &data->screen;
719: struct grid_cell gc;
1.22 nicm 720: size_t last, xoff = 0;
1.25 nicm 721: char hdr[32], label[32];
722: int utf8flag, key;
1.1 nicm 723:
1.3 nicm 724: if (data->callbackfn == NULL)
1.1 nicm 725: fatalx("called before callback assigned");
726:
1.22 nicm 727: last = screen_size_y(s) - 1;
1.2 nicm 728: utf8flag = options_get_number(&wp->window->options, "utf8");
1.1 nicm 729: memcpy(&gc, &grid_default_cell, sizeof gc);
1.22 nicm 730: if (data->selected == data->top + py)
731: window_mode_attrs(&gc, oo);
1.1 nicm 732:
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);
1.24 nicm 736: if (item->wcd->wl != NULL &&
737: item->wcd->wl->flags & WINLINK_ALERTFLAGS)
738: gc.attr |= GRID_ATTR_BRIGHT;
1.11 nicm 739:
1.25 nicm 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,
1.27 nicm 746: "%*s %s %s", data->width + 2, label,
747: /*
748: * Add indication to tree if necessary about whether it's
749: * expanded or not.
750: */
751: (item->wcd->type & TREE_SESSION) ?
752: (item->state & TREE_EXPANDED ? "-" : "+") : "", item->name);
1.1 nicm 753: }
1.40 nicm 754: while (s->cx < screen_size_x(s) - 1)
1.1 nicm 755: screen_write_putc(ctx, &gc, ' ');
1.11 nicm 756:
1.22 nicm 757: if (data->input_type != WINDOW_CHOOSE_NORMAL) {
758: window_mode_attrs(&gc, oo);
1.11 nicm 759:
1.22 nicm 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);
1.11 nicm 766: }
1.22 nicm 767:
1.11 nicm 768: }
769:
770: int
1.25 nicm 771: window_choose_key_index(struct window_choose_mode_data *data, u_int idx)
772: {
773: static const char keys[] = "0123456789"
774: "abcdefghijklmnopqrstuvwxyz"
775: "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
776: const char *ptr;
777: int mkey;
778:
779: for (ptr = keys; *ptr != '\0'; ptr++) {
780: mkey = mode_key_lookup(&data->mdata, *ptr);
781: if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
782: continue;
783: if (idx-- == 0)
784: return (*ptr);
785: }
786: return (-1);
787: }
788:
789: int
790: window_choose_index_key(struct window_choose_mode_data *data, int key)
1.11 nicm 791: {
1.25 nicm 792: static const char keys[] = "0123456789"
793: "abcdefghijklmnopqrstuvwxyz"
794: "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1.11 nicm 795: const char *ptr;
1.25 nicm 796: int mkey;
1.11 nicm 797: u_int idx = 0;
798:
799: for (ptr = keys; *ptr != '\0'; ptr++) {
1.25 nicm 800: mkey = mode_key_lookup(&data->mdata, *ptr);
801: if (mkey != MODEKEY_NONE && mkey != MODEKEY_OTHER)
802: continue;
1.11 nicm 803: if (key == *ptr)
804: return (idx);
805: idx++;
806: }
807: return (-1);
1.1 nicm 808: }
809:
810: void
811: window_choose_redraw_screen(struct window_pane *wp)
812: {
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;
817:
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);
822: }
823:
824: void
825: window_choose_scroll_up(struct window_pane *wp)
826: {
827: struct window_choose_mode_data *data = wp->modedata;
828: struct screen_write_ctx ctx;
829:
830: if (data->top == 0)
831: return;
832: data->top--;
833:
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);
841: }
842:
843: void
844: window_choose_scroll_down(struct window_pane *wp)
845: {
846: struct window_choose_mode_data *data = wp->modedata;
847: struct screen *s = &data->screen;
848: struct screen_write_ctx ctx;
849:
850: if (data->top >= ARRAY_LENGTH(&data->list))
851: return;
852: data->top++;
853:
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);
1.19 nicm 861: }
862:
1.20 nicm 863: struct window_choose_data *
1.35 nicm 864: window_choose_add_session(struct window_pane *wp, struct client *c,
1.36 nicm 865: struct session *s, const char *template, const char *action, u_int idx)
1.20 nicm 866: {
867: struct window_choose_data *wcd;
868:
1.33 nicm 869: wcd = window_choose_data_create(TREE_SESSION, c, c->session);
1.20 nicm 870: wcd->idx = s->idx;
1.33 nicm 871:
1.27 nicm 872: wcd->tree_session = s;
1.33 nicm 873: wcd->tree_session->references++;
874:
1.20 nicm 875: wcd->ft_template = xstrdup(template);
876: format_add(wcd->ft, "line", "%u", idx);
877: format_session(wcd->ft, s);
878:
1.33 nicm 879: wcd->command = cmd_template_replace(action, s->name, 1);
1.20 nicm 880:
881: window_choose_add(wp, wcd);
882:
883: return (wcd);
1.26 nicm 884: }
885:
886: struct window_choose_data *
1.35 nicm 887: window_choose_add_item(struct window_pane *wp, struct client *c,
1.36 nicm 888: struct winlink *wl, const char *template, const char *action, u_int idx)
1.26 nicm 889: {
890: struct window_choose_data *wcd;
1.33 nicm 891: char *expanded;
1.26 nicm 892:
1.33 nicm 893: wcd = window_choose_data_create(TREE_OTHER, c, c->session);
1.26 nicm 894: wcd->idx = wl->idx;
1.33 nicm 895:
1.26 nicm 896: wcd->ft_template = xstrdup(template);
897: format_add(wcd->ft, "line", "%u", idx);
1.33 nicm 898: format_session(wcd->ft, wcd->start_session);
899: format_winlink(wcd->ft, wcd->start_session, wl);
1.26 nicm 900: format_window_pane(wcd->ft, wl->window->active);
901:
1.33 nicm 902: /*
903: * Interpolate action here, since the data we pass back is the expanded
904: * template itself.
905: */
906: xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template));
907: wcd->command = cmd_template_replace(action, expanded, 1);
908: free(expanded);
1.26 nicm 909:
910: window_choose_add(wp, wcd);
911:
912: return (wcd);
913:
1.20 nicm 914: }
915:
916: struct window_choose_data *
1.35 nicm 917: window_choose_add_window(struct window_pane *wp, struct client *c,
1.22 nicm 918: struct session *s, struct winlink *wl, const char *template,
1.36 nicm 919: const char *action, u_int idx)
1.20 nicm 920: {
921: struct window_choose_data *wcd;
1.33 nicm 922: char *expanded;
1.20 nicm 923:
1.33 nicm 924: wcd = window_choose_data_create(TREE_WINDOW, c, c->session);
925: wcd->idx = wl->idx;
1.20 nicm 926:
1.33 nicm 927: wcd->wl = wl;
1.20 nicm 928:
1.27 nicm 929: wcd->tree_session = s;
1.33 nicm 930: wcd->tree_session->references++;
931:
1.20 nicm 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);
937:
1.33 nicm 938: xasprintf(&expanded, "%s:%d", s->name, wl->idx);
939: wcd->command = cmd_template_replace(action, expanded, 1);
940: free(expanded);
1.20 nicm 941:
942: window_choose_add(wp, wcd);
943:
944: return (wcd);
1.1 nicm 945: }