version 1.42, 2017/05/29 18:06:34 |
version 1.43, 2017/05/30 21:44:59 |
|
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <fnmatch.h> |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
|
* Find window containing text. |
* Find window containing text. |
*/ |
*/ |
|
|
#define FIND_WINDOW_TEMPLATE \ |
|
"#{window_index}: #{window_name} " \ |
|
"[#{window_width}x#{window_height}] " \ |
|
"(#{window_panes} panes) #{window_find_matches}" |
|
|
|
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *); |
static enum cmd_retval cmd_find_window_exec(struct cmd *, struct cmdq_item *); |
|
|
static void cmd_find_window_callback(struct window_choose_data *); |
|
|
|
/* Flags for determining matching behavior. */ |
|
#define CMD_FIND_WINDOW_BY_TITLE 0x1 |
|
#define CMD_FIND_WINDOW_BY_CONTENT 0x2 |
|
#define CMD_FIND_WINDOW_BY_NAME 0x4 |
|
|
|
#define CMD_FIND_WINDOW_ALL \ |
|
(CMD_FIND_WINDOW_BY_TITLE | \ |
|
CMD_FIND_WINDOW_BY_CONTENT | \ |
|
CMD_FIND_WINDOW_BY_NAME) |
|
|
|
const struct cmd_entry cmd_find_window_entry = { |
const struct cmd_entry cmd_find_window_entry = { |
.name = "find-window", |
.name = "find-window", |
.alias = "findw", |
.alias = "findw", |
|
|
.args = { "F:CNt:T", 1, 4 }, |
.args = { "CNt:T", 1, 1 }, |
.usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", |
.usage = "[-CNT] " CMD_TARGET_PANE_USAGE " match-string", |
|
|
.target = { 't', CMD_FIND_WINDOW, 0 }, |
.target = { 't', CMD_FIND_PANE, 0 }, |
|
|
.flags = 0, |
.flags = 0, |
.exec = cmd_find_window_exec |
.exec = cmd_find_window_exec |
}; |
}; |
|
|
struct cmd_find_window_data { |
|
struct winlink *wl; |
|
char *list_ctx; |
|
u_int pane_id; |
|
TAILQ_ENTRY(cmd_find_window_data) entry; |
|
}; |
|
TAILQ_HEAD(cmd_find_window_list, cmd_find_window_data); |
|
|
|
static u_int cmd_find_window_match_flags(struct args *); |
|
static void cmd_find_window_match(struct cmd_find_window_list *, int, |
|
struct winlink *, const char *, const char *); |
|
|
|
static u_int |
|
cmd_find_window_match_flags(struct args *args) |
|
{ |
|
u_int match_flags = 0; |
|
|
|
/* Turn on flags based on the options. */ |
|
if (args_has(args, 'T')) |
|
match_flags |= CMD_FIND_WINDOW_BY_TITLE; |
|
if (args_has(args, 'C')) |
|
match_flags |= CMD_FIND_WINDOW_BY_CONTENT; |
|
if (args_has(args, 'N')) |
|
match_flags |= CMD_FIND_WINDOW_BY_NAME; |
|
|
|
/* If none of the flags were set, default to matching anything. */ |
|
if (match_flags == 0) |
|
match_flags = CMD_FIND_WINDOW_ALL; |
|
|
|
return (match_flags); |
|
} |
|
|
|
static void |
|
cmd_find_window_match(struct cmd_find_window_list *find_list, |
|
int match_flags, struct winlink *wl, const char *str, |
|
const char *searchstr) |
|
{ |
|
struct cmd_find_window_data *find_data; |
|
struct window_pane *wp; |
|
u_int i, line; |
|
char *sres; |
|
|
|
find_data = xcalloc(1, sizeof *find_data); |
|
|
|
i = 0; |
|
TAILQ_FOREACH(wp, &wl->window->panes, entry) { |
|
i++; |
|
|
|
if ((match_flags & CMD_FIND_WINDOW_BY_NAME) && |
|
fnmatch(searchstr, wl->window->name, 0) == 0) { |
|
find_data->list_ctx = xstrdup(""); |
|
break; |
|
} |
|
|
|
if ((match_flags & CMD_FIND_WINDOW_BY_TITLE) && |
|
fnmatch(searchstr, wp->base.title, 0) == 0) { |
|
xasprintf(&find_data->list_ctx, |
|
"pane %u title: \"%s\"", i - 1, wp->base.title); |
|
break; |
|
} |
|
|
|
if (match_flags & CMD_FIND_WINDOW_BY_CONTENT && |
|
(sres = window_pane_search_old(wp, str, &line)) != NULL) { |
|
xasprintf(&find_data->list_ctx, |
|
"pane %u line %u: \"%s\"", i - 1, line + 1, sres); |
|
free(sres); |
|
break; |
|
} |
|
} |
|
|
|
if (find_data->list_ctx != NULL) { |
|
find_data->wl = wl; |
|
find_data->pane_id = i - 1; |
|
TAILQ_INSERT_TAIL(find_list, find_data, entry); |
|
} else |
|
free(find_data); |
|
} |
|
|
|
static enum cmd_retval |
static enum cmd_retval |
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) |
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) |
{ |
{ |
struct args *args = self->args; |
struct args *args = self->args, *new_args; |
struct cmd_find_state *current = &item->shared->current; |
struct window_pane *wp = item->target.wp; |
struct client *c = cmd_find_client(item, NULL, 1); |
const char *s = args->argv[0]; |
struct window_choose_data *cdata; |
char *filter, *argv = { NULL }; |
struct session *s = item->target.s; |
int C, N, T; |
struct winlink *wl = item->target.wl, *wm; |
|
struct cmd_find_window_list find_list; |
|
struct cmd_find_window_data *find_data; |
|
struct cmd_find_window_data *find_data1; |
|
char *str, *searchstr; |
|
const char *template; |
|
u_int i, match_flags; |
|
|
|
if (c == NULL) { |
C = args_has(args, 'C'); |
cmdq_error(item, "no client available"); |
N = args_has(args, 'N'); |
return (CMD_RETURN_ERROR); |
T = args_has(args, 'T'); |
} |
|
|
|
if ((template = args_get(args, 'F')) == NULL) |
if (!C && !N && !T) |
template = FIND_WINDOW_TEMPLATE; |
C = N = T = 1; |
|
|
match_flags = cmd_find_window_match_flags(args); |
if (C && N && T) { |
str = args->argv[0]; |
xasprintf(&filter, |
|
"#{||:" |
|
"#{C:%s},#{||:#{m:*%s*,#{window_name}}," |
|
"#{m:*%s*,#{pane_title}}}}", |
|
s, s, s); |
|
} else if (C && N) { |
|
xasprintf(&filter, |
|
"#{||:#{C:%s},#{m:*%s*,#{window_name}}}", |
|
s, s); |
|
} else if (C && T) { |
|
xasprintf(&filter, |
|
"#{||:#{C:%s},#{m:*%s*,#{pane_title}}}", |
|
s, s); |
|
} else if (N && T) { |
|
xasprintf(&filter, |
|
"#{||:#{m:*%s*,#{window_name}},#{m:*%s*,#{pane_title}}}", |
|
s, s); |
|
} else if (C) |
|
xasprintf(&filter, "#{C:%s}", s); |
|
else if (N) |
|
xasprintf(&filter, "#{m:*%s*,#{window_name}}", s); |
|
else if (T) |
|
xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s); |
|
|
TAILQ_INIT(&find_list); |
new_args = args_parse("", 1, &argv); |
|
args_set(new_args, 'f', filter); |
|
|
xasprintf(&searchstr, "*%s*", str); |
window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args); |
RB_FOREACH(wm, winlinks, &s->windows) |
|
cmd_find_window_match(&find_list, match_flags, wm, str, searchstr); |
|
free(searchstr); |
|
|
|
if (TAILQ_EMPTY(&find_list)) { |
args_free(new_args); |
cmdq_error(item, "no windows matching: %s", str); |
free(filter); |
return (CMD_RETURN_ERROR); |
|
} |
|
|
|
if (TAILQ_NEXT(TAILQ_FIRST(&find_list), entry) == NULL) { |
|
if (session_select(s, TAILQ_FIRST(&find_list)->wl->idx) == 0) { |
|
cmd_find_from_session(current, s); |
|
server_redraw_session(s); |
|
} |
|
recalculate_sizes(); |
|
goto out; |
|
} |
|
|
|
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) |
|
goto out; |
|
|
|
i = 0; |
|
TAILQ_FOREACH(find_data, &find_list, entry) { |
|
cdata = window_choose_data_create(TREE_OTHER, c, c->session); |
|
cdata->idx = find_data->wl->idx; |
|
cdata->wl = find_data->wl; |
|
|
|
cdata->ft_template = xstrdup(template); |
|
cdata->pane_id = find_data->pane_id; |
|
|
|
format_add(cdata->ft, "line", "%u", i); |
|
format_add(cdata->ft, "window_find_matches", "%s", |
|
find_data->list_ctx); |
|
format_defaults(cdata->ft, NULL, s, find_data->wl, NULL); |
|
|
|
window_choose_add(wl->window->active, cdata); |
|
|
|
i++; |
|
} |
|
|
|
window_choose_ready(wl->window->active, 0, cmd_find_window_callback); |
|
|
|
out: |
|
TAILQ_FOREACH_SAFE(find_data, &find_list, entry, find_data1) { |
|
free(find_data->list_ctx); |
|
TAILQ_REMOVE(&find_list, find_data, entry); |
|
free(find_data); |
|
} |
|
return (CMD_RETURN_NORMAL); |
return (CMD_RETURN_NORMAL); |
} |
|
|
|
static void |
|
cmd_find_window_callback(struct window_choose_data *cdata) |
|
{ |
|
struct session *s; |
|
struct window_pane *wp; |
|
|
|
if (cdata == NULL) |
|
return; |
|
|
|
s = cdata->start_session; |
|
if (!session_alive(s)) |
|
return; |
|
|
|
wp = window_pane_at_index(cdata->wl->window, cdata->pane_id); |
|
if (wp != NULL && window_pane_visible(wp)) |
|
window_set_active_pane(cdata->wl->window, wp); |
|
|
|
if (session_select(s, cdata->idx) == 0) { |
|
server_redraw_session(s); |
|
recalculate_sizes(); |
|
} |
|
} |
} |