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