xref: /openbsd-src/usr.bin/tmux/cmd-find-window.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /* $OpenBSD: cmd-find-window.c,v 1.5 2009/07/26 12:58:44 nicm 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 
34 const struct cmd_entry cmd_find_window_entry = {
35 	"find-window", "findw",
36 	CMD_TARGET_WINDOW_USAGE " match-string",
37 	CMD_ARG1, 0,
38 	cmd_target_init,
39 	cmd_target_parse,
40 	cmd_find_window_exec,
41 	cmd_target_free,
42 	cmd_target_print
43 };
44 
45 struct cmd_find_window_data {
46 	u_int	session;
47 };
48 
49 int
50 cmd_find_window_exec(struct cmd *self, struct cmd_ctx *ctx)
51 {
52 	struct cmd_target_data		*data = self->data;
53 	struct cmd_find_window_data	*cdata;
54 	struct session			*s;
55 	struct winlink			*wl, *wm;
56 	struct window			*w;
57 	struct window_pane		*wp;
58 	ARRAY_DECL(, u_int)	 	 list_idx;
59 	ARRAY_DECL(, char *)	 	 list_ctx;
60 	char				*sres, *sctx, *searchstr;
61 	u_int				 i, line;
62 
63 	if (ctx->curclient == NULL) {
64 		ctx->error(ctx, "must be run interactively");
65 		return (-1);
66 	}
67 	s = ctx->curclient->session;
68 
69 	if ((wl = cmd_find_window(ctx, data->target, NULL)) == NULL)
70 		return (-1);
71 
72 	ARRAY_INIT(&list_idx);
73 	ARRAY_INIT(&list_ctx);
74 
75 	xasprintf(&searchstr, "*%s*", data->arg);
76 	RB_FOREACH(wm, winlinks, &s->windows) {
77 		i = 0;
78 		TAILQ_FOREACH(wp, &wm->window->panes, entry) {
79 			i++;
80 
81 			if (fnmatch(searchstr, wm->window->name, 0) == 0)
82 				sctx = xstrdup("");
83 			else {
84 				sres = window_pane_search(wp, data->arg, &line);
85 				if (sres == NULL &&
86 				    fnmatch(searchstr, wp->base.title, 0) != 0)
87 					continue;
88 
89 				if (sres == NULL) {
90 					xasprintf(&sctx,
91 					    "pane %u title: \"%s\"", i - 1,
92 					    wp->base.title);
93 				} else {
94 					xasprintf(&sctx,
95 					    "pane %u line %u: \"%s\"", i - 1,
96 					    line + 1, sres);
97 					xfree(sres);
98 				}
99 			}
100 
101 			ARRAY_ADD(&list_idx, wm->idx);
102 			ARRAY_ADD(&list_ctx, sctx);
103 		}
104 	}
105 	xfree(searchstr);
106 
107 	if (ARRAY_LENGTH(&list_idx) == 0) {
108 		ctx->error(ctx, "no windows matching: %s", data->arg);
109 		ARRAY_FREE(&list_idx);
110 		ARRAY_FREE(&list_ctx);
111 		return (-1);
112 	}
113 
114 	if (ARRAY_LENGTH(&list_idx) == 1) {
115 		if (session_select(s, ARRAY_FIRST(&list_idx)) == 0)
116 			server_redraw_session(s);
117 		recalculate_sizes();
118 		goto out;
119 	}
120 
121 	if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
122 		goto out;
123 
124 	for (i = 0; i < ARRAY_LENGTH(&list_idx); i++) {
125 		wm = winlink_find_by_index(
126 		    &s->windows, ARRAY_ITEM(&list_idx, i));
127 		w = wm->window;
128 
129 		sctx = ARRAY_ITEM(&list_ctx, i);
130 		window_choose_add(wl->window->active,
131 		    wm->idx, "%3d: %s [%ux%u] (%u panes) %s", wm->idx, w->name,
132 		    w->sx, w->sy, window_count_panes(w), sctx);
133 		xfree(sctx);
134 	}
135 
136 	cdata = xmalloc(sizeof *cdata);
137 	if (session_index(s, &cdata->session) != 0)
138 		fatalx("session not found");
139 
140 	window_choose_ready(
141 	    wl->window->active, 0, cmd_find_window_callback, xfree, cdata);
142 
143 out:
144 	ARRAY_FREE(&list_idx);
145 	ARRAY_FREE(&list_ctx);
146 
147 	return (0);
148 }
149 
150 void
151 cmd_find_window_callback(void *data, int idx)
152 {
153 	struct cmd_find_window_data	*cdata = data;
154 	struct session			*s;
155 
156 	if (idx != -1 && cdata->session <= ARRAY_LENGTH(&sessions) - 1) {
157 		s = ARRAY_ITEM(&sessions, cdata->session);
158 		if (s != NULL && session_select(s, idx) == 0)
159 			server_redraw_session(s);
160 		recalculate_sizes();
161 	}
162 }
163