xref: /netbsd-src/external/bsd/tmux/dist/cmd-find-window.c (revision 4fee23f98c45552038ad6b5bd05124a41302fb01)
1 /* $Id: cmd-find-window.c,v 1.1.1.1 2011/03/10 09:15:37 jmmv Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <fnmatch.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Find window containing text.
28  */
29 
30 int	cmd_find_window_exec(struct cmd *, struct cmd_ctx *);
31 
32 void	cmd_find_window_callback(void *, int);
33 void	cmd_find_window_free(void *);
34 
35 const struct cmd_entry cmd_find_window_entry = {
36 	"find-window", "findw",
37 	CMD_TARGET_WINDOW_USAGE " match-string",
38 	CMD_ARG1, "",
39 	cmd_target_init,
40 	cmd_target_parse,
41 	cmd_find_window_exec,
42 	cmd_target_free,
43 	cmd_target_print
44 };
45 
46 struct cmd_find_window_data {
47 	struct session	*session;
48 };
49 
50 int
51 cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
52 {
53 	struct cmd_target_data		*data = self->data;
54 	struct cmd_find_window_data	*cdata;
55 	struct session			*s;
56 	struct winlink			*wl, *wm;
57 	struct window			*w;
58 	struct window_pane		*wp;
59 	ARRAY_DECL(, u_int)	 	 list_idx;
60 	ARRAY_DECL(, char *)	 	 list_ctx;
61 	char				*sres, *sctx, *searchstr;
62 	u_int				 i, line;
63 
64 	if (ctx->curclient == NULL) {
65 		ctx->error(ctx, "must be run interactively");
66 		return (-1);
67 	}
68 	s = ctx->curclient->session;
69 
70 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
71 		return (-1);
72 
73 	ARRAY_INIT(&list_idx);
74 	ARRAY_INIT(&list_ctx);
75 
76 	xasprintf(&searchstr, "*%s*", data->arg);
77 	RB_FOREACH(wm, winlinks, &s->windows) {
78 		i = 0;
79 		TAILQ_FOREACH(wp, &wm->window->panes, entry) {
80 			i++;
81 
82 			if (fnmatch(searchstr, wm->window->name, 0) == 0)
83 				sctx = xstrdup("");
84 			else {
85 				sres = window_pane_search(wp, data->arg, &line);
86 				if (sres == NULL &&
87 				    fnmatch(searchstr, wp->base.title, 0) != 0)
88 					continue;
89 
90 				if (sres == NULL) {
91 					xasprintf(&sctx,
92 					    "pane %u title: \"%s\"", i - 1,
93 					    wp->base.title);
94 				} else {
95 					xasprintf(&sctx,
96 					    "pane %u line %u: \"%s\"", i - 1,
97 					    line + 1, sres);
98 					xfree(sres);
99 				}
100 			}
101 
102 			ARRAY_ADD(&list_idx, wm->idx);
103 			ARRAY_ADD(&list_ctx, sctx);
104 		}
105 	}
106 	xfree(searchstr);
107 
108 	if (ARRAY_LENGTH(&list_idx) == 0) {
109 		ctx->error(ctx, "no windows matching: %s", data->arg);
110 		ARRAY_FREE(&list_idx);
111 		ARRAY_FREE(&list_ctx);
112 		return (-1);
113 	}
114 
115 	if (ARRAY_LENGTH(&list_idx) == 1) {
116 		if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
117 			server_redraw_session(s);
118 		recalculate_sizes();
119 		goto out;
120 	}
121 
122 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
123 		goto out;
124 
125 	for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
126 		wm = winlink_find_by_index(
127 		    &s->windows, ARRAY_ITEM(&list_idx, i));
128 		w = wm->window;
129 
130 		sctx = ARRAY_ITEM(&list_ctx, i);
131 		window_choose_add(wl->window->active,
132 		    wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
133 		    w->sx, w->sy, window_count_panes(w), sctx);
134 		xfree(sctx);
135 	}
136 
137 	cdata = xmalloc(sizeof *cdata);
138 	cdata->session = s;
139 	cdata->session->references++;
140 
141 	window_choose_ready(wl->window->active,
142 	    0, cmd_find_window_callback, cmd_find_window_free, cdata);
143 
144 out:
145 	ARRAY_FREE(&list_idx);
146 	ARRAY_FREE(&list_ctx);
147 
148 	return (0);
149 }
150 
151 void
152 cmd_find_window_callback(void *data, int idx)
153 {
154 	struct cmd_find_window_data	*cdata = data;
155 	struct session			*s = cdata->session;
156 
157 	if (idx == -1)
158 		return;
159 	if (!session_alive(s))
160 		return;
161 
162 	if (session_select(s, idx) == 0) {
163 		server_redraw_session(s);
164 		recalculate_sizes();
165 	}
166 }
167 
168 void
169 cmd_find_window_free(void *data)
170 {
171 	struct cmd_find_window_data	*cdata = data;
172 
173 	cdata->session->references--;
174 	xfree(cdata);
175 }
176