Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.47
1.47 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.46 2013/03/25 10:11:45 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:
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 *);
1.1 nicm 77: };
78:
1.38 nicm 79: void window_choose_free1(struct window_choose_mode_data *);
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.47 ! nicm 104: window_choose_set_current(struct window_pane *wp, u_int cur)
1.1 nicm 105: {
106: struct window_choose_mode_data *data = wp->modedata;
107: struct screen *s = &data->screen;
108:
109: data->selected = cur;
110: if (data->selected > screen_size_y(s) - 1)
111: data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
112:
1.47 ! nicm 113: window_choose_redraw_screen(wp);
! 114: }
! 115:
! 116: void
! 117: window_choose_ready(struct window_pane *wp, u_int cur,
! 118: void (*callbackfn)(struct window_choose_data *))
! 119: {
! 120: struct window_choose_mode_data *data = wp->modedata;
! 121:
1.3 nicm 122: data->callbackfn = callbackfn;
1.33 nicm 123: if (data->callbackfn == NULL)
124: data->callbackfn = window_choose_default_callback;
1.1 nicm 125:
1.27 nicm 126: ARRAY_CONCAT(&data->old_list, &data->list);
127:
1.47 ! nicm 128: window_choose_set_current(wp, cur);
1.27 nicm 129: window_choose_collapse_all(wp);
1.1 nicm 130: }
131:
132: struct screen *
133: window_choose_init(struct window_pane *wp)
134: {
135: struct window_choose_mode_data *data;
136: struct screen *s;
1.5 nicm 137: int keys;
1.1 nicm 138:
139: wp->modedata = data = xmalloc(sizeof *data);
1.3 nicm 140:
141: data->callbackfn = NULL;
1.22 nicm 142: data->input_type = WINDOW_CHOOSE_NORMAL;
143: data->input_str = xstrdup("");
144: data->input_prompt = NULL;
1.3 nicm 145:
1.1 nicm 146: ARRAY_INIT(&data->list);
1.27 nicm 147: ARRAY_INIT(&data->old_list);
1.1 nicm 148: data->top = 0;
149:
150: s = &data->screen;
151: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
152: s->mode &= ~MODE_CURSOR;
1.7 nicm 153: if (options_get_number(&wp->window->options, "mode-mouse"))
1.17 nicm 154: s->mode |= MODE_MOUSE_STANDARD;
1.1 nicm 155:
1.5 nicm 156: keys = options_get_number(&wp->window->options, "mode-keys");
157: if (keys == MODEKEY_EMACS)
1.6 nicm 158: mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
1.5 nicm 159: else
1.6 nicm 160: mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
1.1 nicm 161:
162: return (s);
163: }
164:
1.19 nicm 165: struct window_choose_data *
1.33 nicm 166: window_choose_data_create(int type, struct client *c, struct session *s)
1.19 nicm 167: {
168: struct window_choose_data *wcd;
169:
170: wcd = xmalloc(sizeof *wcd);
1.33 nicm 171: wcd->type = type;
172:
1.19 nicm 173: wcd->ft = format_create();
174: wcd->ft_template = NULL;
1.33 nicm 175:
1.20 nicm 176: wcd->command = NULL;
1.33 nicm 177:
1.24 nicm 178: wcd->wl = NULL;
1.33 nicm 179: wcd->pane_id = -1;
180: wcd->idx = -1;
181:
1.27 nicm 182: wcd->tree_session = NULL;
1.33 nicm 183:
184: wcd->start_client = c;
185: wcd->start_client->references++;
186: wcd->start_session = s;
187: wcd->start_session->references++;
1.19 nicm 188:
189: return (wcd);
190: }
191:
1.1 nicm 192: void
1.33 nicm 193: window_choose_data_free(struct window_choose_data *wcd)
194: {
195: wcd->start_client->references--;
196: wcd->start_session->references--;
197:
198: if (wcd->tree_session != NULL)
199: wcd->tree_session->references--;
200:
201: free(wcd->ft_template);
202: format_free(wcd->ft);
203:
204: free(wcd->command);
205: free(wcd);
206: }
207:
208: void
209: window_choose_data_run(struct window_choose_data *cdata)
210: {
1.45 nicm 211: struct cmd_list *cmdlist;
212: char *cause;
1.33 nicm 213:
214: /*
215: * The command template will have already been replaced. But if it's
216: * NULL, bail here.
217: */
218: if (cdata->command == NULL)
219: return;
220:
1.45 nicm 221: if (cmd_string_parse(cdata->command, &cmdlist, NULL, 0, &cause) != 0) {
1.33 nicm 222: if (cause != NULL) {
223: *cause = toupper((u_char) *cause);
224: status_message_set(cdata->start_client, "%s", cause);
225: free(cause);
226: }
227: return;
228: }
229:
1.45 nicm 230: cmdq_run(cdata->start_client->cmdq, cmdlist);
1.33 nicm 231: cmd_list_free(cmdlist);
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) {
1.43 nicm 495: switch (mode_key_lookup(&data->mdata, key, NULL)) {
1.25 nicm 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:
1.43 nicm 526: switch (mode_key_lookup(&data->mdata, key, NULL)) {
1.25 nicm 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++) {
1.43 nicm 780: mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
1.25 nicm 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.43 nicm 800: mkey = mode_key_lookup(&data->mdata, *ptr, NULL);
1.25 nicm 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.46 nicm 870: wcd->idx = s->id;
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: }