xref: /minix3/external/bsd/tmux/dist/cmd-choose-tree.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* Id */
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
5*0a6a1f1dSLionel Sambuc  *
6*0a6a1f1dSLionel Sambuc  * Permission to use, copy, modify, and distribute this software for any
7*0a6a1f1dSLionel Sambuc  * purpose with or without fee is hereby granted, provided that the above
8*0a6a1f1dSLionel Sambuc  * copyright notice and this permission notice appear in all copies.
9*0a6a1f1dSLionel Sambuc  *
10*0a6a1f1dSLionel Sambuc  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*0a6a1f1dSLionel Sambuc  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*0a6a1f1dSLionel Sambuc  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*0a6a1f1dSLionel Sambuc  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*0a6a1f1dSLionel Sambuc  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*0a6a1f1dSLionel Sambuc  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*0a6a1f1dSLionel Sambuc  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*0a6a1f1dSLionel Sambuc  */
18*0a6a1f1dSLionel Sambuc 
19*0a6a1f1dSLionel Sambuc #include <sys/types.h>
20*0a6a1f1dSLionel Sambuc 
21*0a6a1f1dSLionel Sambuc #include <ctype.h>
22*0a6a1f1dSLionel Sambuc #include <stdlib.h>
23*0a6a1f1dSLionel Sambuc 
24*0a6a1f1dSLionel Sambuc #include <string.h>
25*0a6a1f1dSLionel Sambuc 
26*0a6a1f1dSLionel Sambuc #include "tmux.h"
27*0a6a1f1dSLionel Sambuc 
28*0a6a1f1dSLionel Sambuc #define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'"
29*0a6a1f1dSLionel Sambuc #define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'"
30*0a6a1f1dSLionel Sambuc 
31*0a6a1f1dSLionel Sambuc /*
32*0a6a1f1dSLionel Sambuc  * Enter choice mode to choose a session and/or window.
33*0a6a1f1dSLionel Sambuc  */
34*0a6a1f1dSLionel Sambuc 
35*0a6a1f1dSLionel Sambuc enum cmd_retval	cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
36*0a6a1f1dSLionel Sambuc 
37*0a6a1f1dSLionel Sambuc const struct cmd_entry cmd_choose_tree_entry = {
38*0a6a1f1dSLionel Sambuc 	"choose-tree", NULL,
39*0a6a1f1dSLionel Sambuc 	"S:W:swub:c:t:", 0, 1,
40*0a6a1f1dSLionel Sambuc 	"[-suw] [-b session-template] [-c window template] [-S format] " \
41*0a6a1f1dSLionel Sambuc 	"[-W format] " CMD_TARGET_WINDOW_USAGE,
42*0a6a1f1dSLionel Sambuc 	0,
43*0a6a1f1dSLionel Sambuc 	NULL,
44*0a6a1f1dSLionel Sambuc 	cmd_choose_tree_exec
45*0a6a1f1dSLionel Sambuc };
46*0a6a1f1dSLionel Sambuc 
47*0a6a1f1dSLionel Sambuc const struct cmd_entry cmd_choose_session_entry = {
48*0a6a1f1dSLionel Sambuc 	"choose-session", NULL,
49*0a6a1f1dSLionel Sambuc 	"F:t:", 0, 1,
50*0a6a1f1dSLionel Sambuc 	CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
51*0a6a1f1dSLionel Sambuc 	0,
52*0a6a1f1dSLionel Sambuc 	NULL,
53*0a6a1f1dSLionel Sambuc 	cmd_choose_tree_exec
54*0a6a1f1dSLionel Sambuc };
55*0a6a1f1dSLionel Sambuc 
56*0a6a1f1dSLionel Sambuc const struct cmd_entry cmd_choose_window_entry = {
57*0a6a1f1dSLionel Sambuc 	"choose-window", NULL,
58*0a6a1f1dSLionel Sambuc 	"F:t:", 0, 1,
59*0a6a1f1dSLionel Sambuc 	CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
60*0a6a1f1dSLionel Sambuc 	0,
61*0a6a1f1dSLionel Sambuc 	NULL,
62*0a6a1f1dSLionel Sambuc 	cmd_choose_tree_exec
63*0a6a1f1dSLionel Sambuc };
64*0a6a1f1dSLionel Sambuc 
65*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_choose_tree_exec(struct cmd * self,struct cmd_q * cmdq)66*0a6a1f1dSLionel Sambuc cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
67*0a6a1f1dSLionel Sambuc {
68*0a6a1f1dSLionel Sambuc 	struct args			*args = self->args;
69*0a6a1f1dSLionel Sambuc 	struct winlink			*wl, *wm;
70*0a6a1f1dSLionel Sambuc 	struct session			*s, *s2;
71*0a6a1f1dSLionel Sambuc 	struct client			*c;
72*0a6a1f1dSLionel Sambuc 	struct window_choose_data	*wcd = NULL;
73*0a6a1f1dSLionel Sambuc 	const char			*ses_template, *win_template;
74*0a6a1f1dSLionel Sambuc 	char				*final_win_action, *cur_win_template;
75*0a6a1f1dSLionel Sambuc 	char				*final_win_template_middle;
76*0a6a1f1dSLionel Sambuc 	char				*final_win_template_last;
77*0a6a1f1dSLionel Sambuc 	const char			*ses_action, *win_action;
78*0a6a1f1dSLionel Sambuc 	u_int				 cur_win, idx_ses, win_ses, win_max;
79*0a6a1f1dSLionel Sambuc 	u_int				 wflag, sflag;
80*0a6a1f1dSLionel Sambuc 
81*0a6a1f1dSLionel Sambuc 	ses_template = win_template = NULL;
82*0a6a1f1dSLionel Sambuc 	ses_action = win_action = NULL;
83*0a6a1f1dSLionel Sambuc 
84*0a6a1f1dSLionel Sambuc 	if ((c = cmd_current_client(cmdq)) == NULL) {
85*0a6a1f1dSLionel Sambuc 		cmdq_error(cmdq, "no client available");
86*0a6a1f1dSLionel Sambuc 		return (CMD_RETURN_ERROR);
87*0a6a1f1dSLionel Sambuc 	}
88*0a6a1f1dSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc 	if ((wl = cmd_find_window(cmdq, args_get(args, 't'), &s)) == NULL)
90*0a6a1f1dSLionel Sambuc 		return (CMD_RETURN_ERROR);
91*0a6a1f1dSLionel Sambuc 
92*0a6a1f1dSLionel Sambuc 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
93*0a6a1f1dSLionel Sambuc 		return (CMD_RETURN_NORMAL);
94*0a6a1f1dSLionel Sambuc 
95*0a6a1f1dSLionel Sambuc 	/* Sort out which command this is. */
96*0a6a1f1dSLionel Sambuc 	wflag = sflag = 0;
97*0a6a1f1dSLionel Sambuc 	if (self->entry == &cmd_choose_session_entry) {
98*0a6a1f1dSLionel Sambuc 		sflag = 1;
99*0a6a1f1dSLionel Sambuc 		if ((ses_template = args_get(args, 'F')) == NULL)
100*0a6a1f1dSLionel Sambuc 			ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
101*0a6a1f1dSLionel Sambuc 
102*0a6a1f1dSLionel Sambuc 		if (args->argc != 0)
103*0a6a1f1dSLionel Sambuc 			ses_action = args->argv[0];
104*0a6a1f1dSLionel Sambuc 		else
105*0a6a1f1dSLionel Sambuc 			ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
106*0a6a1f1dSLionel Sambuc 	} else if (self->entry == &cmd_choose_window_entry) {
107*0a6a1f1dSLionel Sambuc 		wflag = 1;
108*0a6a1f1dSLionel Sambuc 		if ((win_template = args_get(args, 'F')) == NULL)
109*0a6a1f1dSLionel Sambuc 			win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
110*0a6a1f1dSLionel Sambuc 
111*0a6a1f1dSLionel Sambuc 		if (args->argc != 0)
112*0a6a1f1dSLionel Sambuc 			win_action = args->argv[0];
113*0a6a1f1dSLionel Sambuc 		else
114*0a6a1f1dSLionel Sambuc 			win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
115*0a6a1f1dSLionel Sambuc 	} else {
116*0a6a1f1dSLionel Sambuc 		wflag = args_has(args, 'w');
117*0a6a1f1dSLionel Sambuc 		sflag = args_has(args, 's');
118*0a6a1f1dSLionel Sambuc 
119*0a6a1f1dSLionel Sambuc 		if ((ses_action = args_get(args, 'b')) == NULL)
120*0a6a1f1dSLionel Sambuc 			ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
121*0a6a1f1dSLionel Sambuc 
122*0a6a1f1dSLionel Sambuc 		if ((win_action = args_get(args, 'c')) == NULL)
123*0a6a1f1dSLionel Sambuc 			win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
124*0a6a1f1dSLionel Sambuc 
125*0a6a1f1dSLionel Sambuc 		if ((ses_template = args_get(args, 'S')) == NULL)
126*0a6a1f1dSLionel Sambuc 			ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
127*0a6a1f1dSLionel Sambuc 
128*0a6a1f1dSLionel Sambuc 		if ((win_template = args_get(args, 'W')) == NULL)
129*0a6a1f1dSLionel Sambuc 			win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
130*0a6a1f1dSLionel Sambuc 	}
131*0a6a1f1dSLionel Sambuc 
132*0a6a1f1dSLionel Sambuc 	/*
133*0a6a1f1dSLionel Sambuc 	 * If not asking for windows and sessions, assume no "-ws" given and
134*0a6a1f1dSLionel Sambuc 	 * hence display the entire tree outright.
135*0a6a1f1dSLionel Sambuc 	 */
136*0a6a1f1dSLionel Sambuc 	if (!wflag && !sflag)
137*0a6a1f1dSLionel Sambuc 		wflag = sflag = 1;
138*0a6a1f1dSLionel Sambuc 
139*0a6a1f1dSLionel Sambuc 	/*
140*0a6a1f1dSLionel Sambuc 	 * If we're drawing in tree mode, including sessions, then pad the
141*0a6a1f1dSLionel Sambuc 	 * window template, otherwise just render the windows as a flat list
142*0a6a1f1dSLionel Sambuc 	 * without any padding.
143*0a6a1f1dSLionel Sambuc 	 */
144*0a6a1f1dSLionel Sambuc 	if (wflag && sflag) {
145*0a6a1f1dSLionel Sambuc 		xasprintf(&final_win_template_middle,
146*0a6a1f1dSLionel Sambuc 		    " \001tq\001> %s", win_template);
147*0a6a1f1dSLionel Sambuc 		xasprintf(&final_win_template_last,
148*0a6a1f1dSLionel Sambuc 		    " \001mq\001> %s", win_template);
149*0a6a1f1dSLionel Sambuc 	} else if (wflag) {
150*0a6a1f1dSLionel Sambuc 		final_win_template_middle = xstrdup(win_template);
151*0a6a1f1dSLionel Sambuc 		final_win_template_last = xstrdup(win_template);
152*0a6a1f1dSLionel Sambuc 	} else
153*0a6a1f1dSLionel Sambuc 		final_win_template_middle = final_win_template_last = NULL;
154*0a6a1f1dSLionel Sambuc 
155*0a6a1f1dSLionel Sambuc 	idx_ses = cur_win = -1;
156*0a6a1f1dSLionel Sambuc 	RB_FOREACH(s2, sessions, &sessions) {
157*0a6a1f1dSLionel Sambuc 		idx_ses++;
158*0a6a1f1dSLionel Sambuc 
159*0a6a1f1dSLionel Sambuc 		/*
160*0a6a1f1dSLionel Sambuc 		 * If we're just choosing windows, jump straight there. Note
161*0a6a1f1dSLionel Sambuc 		 * that this implies the current session, so only choose
162*0a6a1f1dSLionel Sambuc 		 * windows when the session matches this one.
163*0a6a1f1dSLionel Sambuc 		 */
164*0a6a1f1dSLionel Sambuc 		if (wflag && !sflag) {
165*0a6a1f1dSLionel Sambuc 			if (s != s2)
166*0a6a1f1dSLionel Sambuc 				continue;
167*0a6a1f1dSLionel Sambuc 			goto windows_only;
168*0a6a1f1dSLionel Sambuc 		}
169*0a6a1f1dSLionel Sambuc 
170*0a6a1f1dSLionel Sambuc 		wcd = window_choose_add_session(wl->window->active,
171*0a6a1f1dSLionel Sambuc 		    c, s2, ses_template, ses_action, idx_ses);
172*0a6a1f1dSLionel Sambuc 
173*0a6a1f1dSLionel Sambuc 		/* If we're just choosing sessions, skip choosing windows. */
174*0a6a1f1dSLionel Sambuc 		if (sflag && !wflag) {
175*0a6a1f1dSLionel Sambuc 			if (s == s2)
176*0a6a1f1dSLionel Sambuc 				cur_win = idx_ses;
177*0a6a1f1dSLionel Sambuc 			continue;
178*0a6a1f1dSLionel Sambuc 		}
179*0a6a1f1dSLionel Sambuc windows_only:
180*0a6a1f1dSLionel Sambuc 		win_ses = win_max = -1;
181*0a6a1f1dSLionel Sambuc 		RB_FOREACH(wm, winlinks, &s2->windows)
182*0a6a1f1dSLionel Sambuc 			win_max++;
183*0a6a1f1dSLionel Sambuc 		RB_FOREACH(wm, winlinks, &s2->windows) {
184*0a6a1f1dSLionel Sambuc 			win_ses++;
185*0a6a1f1dSLionel Sambuc 			if (sflag && wflag)
186*0a6a1f1dSLionel Sambuc 				idx_ses++;
187*0a6a1f1dSLionel Sambuc 
188*0a6a1f1dSLionel Sambuc 			if (wm == s2->curw && s == s2) {
189*0a6a1f1dSLionel Sambuc 				if (wflag && !sflag) {
190*0a6a1f1dSLionel Sambuc 					/*
191*0a6a1f1dSLionel Sambuc 					 * Then we're only counting windows.
192*0a6a1f1dSLionel Sambuc 					 * So remember which is the current
193*0a6a1f1dSLionel Sambuc 					 * window in the list.
194*0a6a1f1dSLionel Sambuc 					 */
195*0a6a1f1dSLionel Sambuc 					cur_win = win_ses;
196*0a6a1f1dSLionel Sambuc 				} else
197*0a6a1f1dSLionel Sambuc 					cur_win = idx_ses;
198*0a6a1f1dSLionel Sambuc 			}
199*0a6a1f1dSLionel Sambuc 
200*0a6a1f1dSLionel Sambuc 			xasprintf(&final_win_action, "%s %s %s",
201*0a6a1f1dSLionel Sambuc 			    wcd != NULL ? wcd->command : "",
202*0a6a1f1dSLionel Sambuc 			    wcd != NULL ? ";" : "", win_action);
203*0a6a1f1dSLionel Sambuc 
204*0a6a1f1dSLionel Sambuc 			if (win_ses != win_max)
205*0a6a1f1dSLionel Sambuc 				cur_win_template = final_win_template_middle;
206*0a6a1f1dSLionel Sambuc 			else
207*0a6a1f1dSLionel Sambuc 				cur_win_template = final_win_template_last;
208*0a6a1f1dSLionel Sambuc 
209*0a6a1f1dSLionel Sambuc 			window_choose_add_window(wl->window->active,
210*0a6a1f1dSLionel Sambuc 			    c, s2, wm, cur_win_template,
211*0a6a1f1dSLionel Sambuc 			    final_win_action,
212*0a6a1f1dSLionel Sambuc 			    (wflag && !sflag) ? win_ses : idx_ses);
213*0a6a1f1dSLionel Sambuc 
214*0a6a1f1dSLionel Sambuc 			free(final_win_action);
215*0a6a1f1dSLionel Sambuc 		}
216*0a6a1f1dSLionel Sambuc 
217*0a6a1f1dSLionel Sambuc 		/*
218*0a6a1f1dSLionel Sambuc 		 * If we're just drawing windows, don't consider moving on to
219*0a6a1f1dSLionel Sambuc 		 * other sessions as we only list windows in this session.
220*0a6a1f1dSLionel Sambuc 		 */
221*0a6a1f1dSLionel Sambuc 		if (wflag && !sflag)
222*0a6a1f1dSLionel Sambuc 			break;
223*0a6a1f1dSLionel Sambuc 	}
224*0a6a1f1dSLionel Sambuc 	free(final_win_template_middle);
225*0a6a1f1dSLionel Sambuc 	free(final_win_template_last);
226*0a6a1f1dSLionel Sambuc 
227*0a6a1f1dSLionel Sambuc 	window_choose_ready(wl->window->active, cur_win, NULL);
228*0a6a1f1dSLionel Sambuc 
229*0a6a1f1dSLionel Sambuc 	if (args_has(args, 'u')) {
230*0a6a1f1dSLionel Sambuc 		window_choose_expand_all(wl->window->active);
231*0a6a1f1dSLionel Sambuc 		window_choose_set_current(wl->window->active, cur_win);
232*0a6a1f1dSLionel Sambuc 	}
233*0a6a1f1dSLionel Sambuc 
234*0a6a1f1dSLionel Sambuc 	return (CMD_RETURN_NORMAL);
235*0a6a1f1dSLionel Sambuc }
236