xref: /minix3/external/bsd/tmux/dist/window-choose.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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