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