From aad4e4ddb194cba9c01b0ddd696fb7b214e1a7eb Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 30 May 2017 21:44:59 +0000 Subject: Rewrite of choose mode, both to simplify and tidy the code and to add some modern features. Now the common code is in mode-tree.c, which provides an API used by the three modes now separated into window-{buffer,client,tree}.c. Buffer mode shows buffers, client mode clients and tree mode a tree of sessions, windows and panes. Each mode has a common set of key bindings plus a few that are specific to the mode. Other changes are: - each mode has a preview pane: for buffers this is the buffer content (very useful), for others it is a preview of the pane; - items may be sorted in different ways ('O' key); - multiple items may be tagged and an operation applied to all of them (for example, to delete multiple buffers at once); - in tree mode a command may be run on the selected item (session, window, pane) or on tagged items (key ':'); - displayed items may be filtered in tree mode by using a format (this is used to implement find-window) (key 'f'); - the custom format (-F) for the display is no longer available; - shortcut keys change from 0-9, a-z, A-Z which was always a bit weird with keys used for other uses to 0-9, M-a to M-z. Now that the code is simpler, other improvements will come later. Primary key bindings for each mode are documented under the commands in the man page (choose-buffer, choose-client, choose-tree). Parts written by Thomas Adam. --- cmd-find-window.c | 247 +++++++++++------------------------------------------- 1 file changed, 49 insertions(+), 198 deletions(-) (limited to 'cmd-find-window.c') diff --git a/cmd-find-window.c b/cmd-find-window.c index 6338e2e1..92714498 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -18,9 +18,7 @@ #include -#include #include -#include #include "tmux.h" @@ -28,216 +26,69 @@ * 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 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 = { .name = "find-window", .alias = "findw", - .args = { "F:CNt:T", 1, 4 }, - .usage = "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", + .args = { "CNt:T", 1, 1 }, + .usage = "[-CNT] " CMD_TARGET_PANE_USAGE " match-string", - .target = { 't', CMD_FIND_WINDOW, 0 }, + .target = { 't', CMD_FIND_PANE, 0 }, .flags = 0, .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 cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) { - struct args *args = self->args; - struct cmd_find_state *current = &item->shared->current; - struct client *c = cmd_find_client(item, NULL, 1); - struct window_choose_data *cdata; - struct session *s = item->target.s; - 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) { - cmdq_error(item, "no client available"); - return (CMD_RETURN_ERROR); - } - - if ((template = args_get(args, 'F')) == NULL) - template = FIND_WINDOW_TEMPLATE; - - match_flags = cmd_find_window_match_flags(args); - str = args->argv[0]; - - TAILQ_INIT(&find_list); - - xasprintf(&searchstr, "*%s*", str); - RB_FOREACH(wm, winlinks, &s->windows) - cmd_find_window_match(&find_list, match_flags, wm, str, searchstr); - free(searchstr); - - if (TAILQ_EMPTY(&find_list)) { - cmdq_error(item, "no windows matching: %s", str); - 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); -} - -static void -cmd_find_window_callback(struct window_choose_data *cdata) -{ - struct session *s; - struct window_pane *wp; - - if (cdata == NULL) - return; + struct args *args = self->args, *new_args; + struct window_pane *wp = item->target.wp; + const char *s = args->argv[0]; + char *filter, *argv = { NULL }; + int C, N, T; + + C = args_has(args, 'C'); + N = args_has(args, 'N'); + T = args_has(args, 'T'); + + if (!C && !N && !T) + C = N = T = 1; + + if (C && N && T) { + 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); + + new_args = args_parse("", 1, &argv); + args_set(new_args, 'f', filter); + + window_pane_set_mode(wp, &window_tree_mode, &item->target, new_args); + + args_free(new_args); + free(filter); - 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(); - } + return (CMD_RETURN_NORMAL); } -- cgit v1.2.3