Merge branch 'master' into floating_panes

This commit is contained in:
Michael Grant
2026-04-15 23:26:02 -04:00
12 changed files with 69 additions and 35 deletions

View File

@@ -42,8 +42,8 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", .name = "command-prompt",
.alias = NULL, .alias = NULL,
.args = { "1beFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, .args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
.usage = "[-1beFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE .usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
" [-T prompt-type] [template]", " [-T prompt-type] [template]",
.flags = CMD_CLIENT_TFLAG, .flags = CMD_CLIENT_TFLAG,
@@ -165,6 +165,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_KEY; cdata->flags |= PROMPT_KEY;
else if (args_has(args, 'e')) else if (args_has(args, 'e'))
cdata->flags |= PROMPT_BSPACE_EXIT; cdata->flags |= PROMPT_BSPACE_EXIT;
if (args_has(args, 'C'))
cdata->flags |= PROMPT_NOFREEZE;
status_prompt_set(tc, target, cdata->prompts[0].prompt, status_prompt_set(tc, target, cdata->prompts[0].prompt,
cdata->prompts[0].input, cmd_command_prompt_callback, cdata->prompts[0].input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);

View File

@@ -24,7 +24,8 @@
#include "tmux.h" #include "tmux.h"
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \ #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
((c) != NULL && ((c)->flags & CLIENT_CONTROL)) ((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \
(c)->control_state != NULL)
void void
control_notify_pane_mode_changed(int pane) control_notify_pane_mode_changed(int pane)

View File

@@ -828,6 +828,9 @@ control_stop(struct client *c)
struct control_block *cb, *cb1; struct control_block *cb, *cb1;
struct control_sub *csub, *csub1; struct control_sub *csub, *csub1;
if (cs == NULL)
return;
if (~c->flags & CLIENT_CONTROLCONTROL) if (~c->flags & CLIENT_CONTROLCONTROL)
bufferevent_free(cs->write_event); bufferevent_free(cs->write_event);
bufferevent_free(cs->read_event); bufferevent_free(cs->read_event);
@@ -841,6 +844,7 @@ control_stop(struct client *c)
control_free_block(cs, cb); control_free_block(cs, cb);
control_reset_offsets(c); control_reset_offsets(c);
c->control_state = NULL;
free(cs); free(cs);
} }

View File

@@ -90,6 +90,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
/* Maimum repeat size. */ /* Maimum repeat size. */
#define FORMAT_MAX_REPEAT 10000 #define FORMAT_MAX_REPEAT 10000
/* Maimum precision. */
#define FORMAT_MAX_PRECISION 100
/* Format modifiers. */ /* Format modifiers. */
#define FORMAT_TIMESTRING 0x1 #define FORMAT_TIMESTRING 0x1
#define FORMAT_BASENAME 0x2 #define FORMAT_BASENAME 0x2
@@ -4886,7 +4889,8 @@ format_replace_expression(struct format_modifier *mexp,
/* The third argument may be precision. */ /* The third argument may be precision. */
if (argc >= 3) { if (argc >= 3) {
prec = strtonum(mexp->argv[2], INT_MIN + 1, INT_MAX, &errstr); prec = strtonum(mexp->argv[2], -FORMAT_MAX_PRECISION,
FORMAT_MAX_PRECISION, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
format_log(es, "expression precision %s: %s", errstr, format_log(es, "expression precision %s: %s", errstr,
mexp->argv[2]); mexp->argv[2]);
@@ -5079,8 +5083,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
if (strchr(fm->argv[0], 'p') != NULL) if (strchr(fm->argv[0], 'p') != NULL)
modifiers |= FORMAT_PRETTY; modifiers |= FORMAT_PRETTY;
else if (fm->argc >= 2 && else if (fm->argc >= 2 &&
strchr(fm->argv[0], 'f') != NULL) strchr(fm->argv[0], 'f') != NULL) {
free(time_format);
time_format = format_strip(fm->argv[1]); time_format = format_strip(fm->argv[1]);
}
break; break;
case 'q': case 'q':
if (fm->argc < 1) if (fm->argc < 1)

View File

@@ -29,7 +29,8 @@
" 'Previous' 'p' {switch-client -p}" \ " 'Previous' 'p' {switch-client -p}" \
" ''" \ " ''" \
" 'Renumber' 'N' {move-window -r}" \ " 'Renumber' 'N' {move-window -r}" \
" 'Rename' 'n' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ " 'Rename' 'r' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \
" 'Detach' 'd' {detach-client}" \
" ''" \ " ''" \
" 'New Session' 's' {new-session}" \ " 'New Session' 's' {new-session}" \
" 'New Window' 'w' {new-window}" " 'New Window' 'w' {new-window}"

View File

@@ -208,8 +208,12 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
format_add(ne->formats, "hook_window", "@%u", w->id); format_add(ne->formats, "hook_window", "@%u", w->id);
format_add(ne->formats, "hook_window_name", "%s", w->name); format_add(ne->formats, "hook_window_name", "%s", w->name);
} }
if (wp != NULL) if (wp != NULL) {
format_add(ne->formats, "hook_pane", "%%%d", wp->id); format_add(ne->formats, "hook_pane", "%%%d", wp->id);
format_add(ne->formats, "hook_window", "@%u", wp->window->id);
format_add(ne->formats, "hook_window_name", "%s",
wp->window->name);
}
format_log_debug(ne->formats, __func__); format_log_debug(ne->formats, __func__);
if (c != NULL) if (c != NULL)

View File

@@ -414,10 +414,10 @@ const struct options_table_entry options_table[] = {
.choices = options_table_get_clipboard_list, .choices = options_table_get_clipboard_list,
.default_num = 1, .default_num = 1,
.text = "When an application requests the clipboard, whether to " .text = "When an application requests the clipboard, whether to "
"ignore the request ('off'); respond with the newest buffer " "ignore the request ('off'); respond with the newest buffer "
"('buffer'); request the clipboard from the most recently " "('buffer'); request the clipboard from the most recently "
"used terminal ('request'); or to request the clipboard, " "used terminal ('request'); or to request the clipboard, "
"create a buffer, and send it to the application ('both')." "create a buffer, and send it to the application ('both')."
}, },
{ .name = "history-file", { .name = "history-file",
@@ -1024,7 +1024,8 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_ARRAY, .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "DISPLAY KRB5CCNAME MSYSTEM SSH_ASKPASS SSH_AUTH_SOCK " .default_str = "DISPLAY KRB5CCNAME MSYSTEM SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY", "SSH_AGENT_PID SSH_CONNECTION WAYLAND_DISPLAY "
"WINDOWID XAUTHORITY",
.text = "List of environment variables to update in the session " .text = "List of environment variables to update in the session "
"environment when a client is attached." "environment when a client is attached."
}, },

41
popup.c
View File

@@ -103,6 +103,27 @@ static const struct menu_item popup_internal_menu_items[] = {
{ NULL, KEYC_NONE, NULL } { NULL, KEYC_NONE, NULL }
}; };
static void
popup_free(struct popup_data *pd)
{
server_client_unref(pd->c);
if (pd->job != NULL)
job_free(pd->job);
input_free(pd->ictx);
free(pd->or[0].ranges);
free(pd->or[1].ranges);
free(pd->r.ranges);
screen_free(&pd->s);
colour_palette_free(&pd->palette);
free(pd->title);
free(pd->style);
free(pd->border_style);
free(pd);
}
static void static void
popup_reapply_styles(struct popup_data *pd) popup_reapply_styles(struct popup_data *pd)
{ {
@@ -343,22 +364,8 @@ popup_free_cb(struct client *c, void *data)
cmdq_get_client(item)->retval = pd->status; cmdq_get_client(item)->retval = pd->status;
cmdq_continue(item); cmdq_continue(item);
} }
server_client_unref(pd->c);
if (pd->job != NULL) popup_free(pd);
job_free(pd->job);
input_free(pd->ictx);
free(pd->or[0].ranges);
free(pd->or[1].ranges);
free(pd->r.ranges);
screen_free(&pd->s);
colour_palette_free(&pd->palette);
free(pd->title);
free(pd->style);
free(pd->border_style);
free(pd);
} }
static void static void
@@ -857,6 +864,10 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
pd->job = job_run(shellcmd, argc, argv, env, s, cwd, pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
popup_job_update_cb, popup_job_complete_cb, NULL, pd, popup_job_update_cb, popup_job_complete_cb, NULL, pd,
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy); JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
if (pd->job == NULL) {
popup_free(pd);
return (-1);
}
pd->ictx = input_init(NULL, job_get_event(pd->job), pd->ictx = input_init(NULL, job_get_event(pd->job),
&pd->palette, c); &pd->palette, c);
} }

