diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 923229eab..7146c98f5 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-attach-session.c,v 1.93 2026/10/09 13:12:14 nicm Exp $ */ +/* $OpenBSD: cmd-attach-session.c,v 1.94 2026/10/15 07:25:07 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -55,7 +55,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state target; enum cmd_find_type type; - int flags; + int flags, ro = 0; struct client *c = cmdq_get_client(item), *c_loop; struct session *s; struct winlink *wl; @@ -72,6 +72,14 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, if (c == NULL) return (CMD_RETURN_NORMAL); + if (c->flags & CLIENT_READONLY) { + if (dflag || xflag || cflag != NULL) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + ro = 1; + } + if (server_client_check_nested(c)) { cmdq_error(item, "sessions should be nested with care, " "unset $TMUX to force"); @@ -91,6 +99,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, wl = target.wl; wp = target.wp; + if (ro && (wl != s->curw || (wp != NULL && wp != wp->window->active))) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + if (wl != NULL) { if (wp != NULL) { window_redraw_active_switch(wp->window, wp); @@ -111,7 +124,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, if (fflag) server_client_set_flags(c, fflag); if (rflag) { - if (c->flags & CLIENT_READONLY) { + if (ro) { uid = proc_get_peer_uid(c->peer); if (uid != getuid()) { cmdq_error(item, "client is read-only"); @@ -134,7 +147,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, server_client_detach(c_loop, msgtype); } } - if (!Eflag) + if (!Eflag && (~c->flags & CLIENT_READONLY)) environ_update(s->options, c->environ, s->environ); server_client_set_session(c, s); @@ -158,7 +171,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, server_client_detach(c_loop, msgtype); } } - if (!Eflag) + if (!Eflag && (~c->flags & CLIENT_READONLY)) environ_update(s->options, c->environ, s->environ); server_client_set_session(c, s); diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 62df6ac6c..47b59a72e 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-choose-tree.c,v 1.60 2026/10/09 13:12:14 nicm Exp $ */ +/* $OpenBSD: cmd-choose-tree.c,v 1.61 2026/10/15 08:07:17 nicm Exp $ */ /* * Copyright (c) 2012 Thomas Adam @@ -18,6 +18,9 @@ #include +#include +#include + #include "tmux.h" /* @@ -28,6 +31,9 @@ static enum args_parse_type cmd_choose_tree_args_parse(struct args *args, u_int idx, char **cause); static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *); +static void cmd_choose_tree_read_done(struct client *, + const char *, int, int, struct evbuffer *, + void *); const struct cmd_entry cmd_choose_tree_entry = { .name = "choose-tree", @@ -93,9 +99,9 @@ const struct cmd_entry cmd_switch_mode_entry = { .description = "Switch the active pane mode.", .alias = NULL, - .args = { "F:kO:rst:wZ", 0, 1, cmd_choose_tree_args_parse }, - .usage = "[-krsZw] [-F format] [-O sort-order] " CMD_TARGET_PANE_USAGE - " [command]", + .args = { "F:f:kO:rst:wZ", 0, 1, cmd_choose_tree_args_parse }, + .usage = "[-krsZw] [-F format] [-f path] [-O sort-order] " + CMD_TARGET_PANE_USAGE " [command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -131,9 +137,11 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); + struct client *c = cmdq_get_client(item); struct window_pane *wp = target->wp; const struct window_mode *mode; enum sort_order order; + char *path; order = sort_order_from_string(args_get(args, 'O')); if (order == SORT_END && args_has(args, 'O')) { @@ -158,6 +166,53 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) else mode = &window_tree_mode; + if (mode == &window_switch_mode && args_has(args, 'f')) { + path = format_single_from_target(item, args_get(args, 'f')); + file_read(c, path, cmd_choose_tree_read_done, item); + free(path); + return (CMD_RETURN_WAIT); + } window_pane_set_mode(wp, NULL, mode, item, target, args); return (CMD_RETURN_NORMAL); } + +static void +cmd_choose_tree_read_done(__unused struct client *c, const char *path, + int error, int closed, struct evbuffer *buffer, void *data) +{ + struct cmdq_item *item = data; + struct cmd *cmd = cmdq_get_cmd(item); + struct args *args = cmd_get_args(cmd); + struct cmd_find_state *target = cmdq_get_target(item); + struct window_pane *wp = target->wp; + struct window_mode_entry *wme; + char *buf = EVBUFFER_DATA(buffer); + size_t len = EVBUFFER_LENGTH(buffer); + + if (!closed) + return; + + if (error != 0) { + cmdq_error(item, "%s: %s", strerror(error), path); + goto out; + } + if (len != 0 && memchr(buf, '\0', len) != NULL) { + cmdq_error(item, "%s: contains binary data", path); + goto out; + } + if (!cmd_find_valid_state(target)) { + cmdq_error(item, "target pane no longer exists"); + goto out; + } + + TAILQ_FOREACH(wme, &wp->modes, entry) { + if (wme->mode == &window_switch_mode) + break; + } + if (window_pane_set_mode(wp, NULL, &window_switch_mode, item, target, + args) == 0 && wme == NULL) + window_switch_set_input(TAILQ_FIRST(&wp->modes), buffer); + +out: + cmdq_continue(item); +} diff --git a/cmd-find.c b/cmd-find.c index 183e5525d..51e345094 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-find.c,v 1.88 2026/09/07 12:05:12 nicm Exp $ */ +/* $OpenBSD: cmd-find.c,v 1.89 2026/10/15 07:51:50 nicm Exp $ */ /* * Copyright (c) 2015 Nicholas Marriott @@ -1019,6 +1019,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, cmdq_error(item, "no current client"); goto error; } + fs->s = c->session; fs->wl = c->session->curw; fs->wp = c->session->curw->window->active; fs->w = c->session->curw->window; diff --git a/cmd-queue.c b/cmd-queue.c index e84c265f7..5ff4a2c2f 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-queue.c,v 1.124 2026/09/22 06:46:50 nicm Exp $ */ +/* $OpenBSD: cmd-queue.c,v 1.125 2026/10/15 07:25:07 nicm Exp $ */ /* * Copyright (c) 2013 Nicholas Marriott @@ -594,6 +594,15 @@ cmdq_fire_command(struct cmdq_item *item) flags = !!(state->flags & CMDQ_STATE_CONTROL); cmdq_guard(item, "begin", flags); + if (flags && + saved != NULL && + (saved->flags & CLIENT_READONLY) && + (~entry->flags & CMD_READONLY)) { + cmdq_error(item, "client is read-only"); + retval = CMD_RETURN_ERROR; + goto out; + } + if (item->client == NULL) item->client = cmd_find_client(item, NULL, 1); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index f9f0360e4..3ca963ffb 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-send-keys.c,v 1.82 2026/10/09 13:12:14 nicm Exp $ */ +/* $OpenBSD: cmd-send-keys.c,v 1.83 2026/10/15 07:25:07 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -164,6 +164,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); + struct client *c = cmdq_get_client(item); struct client *tc = cmdq_get_target_client(item); struct session *s = target->s; struct winlink *wl = target->wl; @@ -177,7 +178,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) u_int count = args_count(args); char *cause = NULL; - if (tc != NULL && tc->flags & CLIENT_READONLY && !args_has(args, 'X')) { + if ((c != NULL && (c->flags & CLIENT_READONLY) && c != tc) || + (tc != NULL && (tc->flags & CLIENT_READONLY) && !args_has(args, 'X'))) { cmdq_error(item, "client is read-only"); return (CMD_RETURN_ERROR); } diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 19a04cf39..a2d0ee630 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-switch-client.c,v 1.76 2026/10/09 13:12:14 nicm Exp $ */ +/* $OpenBSD: cmd-switch-client.c,v 1.77 2026/10/15 07:25:07 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -66,6 +66,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) struct sort_criteria sort_crit; uid_t uid; + if (c != NULL && (c->flags & CLIENT_READONLY) && c != tc) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + if (tflag != NULL && (tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) { type = CMD_FIND_PANE; @@ -80,6 +85,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) wl = target.wl; wp = target.wp; + if (c != NULL && (c->flags & CLIENT_READONLY) && + (wl != s->curw || (wp != NULL && wp != wp->window->active))) { + cmdq_error(item, "client is read-only"); + return (CMD_RETURN_ERROR); + } + if (args_has(args, 'r')) { if (tc->flags & CLIENT_READONLY) { uid = proc_get_peer_uid(c->peer); @@ -157,7 +168,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) } } - if (!args_has(args, 'E')) + if (!args_has(args, 'E') && (~tc->flags & CLIENT_READONLY)) environ_update(s->options, tc->environ, s->environ); server_client_set_session(tc, s); diff --git a/format.c b/format.c index cc97cbd51..cdbfaa06a 100644 --- a/format.c +++ b/format.c @@ -1,4 +1,4 @@ -/* $OpenBSD: format.c,v 1.428 2026/10/13 10:21:58 nicm Exp $ */ +/* $OpenBSD: format.c,v 1.429 2026/10/15 07:25:07 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott @@ -4289,7 +4289,10 @@ format_create_add_item(struct format_tree *ft, struct cmdq_item *item) { struct key_event *event = cmdq_get_event(item); struct mouse_event *m = &event->m; + struct client *c = cmdq_get_client(item); + if (c != NULL && (c->flags & CLIENT_READONLY)) + ft->flags |= FORMAT_NOJOBS; cmdq_merge_formats(item, ft); memcpy(&ft->m, m, sizeof ft->m); } diff --git a/hooks.c b/hooks.c index acc11704d..5cef0b143 100644 --- a/hooks.c +++ b/hooks.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hooks.c,v 1.16 2026/07/27 19:15:58 nicm Exp $ */ +/* $OpenBSD: hooks.c,v 1.17 2026/10/15 08:21:11 nicm Exp $ */ /* * Copyright (c) 2026 Nicholas Marriott @@ -164,6 +164,7 @@ hooks_insert(struct cmdq_item *item, struct hooks_data *hd) break; case CMD_PARSE_SUCCESS: hooks_insert_one(item, hd, pr->cmdlist, state); + cmd_list_free(pr->cmdlist); break; } } else { @@ -178,10 +179,12 @@ hooks_insert(struct cmdq_item *item, struct hooks_data *hd) cmdq_error(item, "%s", pr->error); } + free(pr->error); break; case CMD_PARSE_SUCCESS: item = hooks_insert_one(item, hd, pr->cmdlist, state); + cmd_list_free(pr->cmdlist); break; } } else { diff --git a/server-client.c b/server-client.c index 6f824662d..a2a51bc81 100644 --- a/server-client.c +++ b/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.520 2026/10/12 10:48:05 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.522 2026/10/15 08:21:11 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -2274,7 +2274,7 @@ server_client_check_exit(struct client *c, int force) if (~c->flags & CLIENT_EXIT) return; - if (c->flags & CLIENT_CONTROL) { + if ((c->flags & CLIENT_CONTROL) && c->control_state != NULL) { if (force) control_discard_all(c); else { @@ -2752,6 +2752,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) } else { values = args_from_vector(argc, argv); pr = cmd_parse_from_arguments(values, argc, NULL); + args_free_values(values, argc); + free(values); switch (pr->status) { case CMD_PARSE_ERROR: cause = pr->error; @@ -2759,8 +2761,6 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) case CMD_PARSE_SUCCESS: break; } - args_free_values(values, argc); - free(values); cmd_free_argv(argc, argv); if ((c->flags & CLIENT_READONLY) && !cmd_list_all_have(pr->cmdlist, CMD_READONLY)) { diff --git a/tmux.1 b/tmux.1 index 0b6c48c40..8f7337892 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.1186 2026/10/14 12:33:46 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.1187 2026/10/15 08:07:17 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 14 2026 $ +.Dd $Mdocdate: October 15 2026 $ .Dt TMUX 1 .Os .Sh NAME @@ -3207,6 +3207,7 @@ command works only if at least one client is attached. .Ic switch\-mode .Op Fl krsZw .Op Fl F Ar format +.Op Fl f Ar path .Op Fl O Ar sort\-order .Op Fl t Ar target\-pane .Op Ar command @@ -3252,6 +3253,24 @@ If is not given, "switch\-client \-Zt \[aq]%%\[aq]" is used. .Fl F specifies the format for each item in the list. +.Pp +.Fl f +reads choices from +.Ar path +instead of listing sessions or windows. +Each line is one choice. +With +.Fl f , +.Ql switch_item +contains the original line and the default display format is +.Ql #{switch_item} . +Fuzzy matching uses the displayed text. +When a choice is selected, +.Ql %% +and +.Ql %1 +are replaced by the original line +.Pp .Fl k kills the pane when the mode is exited. .Pp @@ -7631,6 +7650,7 @@ The following variables are available, where appropriate: .It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "socket_path" Ta "" Ta "Server socket path" .It Li "start_time" Ta "" Ta "Server start time" +.It Li "switch_item" Ta "" Ta "Original input line in switch mode" .It Li "synchronized_output_flag" Ta "" Ta "1 if pane has synchronized output enabled" .It Li "uid" Ta "" Ta "Server UID" .It Li "user" Ta "" Ta "Server user" diff --git a/tmux.h b/tmux.h index 00293690f..a6c6d7f6c 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1463 2026/10/14 12:48:50 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1464 2026/10/15 08:07:17 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -3989,6 +3989,7 @@ extern const struct window_mode window_tree_mode; /* window-switch.c */ extern const struct window_mode window_switch_mode; +void window_switch_set_input(struct window_mode_entry *, struct evbuffer *); /* window-clock.c */ extern const struct window_mode window_clock_mode; diff --git a/tty-term.c b/tty-term.c index 7415cc552..d59819859 100644 --- a/tty-term.c +++ b/tty-term.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty-term.c,v 1.113 2026/10/14 12:33:46 nicm Exp $ */ +/* $OpenBSD: tty-term.c,v 1.114 2026/10/15 08:21:11 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -415,6 +415,8 @@ tty_term_apply(struct tty_term *term, const char *capabilities, int quiet, continue; if (remove) { + if (code->type == TTYCODE_STRING) + free(code->value.string); code->type = TTYCODE_NONE; continue; } diff --git a/window-customize.c b/window-customize.c index b8ec4f140..f482031b6 100644 --- a/window-customize.c +++ b/window-customize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-customize.c,v 1.37 2026/10/08 07:50:05 nicm Exp $ */ +/* $OpenBSD: window-customize.c,v 1.38 2026/10/15 08:21:11 nicm Exp $ */ /* * Copyright (c) 2020 Nicholas Marriott @@ -1430,6 +1430,7 @@ monitor: if (wo != NULL && options_owner(o) != wo) { parent = options_get_only(wo, name); if (parent != NULL) { + free(value); value = options_to_string(parent, NULL, 0); xsnprintf(label, sizeof label, "Window value (from window %u): ", fs.wl->idx); @@ -1442,6 +1443,7 @@ monitor: if (go != NULL && options_owner(o) != go) { parent = options_get_only(go, name); if (parent != NULL) { + free(value); value = options_to_string(parent, NULL, 0); if (!window_customize_write_value(ctx, s->cx, sx, sy - (s->cy - cy), 0, "Global value: ", "%s%s%s", diff --git a/window-switch.c b/window-switch.c index 24b3851ac..cafc18ca4 100644 --- a/window-switch.c +++ b/window-switch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-switch.c,v 1.5 2026/10/07 13:13:49 nicm Exp $ */ +/* $OpenBSD: window-switch.c,v 1.6 2026/10/15 08:07:17 nicm Exp $ */ /* * Copyright (c) 2026 Nicholas Marriott @@ -63,7 +63,8 @@ const struct window_mode window_switch_mode = { enum window_switch_type { WINDOW_SWITCH_TYPE_SESSION, - WINDOW_SWITCH_TYPE_WINDOW + WINDOW_SWITCH_TYPE_WINDOW, + WINDOW_SWITCH_TYPE_INPUT }; struct window_switch_itemdata { @@ -73,6 +74,7 @@ struct window_switch_itemdata { uint64_t tag; char *text; + const char *value; bitstr_t *match; u_int score; @@ -87,6 +89,9 @@ struct window_switch_modedata { char *format; char *command; + char **lines; + u_int lines_size; + enum window_switch_type type; enum sort_order order; int reversed; @@ -165,6 +170,20 @@ window_switch_add_window(struct window_switch_modedata *data, format_free(ft); } +static void +window_switch_add_input(struct window_switch_modedata *data, u_int idx, + struct format_tree *ft) +{ + struct window_switch_itemdata *item; + + item = window_switch_add_item(data); + item->type = WINDOW_SWITCH_TYPE_INPUT; + item->value = data->lines[idx]; + item->order = data->reversed ? data->lines_size - idx - 1 : idx; + format_add(ft, "switch_item", "%s", item->value); + item->text = format_expand(ft, data->format); +} + static int window_switch_compare(const void *a0, const void *b0) { @@ -192,6 +211,8 @@ window_switch_build(struct window_switch_modedata *data) struct session **sl; struct winlink **wl; struct sort_criteria sort_crit; + struct cmd_find_state fs; + struct format_tree *ft; sort_crit.order = data->order; sort_crit.reversed = data->reversed; @@ -214,6 +235,14 @@ window_switch_build(struct window_switch_modedata *data) for (i = 0; i < nw; i++) window_switch_add_window(data, wl[i], &order); break; + case WINDOW_SWITCH_TYPE_INPUT: + cmd_find_from_pane(&fs, data->wp, 0); + ft = format_create(NULL, NULL, FORMAT_NONE, 0); + format_defaults(ft, NULL, fs.s, fs.wl, fs.wp); + for (i = 0; i < data->lines_size; i++) + window_switch_add_input(data, i, ft); + format_free(ft); + break; } for (i = 0; i < data->item_size; i++) { @@ -365,11 +394,16 @@ window_switch_init(struct window_mode_entry *wme, data->type = WINDOW_SWITCH_TYPE_WINDOW; else data->type = WINDOW_SWITCH_TYPE_SESSION; + if (args_has(args, 'f')) + data->type = WINDOW_SWITCH_TYPE_INPUT; data->filter = xstrdup(""); - if (args == NULL || !args_has(args, 'F')) - data->format = xstrdup(WINDOW_SWITCH_DEFAULT_FORMAT); - else + if (args == NULL || !args_has(args, 'F')) { + if (data->type == WINDOW_SWITCH_TYPE_INPUT) + data->format = xstrdup("#{switch_item}"); + else + data->format = xstrdup(WINDOW_SWITCH_DEFAULT_FORMAT); + } else data->format = xstrdup(args_get(args, 'F')); if (args == NULL || args_count(args) == 0) data->command = xstrdup(WINDOW_SWITCH_DEFAULT_COMMAND); @@ -407,6 +441,36 @@ window_switch_init(struct window_mode_entry *wme, return (s); } +void +window_switch_set_input(struct window_mode_entry *wme, struct evbuffer *buffer) +{ + struct window_switch_modedata *data = wme->data; + char *line; + size_t size; + + for (;;) { + line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF); + if (line == NULL) { + size = EVBUFFER_LENGTH(buffer); + if (size == 0) + break; + line = xmemdup(EVBUFFER_DATA(buffer), size); + evbuffer_drain(buffer, size); + } + if (*line == '\0') { + free(line); + continue; + } + data->lines = xreallocarray(data->lines, data->lines_size + 1, + sizeof *data->lines); + data->lines[data->lines_size++] = line; + } + window_switch_build(data); + window_switch_set_current(data, 0); + window_switch_draw_screen(wme); + wme->wp->flags |= PANE_REDRAW; +} + static void window_switch_free(struct window_mode_entry *wme) { @@ -419,6 +483,9 @@ window_switch_free(struct window_mode_entry *wme) for (i = 0; i < data->item_size; i++) window_switch_free_item(data->item_list[i]); free(data->item_list); + for (i = 0; i < data->lines_size; i++) + free(data->lines[i]); + free(data->lines); free(data->matches); free(data->filter); @@ -477,6 +544,10 @@ window_switch_run_command(struct window_switch_modedata *data, struct client *c) } } break; + case WINDOW_SWITCH_TYPE_INPUT: + target = xstrdup(item->value); + cmd_find_from_pane(&fs, data->wp, 0); + break; } if (target == NULL) return (0); @@ -484,6 +555,8 @@ window_switch_run_command(struct window_switch_modedata *data, struct client *c) command = cmd_template_replace(data->command, target, 1); if (command != NULL && *command != '\0') { state = cmdq_new_state(&fs, NULL, 0); + if (item->type == WINDOW_SWITCH_TYPE_INPUT) + cmdq_add_format(state, "switch_item", "%s", item->value); status = cmd_parse_and_append(command, NULL, c, state, &error); if (status == CMD_PARSE_ERROR) { if (c != NULL) { @@ -539,7 +612,8 @@ window_switch_key(struct window_mode_entry *wme, struct client *c, return; if (data->prompt != NULL && screen_size_y(&data->screen) != 0 && y == screen_size_y(&data->screen) - 1 && - MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_1 && !MOUSE_DRAG(m->b) && + MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_1 && + !MOUSE_DRAG(m->b) && !MOUSE_RELEASE(m->b)) { result = prompt_mouse(data->prompt, x, 0, screen_size_x(&data->screen), &redraw);