From 147521b7578fabc998d5a16b4e6971321836f1a0 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 13 Apr 2026 09:33:09 +0000 Subject: [PATCH 01/11] Add -C flag to command-prompt to match display-message -C (do not freeze panes). From Barrett Ruth in GitHub issue 4978. --- cmd-command-prompt.c | 6 ++++-- status.c | 2 +- tmux.1 | 5 ++++- tmux.h | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index e5c2b12c..c5f958cd 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -42,8 +42,8 @@ const struct cmd_entry cmd_command_prompt_entry = { .name = "command-prompt", .alias = NULL, - .args = { "1beFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, - .usage = "[-1beFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE + .args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, + .usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [-T prompt-type] [template]", .flags = CMD_CLIENT_TFLAG, @@ -165,6 +165,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cdata->flags |= PROMPT_KEY; else if (args_has(args, 'e')) cdata->flags |= PROMPT_BSPACE_EXIT; + if (args_has(args, 'C')) + cdata->flags |= PROMPT_NOFREEZE; status_prompt_set(tc, target, cdata->prompts[0].prompt, cdata->prompts[0].input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); diff --git a/status.c b/status.c index c39d0d8f..5ecf7bf9 100644 --- a/status.c +++ b/status.c @@ -728,7 +728,7 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs, c->prompt_type = prompt_type; c->prompt_mode = PROMPT_ENTRY; - if (~flags & PROMPT_INCREMENTAL) + if ((~flags & PROMPT_INCREMENTAL) && (~flags & PROMPT_NOFREEZE)) c->tty.flags |= TTY_FREEZE; c->flags |= CLIENT_REDRAWSTATUS; diff --git a/tmux.1 b/tmux.1 index 5a457420..ae86c1dc 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6911,7 +6911,7 @@ See for possible values for .Ar prompt\-type . .It Xo Ic command\-prompt -.Op Fl 1beFiklN +.Op Fl 1bCeFiklN .Op Fl I Ar inputs .Op Fl p Ar prompts .Op Fl t Ar target\-client @@ -6981,6 +6981,9 @@ is like but the key press is translated to a key name. .Fl N 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 executes the command every time the prompt input changes instead of when the user exits the command prompt. diff --git a/tmux.h b/tmux.h index 49519d0e..00a1c94a 100644 --- a/tmux.h +++ b/tmux.h @@ -2112,6 +2112,7 @@ struct client { #define PROMPT_ACCEPT 0x20 #define PROMPT_QUOTENEXT 0x40 #define PROMPT_BSPACE_EXIT 0x80 +#define PROMPT_NOFREEZE 0x100 int prompt_flags; enum prompt_type prompt_type; int prompt_cursor; From e5a2a25fafb8ee107c230d8acad694f6b635f8bb Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 13 Apr 2026 09:35:20 +0000 Subject: [PATCH 02/11] Do not notify clients if not fully initialized, from Ben Maurer in GitHub issue 4980. --- control-notify.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/control-notify.c b/control-notify.c index ba6a8355..0ced0c87 100644 --- a/control-notify.c +++ b/control-notify.c @@ -24,7 +24,8 @@ #include "tmux.h" #define CONTROL_SHOULD_NOTIFY_CLIENT(c) \ - ((c) != NULL && ((c)->flags & CLIENT_CONTROL)) + ((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \ + (c)->control_state != NULL) void control_notify_pane_mode_changed(int pane) From cc57913d7a76f957523b450966ae09255034310e Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 07:16:02 +0000 Subject: [PATCH 03/11] Add WAYLAND_DISPLAY to default update-environment, GitHub issue 4965 from wgh at torlan dot ru. --- options-table.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/options-table.c b/options-table.c index 55abe679..6d1e6552 100644 --- a/options-table.c +++ b/options-table.c @@ -415,10 +415,10 @@ const struct options_table_entry options_table[] = { .choices = options_table_get_clipboard_list, .default_num = 1, .text = "When an application requests the clipboard, whether to " - "ignore the request ('off'); respond with the newest buffer " - "('buffer'); request the clipboard from the most recently " - "used terminal ('request'); or to request the clipboard, " - "create a buffer, and send it to the application ('both')." + "ignore the request ('off'); respond with the newest buffer " + "('buffer'); request the clipboard from the most recently " + "used terminal ('request'); or to request the clipboard, " + "create a buffer, and send it to the application ('both')." }, { .name = "history-file", @@ -1025,7 +1025,8 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SESSION, .flags = OPTIONS_TABLE_IS_ARRAY, .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 " "environment when a client is attached." }, From a11363e9e7c3dca151a773193c1d0a2fad39180e Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 07:24:23 +0000 Subject: [PATCH 04/11] Limit precision to 100 to stop silly formats from running out of memory, reported by z1281552865 at gmail dot com. --- format.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/format.c b/format.c index db769668..9e671428 100644 --- a/format.c +++ b/format.c @@ -90,6 +90,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) /* Maimum repeat size. */ #define FORMAT_MAX_REPEAT 10000 +/* Maimum precision. */ +#define FORMAT_MAX_PRECISION 100 + /* Format modifiers. */ #define FORMAT_TIMESTRING 0x1 #define FORMAT_BASENAME 0x2 @@ -4850,7 +4853,8 @@ format_replace_expression(struct format_modifier *mexp, /* The third argument may be precision. */ 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) { format_log(es, "expression precision %s: %s", errstr, mexp->argv[2]); From 51109e3f72c4429b6213e7c9329ab232fd9111ea Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 07:26:45 +0000 Subject: [PATCH 05/11] Include window bits for pane notifications, GitHub issue 5007 from Saul Nogueras. --- notify.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/notify.c b/notify.c index aadfd450..ac5d2e92 100644 --- a/notify.c +++ b/notify.c @@ -209,8 +209,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_name", "%s", w->name); } - if (wp != NULL) + if (wp != NULL) { 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__); if (c != NULL) From 663e82bc19b01a1809d845a27e552f9f1c208483 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 07:28:57 +0000 Subject: [PATCH 06/11] Fix key binding conflict in session menu, from Dane Jensen. --- key-bindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key-bindings.c b/key-bindings.c index a6c726f6..85fa7c80 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -29,7 +29,7 @@ " 'Previous' 'p' {switch-client -p}" \ " ''" \ " 'Renumber' 'N' {move-window -r}" \ - " 'Rename' 'n' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ + " 'Rename' 'r' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ " ''" \ " 'New Session' 's' {new-session}" \ " 'New Window' 'w' {new-window}" From 86d4d5689cb53372ff3766016a954d69428d149a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 07:35:17 +0000 Subject: [PATCH 07/11] Add detach to default session menu, suggested by Przemyslaw Sztoch. --- key-bindings.c | 1 + 1 file changed, 1 insertion(+) diff --git a/key-bindings.c b/key-bindings.c index 85fa7c80..9bc69045 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -30,6 +30,7 @@ " ''" \ " 'Renumber' 'N' {move-window -r}" \ " 'Rename' 'r' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ + " 'Detach' 'd' {detach-client}" \ " ''" \ " 'New Session' 's' {new-session}" \ " 'New Window' 'w' {new-window}" From 31c93c483afa4f94ef2091c8d9f25db4731d0e7f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 08:32:30 +0000 Subject: [PATCH 08/11] Another check for partially initialized control client, from Matt Koscica in GitHub issue 5004. --- control.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/control.c b/control.c index 00544aa1..e4efb01f 100644 --- a/control.c +++ b/control.c @@ -829,6 +829,9 @@ control_stop(struct client *c) struct control_block *cb, *cb1; struct control_sub *csub, *csub1; + if (cs == NULL) + return; + if (~c->flags & CLIENT_CONTROLCONTROL) bufferevent_free(cs->write_event); bufferevent_free(cs->read_event); @@ -842,6 +845,7 @@ control_stop(struct client *c) control_free_block(cs, cb); control_reset_offsets(c); + c->control_state = NULL; free(cs); } From 67e6f8245b63485d374b1dd87655e0245094ae64 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 08:39:10 +0000 Subject: [PATCH 09/11] If job_run fails, do not crash but instead free the popup. --- popup.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/popup.c b/popup.c index 4ef1cc0a..c31977ba 100644 --- a/popup.c +++ b/popup.c @@ -104,6 +104,27 @@ static const struct menu_item popup_internal_menu_items[] = { { 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 popup_reapply_styles(struct popup_data *pd) { @@ -344,22 +365,8 @@ popup_free_cb(struct client *c, void *data) cmdq_get_client(item)->retval = pd->status; cmdq_continue(item); } - 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); + popup_free(pd); } static void @@ -858,6 +865,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, popup_job_update_cb, popup_job_complete_cb, NULL, pd, 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->palette, c); } From a97cfe513d8a2fe54935e81be63b7c0f1cfb7dce Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 14 Apr 2026 11:25:41 +0000 Subject: [PATCH 10/11] Do not leak old time format if it is replaced in same format. --- format.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/format.c b/format.c index 9e671428..88fb227a 100644 --- a/format.c +++ b/format.c @@ -5047,8 +5047,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, if (strchr(fm->argv[0], 'p') != NULL) modifiers |= FORMAT_PRETTY; 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]); + } break; case 'q': if (fm->argc < 1) From dd62c2f9467f975388f4a2701022752961bdb086 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 15 Apr 2026 16:21:35 +0100 Subject: [PATCH 11/11] Do not need to create a new window each time for input-keys.sh test. --- regress/input-keys.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/regress/input-keys.sh b/regress/input-keys.sh index d3b90995..96d2d5e8 100644 --- a/regress/input-keys.sh +++ b/regress/input-keys.sh @@ -7,9 +7,10 @@ TERM=screen TMUX="$TEST_TMUX -Ltest" $TMUX kill-server 2>/dev/null 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 -$TMUX set -g escape-time 0 exit_status=0 @@ -17,14 +18,13 @@ assert_key () { key=$1 expected_code=$2 - W=$($TMUX new-window -P -- sh -c 'stty raw -echo && cat -tv') - $TMUX send-keys -t$W "$key" 'EOL' || exit 1 - sleep 0.2 + $TMUX send-keys -t$W -R \; \ + clear-history -t$W \; \ + send-keys -t$W "$key" 'EOL' || exit 1 actual_code=$($TMUX capturep -pt$W | \ head -1 | \ sed -e 's/EOL.*$//') - $TMUX kill-window -t$W || exit 1 if [ "$actual_code" = "$expected_code" ]; then if [ -n "$VERBOSE" ]; then