mirror of
https://github.com/tmux/tmux.git
synced 2026-10-16 08:24:23 +00:00
Merge remote-tracking branch 'refs/remotes/tmux-openbsd/master'
* refs/remotes/tmux-openbsd/master:
Memory leak fixes from someone in GitHub issues 5739, 5744, 5745, 5746.
Add -f to switch-mode to read choices from a file, GitHub issue 5738.
Set session for {current} target, GitHub issue 5742.
Do not discard control state before a control client creates it, GitHub issue 5740 from Andre Popp.
A few additional readonly checks, GitHub issue 5736 from gmkbenjamin at hotmail dot com.
This commit is contained in:
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -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 *current = cmdq_get_current(item);
|
||||||
struct cmd_find_state target;
|
struct cmd_find_state target;
|
||||||
enum cmd_find_type type;
|
enum cmd_find_type type;
|
||||||
int flags;
|
int flags, ro = 0;
|
||||||
struct client *c = cmdq_get_client(item), *c_loop;
|
struct client *c = cmdq_get_client(item), *c_loop;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
@@ -72,6 +72,14 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
|||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
return (CMD_RETURN_NORMAL);
|
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)) {
|
if (server_client_check_nested(c)) {
|
||||||
cmdq_error(item, "sessions should be nested with care, "
|
cmdq_error(item, "sessions should be nested with care, "
|
||||||
"unset $TMUX to force");
|
"unset $TMUX to force");
|
||||||
@@ -91,6 +99,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
|||||||
wl = target.wl;
|
wl = target.wl;
|
||||||
wp = target.wp;
|
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 (wl != NULL) {
|
||||||
if (wp != NULL) {
|
if (wp != NULL) {
|
||||||
window_redraw_active_switch(wp->window, wp);
|
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)
|
if (fflag)
|
||||||
server_client_set_flags(c, fflag);
|
server_client_set_flags(c, fflag);
|
||||||
if (rflag) {
|
if (rflag) {
|
||||||
if (c->flags & CLIENT_READONLY) {
|
if (ro) {
|
||||||
uid = proc_get_peer_uid(c->peer);
|
uid = proc_get_peer_uid(c->peer);
|
||||||
if (uid != getuid()) {
|
if (uid != getuid()) {
|
||||||
cmdq_error(item, "client is read-only");
|
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);
|
server_client_detach(c_loop, msgtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Eflag)
|
if (!Eflag && (~c->flags & CLIENT_READONLY))
|
||||||
environ_update(s->options, c->environ, s->environ);
|
environ_update(s->options, c->environ, s->environ);
|
||||||
|
|
||||||
server_client_set_session(c, s);
|
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);
|
server_client_detach(c_loop, msgtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Eflag)
|
if (!Eflag && (~c->flags & CLIENT_READONLY))
|
||||||
environ_update(s->options, c->environ, s->environ);
|
environ_update(s->options, c->environ, s->environ);
|
||||||
|
|
||||||
server_client_set_session(c, s);
|
server_client_set_session(c, s);
|
||||||
|
|||||||
@@ -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 <thomas@xteddy.org>
|
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#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);
|
u_int idx, char **cause);
|
||||||
static enum cmd_retval cmd_choose_tree_exec(struct cmd *,
|
static enum cmd_retval cmd_choose_tree_exec(struct cmd *,
|
||||||
struct cmdq_item *);
|
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 = {
|
const struct cmd_entry cmd_choose_tree_entry = {
|
||||||
.name = "choose-tree",
|
.name = "choose-tree",
|
||||||
@@ -93,9 +99,9 @@ const struct cmd_entry cmd_switch_mode_entry = {
|
|||||||
.description = "Switch the active pane mode.",
|
.description = "Switch the active pane mode.",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:kO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:kO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-krsZw] [-F format] [-O sort-order] " CMD_TARGET_PANE_USAGE
|
.usage = "[-krsZw] [-F format] [-f path] [-O sort-order] "
|
||||||
" [command]",
|
CMD_TARGET_PANE_USAGE " [command]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.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 args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
const struct window_mode *mode;
|
const struct window_mode *mode;
|
||||||
enum sort_order order;
|
enum sort_order order;
|
||||||
|
char *path;
|
||||||
|
|
||||||
order = sort_order_from_string(args_get(args, 'O'));
|
order = sort_order_from_string(args_get(args, 'O'));
|
||||||
if (order == SORT_END && args_has(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
|
else
|
||||||
mode = &window_tree_mode;
|
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);
|
window_pane_set_mode(wp, NULL, mode, item, target, args);
|
||||||
return (CMD_RETURN_NORMAL);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -1019,6 +1019,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
|||||||
cmdq_error(item, "no current client");
|
cmdq_error(item, "no current client");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
fs->s = c->session;
|
||||||
fs->wl = c->session->curw;
|
fs->wl = c->session->curw;
|
||||||
fs->wp = c->session->curw->window->active;
|
fs->wp = c->session->curw->window->active;
|
||||||
fs->w = c->session->curw->window;
|
fs->w = c->session->curw->window;
|
||||||
|
|||||||
11
cmd-queue.c
11
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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -594,6 +594,15 @@ cmdq_fire_command(struct cmdq_item *item)
|
|||||||
flags = !!(state->flags & CMDQ_STATE_CONTROL);
|
flags = !!(state->flags & CMDQ_STATE_CONTROL);
|
||||||
cmdq_guard(item, "begin", flags);
|
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)
|
if (item->client == NULL)
|
||||||
item->client = cmd_find_client(item, NULL, 1);
|
item->client = cmd_find_client(item, NULL, 1);
|
||||||
|
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -164,6 +164,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
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 client *tc = cmdq_get_target_client(item);
|
||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
struct winlink *wl = target->wl;
|
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);
|
u_int count = args_count(args);
|
||||||
char *cause = NULL;
|
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");
|
cmdq_error(item, "client is read-only");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -66,6 +66,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct sort_criteria sort_crit;
|
struct sort_criteria sort_crit;
|
||||||
uid_t uid;
|
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 &&
|
if (tflag != NULL &&
|
||||||
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) {
|
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) {
|
||||||
type = CMD_FIND_PANE;
|
type = CMD_FIND_PANE;
|
||||||
@@ -80,6 +85,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
wl = target.wl;
|
wl = target.wl;
|
||||||
wp = target.wp;
|
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 (args_has(args, 'r')) {
|
||||||
if (tc->flags & CLIENT_READONLY) {
|
if (tc->flags & CLIENT_READONLY) {
|
||||||
uid = proc_get_peer_uid(c->peer);
|
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);
|
environ_update(s->options, tc->environ, s->environ);
|
||||||
|
|
||||||
server_client_set_session(tc, s);
|
server_client_set_session(tc, s);
|
||||||
|
|||||||
5
format.c
5
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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -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 key_event *event = cmdq_get_event(item);
|
||||||
struct mouse_event *m = &event->m;
|
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);
|
cmdq_merge_formats(item, ft);
|
||||||
memcpy(&ft->m, m, sizeof ft->m);
|
memcpy(&ft->m, m, sizeof ft->m);
|
||||||
}
|
}
|
||||||
|
|||||||
5
hooks.c
5
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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -164,6 +164,7 @@ hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
|
|||||||
break;
|
break;
|
||||||
case CMD_PARSE_SUCCESS:
|
case CMD_PARSE_SUCCESS:
|
||||||
hooks_insert_one(item, hd, pr->cmdlist, state);
|
hooks_insert_one(item, hd, pr->cmdlist, state);
|
||||||
|
cmd_list_free(pr->cmdlist);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -178,10 +179,12 @@ hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
|
|||||||
cmdq_error(item, "%s",
|
cmdq_error(item, "%s",
|
||||||
pr->error);
|
pr->error);
|
||||||
}
|
}
|
||||||
|
free(pr->error);
|
||||||
break;
|
break;
|
||||||
case CMD_PARSE_SUCCESS:
|
case CMD_PARSE_SUCCESS:
|
||||||
item = hooks_insert_one(item, hd,
|
item = hooks_insert_one(item, hd,
|
||||||
pr->cmdlist, state);
|
pr->cmdlist, state);
|
||||||
|
cmd_list_free(pr->cmdlist);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -2274,7 +2274,7 @@ server_client_check_exit(struct client *c, int force)
|
|||||||
if (~c->flags & CLIENT_EXIT)
|
if (~c->flags & CLIENT_EXIT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (c->flags & CLIENT_CONTROL) {
|
if ((c->flags & CLIENT_CONTROL) && c->control_state != NULL) {
|
||||||
if (force)
|
if (force)
|
||||||
control_discard_all(c);
|
control_discard_all(c);
|
||||||
else {
|
else {
|
||||||
@@ -2752,6 +2752,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
|||||||
} else {
|
} else {
|
||||||
values = args_from_vector(argc, argv);
|
values = args_from_vector(argc, argv);
|
||||||
pr = cmd_parse_from_arguments(values, argc, NULL);
|
pr = cmd_parse_from_arguments(values, argc, NULL);
|
||||||
|
args_free_values(values, argc);
|
||||||
|
free(values);
|
||||||
switch (pr->status) {
|
switch (pr->status) {
|
||||||
case CMD_PARSE_ERROR:
|
case CMD_PARSE_ERROR:
|
||||||
cause = pr->error;
|
cause = pr->error;
|
||||||
@@ -2759,8 +2761,6 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
|||||||
case CMD_PARSE_SUCCESS:
|
case CMD_PARSE_SUCCESS:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args_free_values(values, argc);
|
|
||||||
free(values);
|
|
||||||
cmd_free_argv(argc, argv);
|
cmd_free_argv(argc, argv);
|
||||||
if ((c->flags & CLIENT_READONLY) &&
|
if ((c->flags & CLIENT_READONLY) &&
|
||||||
!cmd_list_all_have(pr->cmdlist, CMD_READONLY)) {
|
!cmd_list_all_have(pr->cmdlist, CMD_READONLY)) {
|
||||||
|
|||||||
24
tmux.1
24
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 <nicholas.marriott@gmail.com>
|
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
.\"
|
.\"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" 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
|
.Dt TMUX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -3207,6 +3207,7 @@ command works only if at least one client is attached.
|
|||||||
.Ic switch\-mode
|
.Ic switch\-mode
|
||||||
.Op Fl krsZw
|
.Op Fl krsZw
|
||||||
.Op Fl F Ar format
|
.Op Fl F Ar format
|
||||||
|
.Op Fl f Ar path
|
||||||
.Op Fl O Ar sort\-order
|
.Op Fl O Ar sort\-order
|
||||||
.Op Fl t Ar target\-pane
|
.Op Fl t Ar target\-pane
|
||||||
.Op Ar command
|
.Op Ar command
|
||||||
@@ -3252,6 +3253,24 @@ If
|
|||||||
is not given, "switch\-client \-Zt \[aq]%%\[aq]" is used.
|
is not given, "switch\-client \-Zt \[aq]%%\[aq]" is used.
|
||||||
.Fl F
|
.Fl F
|
||||||
specifies the format for each item in the list.
|
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
|
.Fl k
|
||||||
kills the pane when the mode is exited.
|
kills the pane when the mode is exited.
|
||||||
.Pp
|
.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 "session_windows" Ta "" Ta "Number of windows in session"
|
||||||
.It Li "socket_path" Ta "" Ta "Server socket path"
|
.It Li "socket_path" Ta "" Ta "Server socket path"
|
||||||
.It Li "start_time" Ta "" Ta "Server start time"
|
.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 "synchronized_output_flag" Ta "" Ta "1 if pane has synchronized output enabled"
|
||||||
.It Li "uid" Ta "" Ta "Server UID"
|
.It Li "uid" Ta "" Ta "Server UID"
|
||||||
.It Li "user" Ta "" Ta "Server user"
|
.It Li "user" Ta "" Ta "Server user"
|
||||||
|
|||||||
3
tmux.h
3
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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -3989,6 +3989,7 @@ extern const struct window_mode window_tree_mode;
|
|||||||
|
|
||||||
/* window-switch.c */
|
/* window-switch.c */
|
||||||
extern const struct window_mode window_switch_mode;
|
extern const struct window_mode window_switch_mode;
|
||||||
|
void window_switch_set_input(struct window_mode_entry *, struct evbuffer *);
|
||||||
|
|
||||||
/* window-clock.c */
|
/* window-clock.c */
|
||||||
extern const struct window_mode window_clock_mode;
|
extern const struct window_mode window_clock_mode;
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -415,6 +415,8 @@ tty_term_apply(struct tty_term *term, const char *capabilities, int quiet,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (remove) {
|
if (remove) {
|
||||||
|
if (code->type == TTYCODE_STRING)
|
||||||
|
free(code->value.string);
|
||||||
code->type = TTYCODE_NONE;
|
code->type = TTYCODE_NONE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -1430,6 +1430,7 @@ monitor:
|
|||||||
if (wo != NULL && options_owner(o) != wo) {
|
if (wo != NULL && options_owner(o) != wo) {
|
||||||
parent = options_get_only(wo, name);
|
parent = options_get_only(wo, name);
|
||||||
if (parent != NULL) {
|
if (parent != NULL) {
|
||||||
|
free(value);
|
||||||
value = options_to_string(parent, NULL, 0);
|
value = options_to_string(parent, NULL, 0);
|
||||||
xsnprintf(label, sizeof label,
|
xsnprintf(label, sizeof label,
|
||||||
"Window value (from window %u): ", fs.wl->idx);
|
"Window value (from window %u): ", fs.wl->idx);
|
||||||
@@ -1442,6 +1443,7 @@ monitor:
|
|||||||
if (go != NULL && options_owner(o) != go) {
|
if (go != NULL && options_owner(o) != go) {
|
||||||
parent = options_get_only(go, name);
|
parent = options_get_only(go, name);
|
||||||
if (parent != NULL) {
|
if (parent != NULL) {
|
||||||
|
free(value);
|
||||||
value = options_to_string(parent, NULL, 0);
|
value = options_to_string(parent, NULL, 0);
|
||||||
if (!window_customize_write_value(ctx, s->cx, sx,
|
if (!window_customize_write_value(ctx, s->cx, sx,
|
||||||
sy - (s->cy - cy), 0, "Global value: ", "%s%s%s",
|
sy - (s->cy - cy), 0, "Global value: ", "%s%s%s",
|
||||||
|
|||||||
@@ -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 <nicholas.marriott@gmail.com>
|
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -63,7 +63,8 @@ const struct window_mode window_switch_mode = {
|
|||||||
|
|
||||||
enum window_switch_type {
|
enum window_switch_type {
|
||||||
WINDOW_SWITCH_TYPE_SESSION,
|
WINDOW_SWITCH_TYPE_SESSION,
|
||||||
WINDOW_SWITCH_TYPE_WINDOW
|
WINDOW_SWITCH_TYPE_WINDOW,
|
||||||
|
WINDOW_SWITCH_TYPE_INPUT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct window_switch_itemdata {
|
struct window_switch_itemdata {
|
||||||
@@ -73,6 +74,7 @@ struct window_switch_itemdata {
|
|||||||
|
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
char *text;
|
char *text;
|
||||||
|
const char *value;
|
||||||
bitstr_t *match;
|
bitstr_t *match;
|
||||||
|
|
||||||
u_int score;
|
u_int score;
|
||||||
@@ -87,6 +89,9 @@ struct window_switch_modedata {
|
|||||||
char *format;
|
char *format;
|
||||||
char *command;
|
char *command;
|
||||||
|
|
||||||
|
char **lines;
|
||||||
|
u_int lines_size;
|
||||||
|
|
||||||
enum window_switch_type type;
|
enum window_switch_type type;
|
||||||
enum sort_order order;
|
enum sort_order order;
|
||||||
int reversed;
|
int reversed;
|
||||||
@@ -165,6 +170,20 @@ window_switch_add_window(struct window_switch_modedata *data,
|
|||||||
format_free(ft);
|
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
|
static int
|
||||||
window_switch_compare(const void *a0, const void *b0)
|
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 session **sl;
|
||||||
struct winlink **wl;
|
struct winlink **wl;
|
||||||
struct sort_criteria sort_crit;
|
struct sort_criteria sort_crit;
|
||||||
|
struct cmd_find_state fs;
|
||||||
|
struct format_tree *ft;
|
||||||
|
|
||||||
sort_crit.order = data->order;
|
sort_crit.order = data->order;
|
||||||
sort_crit.reversed = data->reversed;
|
sort_crit.reversed = data->reversed;
|
||||||
@@ -214,6 +235,14 @@ window_switch_build(struct window_switch_modedata *data)
|
|||||||
for (i = 0; i < nw; i++)
|
for (i = 0; i < nw; i++)
|
||||||
window_switch_add_window(data, wl[i], &order);
|
window_switch_add_window(data, wl[i], &order);
|
||||||
break;
|
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++) {
|
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;
|
data->type = WINDOW_SWITCH_TYPE_WINDOW;
|
||||||
else
|
else
|
||||||
data->type = WINDOW_SWITCH_TYPE_SESSION;
|
data->type = WINDOW_SWITCH_TYPE_SESSION;
|
||||||
|
if (args_has(args, 'f'))
|
||||||
|
data->type = WINDOW_SWITCH_TYPE_INPUT;
|
||||||
|
|
||||||
data->filter = xstrdup("");
|
data->filter = xstrdup("");
|
||||||
if (args == NULL || !args_has(args, 'F'))
|
if (args == NULL || !args_has(args, 'F')) {
|
||||||
data->format = xstrdup(WINDOW_SWITCH_DEFAULT_FORMAT);
|
if (data->type == WINDOW_SWITCH_TYPE_INPUT)
|
||||||
else
|
data->format = xstrdup("#{switch_item}");
|
||||||
|
else
|
||||||
|
data->format = xstrdup(WINDOW_SWITCH_DEFAULT_FORMAT);
|
||||||
|
} else
|
||||||
data->format = xstrdup(args_get(args, 'F'));
|
data->format = xstrdup(args_get(args, 'F'));
|
||||||
if (args == NULL || args_count(args) == 0)
|
if (args == NULL || args_count(args) == 0)
|
||||||
data->command = xstrdup(WINDOW_SWITCH_DEFAULT_COMMAND);
|
data->command = xstrdup(WINDOW_SWITCH_DEFAULT_COMMAND);
|
||||||
@@ -407,6 +441,36 @@ window_switch_init(struct window_mode_entry *wme,
|
|||||||
return (s);
|
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
|
static void
|
||||||
window_switch_free(struct window_mode_entry *wme)
|
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++)
|
for (i = 0; i < data->item_size; i++)
|
||||||
window_switch_free_item(data->item_list[i]);
|
window_switch_free_item(data->item_list[i]);
|
||||||
free(data->item_list);
|
free(data->item_list);
|
||||||
|
for (i = 0; i < data->lines_size; i++)
|
||||||
|
free(data->lines[i]);
|
||||||
|
free(data->lines);
|
||||||
|
|
||||||
free(data->matches);
|
free(data->matches);
|
||||||
free(data->filter);
|
free(data->filter);
|
||||||
@@ -477,6 +544,10 @@ window_switch_run_command(struct window_switch_modedata *data, struct client *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WINDOW_SWITCH_TYPE_INPUT:
|
||||||
|
target = xstrdup(item->value);
|
||||||
|
cmd_find_from_pane(&fs, data->wp, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (target == NULL)
|
if (target == NULL)
|
||||||
return (0);
|
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);
|
command = cmd_template_replace(data->command, target, 1);
|
||||||
if (command != NULL && *command != '\0') {
|
if (command != NULL && *command != '\0') {
|
||||||
state = cmdq_new_state(&fs, NULL, 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);
|
status = cmd_parse_and_append(command, NULL, c, state, &error);
|
||||||
if (status == CMD_PARSE_ERROR) {
|
if (status == CMD_PARSE_ERROR) {
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
@@ -539,7 +612,8 @@ window_switch_key(struct window_mode_entry *wme, struct client *c,
|
|||||||
return;
|
return;
|
||||||
if (data->prompt != NULL && screen_size_y(&data->screen) != 0 &&
|
if (data->prompt != NULL && screen_size_y(&data->screen) != 0 &&
|
||||||
y == screen_size_y(&data->screen) - 1 &&
|
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)) {
|
!MOUSE_RELEASE(m->b)) {
|
||||||
result = prompt_mouse(data->prompt, x, 0,
|
result = prompt_mouse(data->prompt, x, 0,
|
||||||
screen_size_x(&data->screen), &redraw);
|
screen_size_x(&data->screen), &redraw);
|
||||||
|
|||||||
Reference in New Issue
Block a user