View File

@@ -7,9 +7,10 @@ TERM=screen
TMUX="$TEST_TMUX -Ltest" TMUX="$TEST_TMUX -Ltest"
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
sleep 1 sleep 1
$TMUX -f/dev/null new -x20 -y2 -d || exit 1 $TMUX -f/dev/null new -x20 -y2 -d \; set -g escape-time 0 || exit 1
sleep 1
W=$($TMUX new-window -P -- sh -c 'stty raw -echo && cat -tv')
sleep 1 sleep 1
$TMUX set -g escape-time 0
exit_status=0 exit_status=0
@@ -17,14 +18,13 @@ assert_key () {
key=$1 key=$1
expected_code=$2 expected_code=$2
W=$($TMUX new-window -P -- sh -c 'stty raw -echo && cat -tv') $TMUX send-keys -t$W -R \; \
$TMUX send-keys -t$W "$key" 'EOL' || exit 1 clear-history -t$W \; \
sleep 0.2 send-keys -t$W "$key" 'EOL' || exit 1
actual_code=$($TMUX capturep -pt$W | \ actual_code=$($TMUX capturep -pt$W | \
head -1 | \ head -1 | \
sed -e 's/EOL.*$//') sed -e 's/EOL.*$//')
$TMUX kill-window -t$W || exit 1
if [ "$actual_code" = "$expected_code" ]; then if [ "$actual_code" = "$expected_code" ]; then
if [ -n "$VERBOSE" ]; then if [ -n "$VERBOSE" ]; then

View File

@@ -728,7 +728,7 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
c->prompt_type = prompt_type; c->prompt_type = prompt_type;
c->prompt_mode = PROMPT_ENTRY; c->prompt_mode = PROMPT_ENTRY;
if (~flags & PROMPT_INCREMENTAL) if ((~flags & PROMPT_INCREMENTAL) && (~flags & PROMPT_NOFREEZE))
c->tty.flags |= TTY_FREEZE; c->tty.flags |= TTY_FREEZE;
c->flags |= CLIENT_REDRAWSTATUS; c->flags |= CLIENT_REDRAWSTATUS;

5
tmux.1
View File

@@ -7126,7 +7126,7 @@ See
for possible values for for possible values for
.Ar prompt\-type . .Ar prompt\-type .
.It Xo Ic command\-prompt .It Xo Ic command\-prompt
.Op Fl 1beFiklN .Op Fl 1bCeFiklN
.Op Fl I Ar inputs .Op Fl I Ar inputs
.Op Fl p Ar prompts .Op Fl p Ar prompts
.Op Fl t Ar target\-client .Op Fl t Ar target\-client
@@ -7196,6 +7196,9 @@ is like
but the key press is translated to a key name. but the key press is translated to a key name.
.Fl N .Fl N
makes the prompt only accept numeric key presses. makes the prompt only accept numeric key presses.
If
.Fl C
given, panes will continue to be updated while the prompt is displayed.
.Fl i .Fl i
executes the command every time the prompt input changes instead of when the executes the command every time the prompt input changes instead of when the
user exits the command prompt. user exits the command prompt.

1
tmux.h
View File

@@ -2165,6 +2165,7 @@ struct client {
#define PROMPT_ACCEPT 0x20 #define PROMPT_ACCEPT 0x20
#define PROMPT_QUOTENEXT 0x40 #define PROMPT_QUOTENEXT 0x40
#define PROMPT_BSPACE_EXIT 0x80 #define PROMPT_BSPACE_EXIT 0x80
#define PROMPT_NOFREEZE 0x100
int prompt_flags; int prompt_flags;
enum prompt_type prompt_type; enum prompt_type prompt_type;
int prompt_cursor; int prompt_cursor;