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