cmd-find-window.c revision 1.1.1.3 1 1.1.1.3 christos /* $Id: cmd-find-window.c,v 1.1.1.3 2014/07/24 14:22:54 christos Exp $ */
2 1.1 jmmv
3 1.1 jmmv /*
4 1.1 jmmv * Copyright (c) 2009 Nicholas Marriott <nicm (at) users.sourceforge.net>
5 1.1 jmmv *
6 1.1 jmmv * Permission to use, copy, modify, and distribute this software for any
7 1.1 jmmv * purpose with or without fee is hereby granted, provided that the above
8 1.1 jmmv * copyright notice and this permission notice appear in all copies.
9 1.1 jmmv *
10 1.1 jmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 1.1 jmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 1.1 jmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 1.1 jmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 1.1 jmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 1.1 jmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 1.1 jmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 1.1 jmmv */
18 1.1 jmmv
19 1.1 jmmv #include <sys/types.h>
20 1.1 jmmv
21 1.1 jmmv #include <fnmatch.h>
22 1.1.1.3 christos #include <stdlib.h>
23 1.1 jmmv #include <string.h>
24 1.1 jmmv
25 1.1 jmmv #include "tmux.h"
26 1.1 jmmv
27 1.1 jmmv /*
28 1.1 jmmv * Find window containing text.
29 1.1 jmmv */
30 1.1 jmmv
31 1.1.1.3 christos enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmd_q *);
32 1.1 jmmv
33 1.1.1.3 christos void cmd_find_window_callback(struct window_choose_data *);
34 1.1.1.3 christos
35 1.1.1.3 christos /* Flags for determining matching behavior. */
36 1.1.1.3 christos #define CMD_FIND_WINDOW_BY_TITLE 0x1
37 1.1.1.3 christos #define CMD_FIND_WINDOW_BY_CONTENT 0x2
38 1.1.1.3 christos #define CMD_FIND_WINDOW_BY_NAME 0x4
39 1.1.1.3 christos
40 1.1.1.3 christos #define CMD_FIND_WINDOW_ALL \
41 1.1.1.3 christos (CMD_FIND_WINDOW_BY_TITLE | \
42 1.1.1.3 christos CMD_FIND_WINDOW_BY_CONTENT | \
43 1.1.1.3 christos CMD_FIND_WINDOW_BY_NAME)
44 1.1 jmmv
45 1.1 jmmv const struct cmd_entry cmd_find_window_entry = {
46 1.1 jmmv "find-window", "findw",
47 1.1.1.3 christos "F:CNt:T", 1, 4,
48 1.1.1.3 christos "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string",
49 1.1.1.2 jmmv 0,
50 1.1.1.2 jmmv NULL,
51 1.1.1.2 jmmv cmd_find_window_exec
52 1.1 jmmv };
53 1.1 jmmv
54 1.1 jmmv struct cmd_find_window_data {
55 1.1.1.3 christos struct winlink *wl;
56 1.1.1.3 christos char *list_ctx;
57 1.1.1.3 christos u_int pane_id;
58 1.1 jmmv };
59 1.1.1.3 christos ARRAY_DECL(cmd_find_window_data_list, struct cmd_find_window_data);
60 1.1.1.3 christos
61 1.1.1.3 christos u_int cmd_find_window_match_flags(struct args *);
62 1.1.1.3 christos void cmd_find_window_match(struct cmd_find_window_data_list *, int,
63 1.1.1.3 christos struct winlink *, const char *, const char *);
64 1.1 jmmv
65 1.1.1.3 christos u_int
66 1.1.1.3 christos cmd_find_window_match_flags(struct args *args)
67 1.1.1.3 christos {
68 1.1.1.3 christos u_int match_flags = 0;
69 1.1.1.3 christos
70 1.1.1.3 christos /* Turn on flags based on the options. */
71 1.1.1.3 christos if (args_has(args, 'T'))
72 1.1.1.3 christos match_flags |= CMD_FIND_WINDOW_BY_TITLE;
73 1.1.1.3 christos if (args_has(args, 'C'))
74 1.1.1.3 christos match_flags |= CMD_FIND_WINDOW_BY_CONTENT;
75 1.1.1.3 christos if (args_has(args, 'N'))
76 1.1.1.3 christos match_flags |= CMD_FIND_WINDOW_BY_NAME;
77 1.1.1.3 christos
78 1.1.1.3 christos /* If none of the flags were set, default to matching anything. */
79 1.1.1.3 christos if (match_flags == 0)
80 1.1.1.3 christos match_flags = CMD_FIND_WINDOW_ALL;
81 1.1.1.3 christos
82 1.1.1.3 christos return (match_flags);
83 1.1.1.3 christos }
84 1.1.1.3 christos
85 1.1.1.3 christos void
86 1.1.1.3 christos cmd_find_window_match(struct cmd_find_window_data_list *find_list,
87 1.1.1.3 christos int match_flags, struct winlink *wl, const char *str, const char *searchstr)
88 1.1.1.3 christos {
89 1.1.1.3 christos struct cmd_find_window_data find_data;
90 1.1.1.3 christos struct window_pane *wp;
91 1.1.1.3 christos u_int i, line;
92 1.1.1.3 christos char *sres;
93 1.1.1.3 christos
94 1.1.1.3 christos memset(&find_data, 0, sizeof find_data);
95 1.1.1.3 christos
96 1.1.1.3 christos i = 0;
97 1.1.1.3 christos TAILQ_FOREACH(wp, &wl->window->panes, entry) {
98 1.1.1.3 christos i++;
99 1.1.1.3 christos
100 1.1.1.3 christos if ((match_flags & CMD_FIND_WINDOW_BY_NAME) &&
101 1.1.1.3 christos fnmatch(searchstr, wl->window->name, 0) == 0) {
102 1.1.1.3 christos find_data.list_ctx = xstrdup("");
103 1.1.1.3 christos break;
104 1.1.1.3 christos }
105 1.1.1.3 christos
106 1.1.1.3 christos if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) &&
107 1.1.1.3 christos fnmatch(searchstr, wp->base.title, 0) == 0) {
108 1.1.1.3 christos xasprintf(&find_data.list_ctx,
109 1.1.1.3 christos "pane %u title: \"%s\"", i - 1, wp->base.title);
110 1.1.1.3 christos break;
111 1.1.1.3 christos }
112 1.1.1.3 christos
113 1.1.1.3 christos if (match_flags & CMD_FIND_WINDOW_BY_CONTENT &&
114 1.1.1.3 christos (sres = window_pane_search(wp, str, &line)) != NULL) {
115 1.1.1.3 christos xasprintf(&find_data.list_ctx,
116 1.1.1.3 christos "pane %u line %u: \"%s\"", i - 1, line + 1, sres);
117 1.1.1.3 christos free(sres);
118 1.1.1.3 christos break;
119 1.1.1.3 christos }
120 1.1.1.3 christos }
121 1.1.1.3 christos if (find_data.list_ctx != NULL) {
122 1.1.1.3 christos find_data.wl = wl;
123 1.1.1.3 christos find_data.pane_id = i - 1;
124 1.1.1.3 christos ARRAY_ADD(find_list, find_data);
125 1.1.1.3 christos }
126 1.1.1.3 christos }
127 1.1.1.3 christos
128 1.1.1.3 christos enum cmd_retval
129 1.1.1.3 christos cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
130 1.1 jmmv {
131 1.1.1.2 jmmv struct args *args = self->args;
132 1.1.1.3 christos struct client *c;
133 1.1.1.3 christos struct window_choose_data *cdata;
134 1.1 jmmv struct session *s;
135 1.1 jmmv struct winlink *wl, *wm;
136 1.1.1.3 christos struct cmd_find_window_data_list find_list;
137 1.1.1.3 christos char *str, *searchstr;
138 1.1.1.3 christos const char *template;
139 1.1.1.3 christos u_int i, match_flags;
140 1.1 jmmv
141 1.1.1.3 christos if ((c = cmd_current_client(cmdq)) == NULL) {
142 1.1.1.3 christos cmdq_error(cmdq, "no client available");
143 1.1.1.3 christos return (CMD_RETURN_ERROR);
144 1.1 jmmv }
145 1.1.1.3 christos s = c->session;
146 1.1 jmmv
147 1.1.1.3 christos if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL)
148 1.1.1.3 christos return (CMD_RETURN_ERROR);
149 1.1 jmmv
150 1.1.1.3 christos if ((template = args_get(args, 'F')) == NULL)
151 1.1.1.3 christos template = FIND_WINDOW_TEMPLATE;
152 1.1.1.3 christos
153 1.1.1.3 christos match_flags = cmd_find_window_match_flags(args);
154 1.1.1.2 jmmv str = args->argv[0];
155 1.1.1.2 jmmv
156 1.1.1.3 christos ARRAY_INIT(&find_list);
157 1.1 jmmv
158 1.1.1.2 jmmv xasprintf(&searchstr, "*%s*", str);
159 1.1.1.3 christos RB_FOREACH(wm, winlinks, &s->windows)
160 1.1.1.3 christos cmd_find_window_match (&find_list, match_flags, wm, str, searchstr);
161 1.1.1.3 christos free(searchstr);
162 1.1.1.3 christos
163 1.1.1.3 christos if (ARRAY_LENGTH(&find_list) == 0) {
164 1.1.1.3 christos cmdq_error(cmdq, "no windows matching: %s", str);
165 1.1.1.3 christos ARRAY_FREE(&find_list);
166 1.1.1.3 christos return (CMD_RETURN_ERROR);
167 1.1 jmmv }
168 1.1 jmmv
169 1.1.1.3 christos if (ARRAY_LENGTH(&find_list) == 1) {
170 1.1.1.3 christos if (session_select(s, ARRAY_FIRST(&find_list).wl->idx) == 0)
171 1.1 jmmv server_redraw_session(s);
172 1.1 jmmv recalculate_sizes();
173 1.1 jmmv goto out;
174 1.1 jmmv }
175 1.1 jmmv
176 1.1 jmmv if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
177 1.1 jmmv goto out;
178 1.1 jmmv
179 1.1.1.3 christos for (i = 0; i < ARRAY_LENGTH(&find_list); i++) {
180 1.1.1.3 christos wm = ARRAY_ITEM(&find_list, i).wl;
181 1.1 jmmv
182 1.1.1.3 christos cdata = window_choose_data_create(TREE_OTHER, c, c->session);
183 1.1.1.3 christos cdata->idx = wm->idx;
184 1.1.1.3 christos cdata->wl = wm;
185 1.1 jmmv
186 1.1.1.3 christos cdata->ft_template = xstrdup(template);
187 1.1.1.3 christos cdata->pane_id = ARRAY_ITEM(&find_list, i).pane_id;
188 1.1 jmmv
189 1.1.1.3 christos format_add(cdata->ft, "line", "%u", i);
190 1.1.1.3 christos format_add(cdata->ft, "window_find_matches", "%s",
191 1.1.1.3 christos ARRAY_ITEM(&find_list, i).list_ctx);
192 1.1.1.3 christos format_session(cdata->ft, s);
193 1.1.1.3 christos format_winlink(cdata->ft, s, wm);
194 1.1.1.3 christos format_window_pane(cdata->ft, wm->window->active);
195 1.1.1.3 christos
196 1.1.1.3 christos window_choose_add(wl->window->active, cdata);
197 1.1.1.3 christos }
198 1.1.1.3 christos
199 1.1.1.3 christos window_choose_ready(wl->window->active, 0, cmd_find_window_callback);
200 1.1.1.3 christos
201 1.1.1.3 christos out:
202 1.1.1.3 christos ARRAY_FREE(&find_list);
203 1.1.1.3 christos return (CMD_RETURN_NORMAL);
204 1.1 jmmv }
205 1.1 jmmv
206 1.1 jmmv void
207 1.1.1.3 christos cmd_find_window_callback(struct window_choose_data *cdata)
208 1.1 jmmv {
209 1.1.1.3 christos struct session *s;
210 1.1.1.3 christos struct window_pane *wp;
211 1.1 jmmv
212 1.1.1.3 christos if (cdata == NULL)
213 1.1 jmmv return;
214 1.1.1.3 christos
215 1.1.1.3 christos s = cdata->start_session;
216 1.1 jmmv if (!session_alive(s))
217 1.1 jmmv return;
218 1.1 jmmv
219 1.1.1.3 christos wp = window_pane_at_index(cdata->wl->window, cdata->pane_id);
220 1.1.1.3 christos if (wp != NULL && window_pane_visible(wp))
221 1.1.1.3 christos window_set_active_pane(cdata->wl->window, wp);
222 1.1.1.3 christos
223 1.1.1.3 christos if (session_select(s, cdata->idx) == 0) {
224 1.1 jmmv server_redraw_session(s);
225 1.1 jmmv recalculate_sizes();
226 1.1 jmmv }
227 1.1 jmmv }
228