patch 9.2.0209: freeze during wildmenu completion

Problem:  Vim may freeze if setcmdline() is called while the wildmenu or
          cmdline popup menu is active (rendcrx)
Solution: Cleanup completion state if cmdbuff_replaced flag has been set
          (Yasuhiro Matsumoto)

fixes:  #19742
closes: #19744

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yasuhiro Matsumoto
2026-03-19 21:59:45 +00:00
committed by Christian Brabandt
parent 67ae763557
commit 332dd22ed4
4 changed files with 37 additions and 0 deletions
+16
View File
@@ -1899,6 +1899,21 @@ getcmdline_int(
c = safe_vgetc();
} while (c == K_IGNORE || c == K_NOP);
// If the cmdline was replaced externally (e.g. by setcmdline()
// during an <expr> mapping), clean up the wildmenu completion
// state to avoid using stale completion data.
if (ccline.cmdbuff_replaced && xpc.xp_numfiles > 0)
{
if (cmdline_pum_active())
cmdline_pum_remove(&ccline, FALSE);
(void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
did_wild_list = FALSE;
xpc.xp_context = EXPAND_NOTHING;
wim_index = 0;
wildmenu_cleanup(&ccline);
}
ccline.cmdbuff_replaced = FALSE;
// Skip wildmenu during history navigation via Up/Down keys
if (c == K_WILD && did_hist_navigate)
{
@@ -4518,6 +4533,7 @@ set_cmdline_str(char_u *str, int pos)
p->cmdpos = pos < 0 || pos > p->cmdlen ? p->cmdlen : pos;
new_cmdpos = p->cmdpos;
p->cmdbuff_replaced = TRUE;
redrawcmd();
+2
View File
@@ -716,6 +716,8 @@ typedef struct
char_u *xp_arg; // user-defined expansion arg
int input_fn; // when TRUE Invoked for input() function
#endif
int cmdbuff_replaced; // when TRUE cmdline was replaced externally
// (e.g. by setcmdline())
} cmdline_info_T;
/*
+17
View File
@@ -4488,6 +4488,23 @@ func Test_setcmdline()
call feedkeys(":a\<CR>", 'tx')
call assert_equal('let foo=0', @:)
cunmap a
" setcmdline() during wildmenu completion should not freeze.
" Stripping completion state when cmdline was replaced externally.
set wildmenu
call mkdir('Xsetcmdlinedir', 'pR')
call writefile([], 'Xsetcmdlinedir/Xfile1')
call writefile([], 'Xsetcmdlinedir/Xfile2')
func g:SetCmdLineEmpty()
call setcmdline('', 1)
return "\<Left>"
endfunc
cnoremap <expr> a g:SetCmdLineEmpty()
call feedkeys(":e Xsetcmdlinedir/\<Tab>a\<C-B>\"\<CR>", 'tx')
call assert_equal('"', @:)
cunmap a
delfunc g:SetCmdLineEmpty
set nowildmenu
endfunc
func Test_rulerformat_position()
+2
View File
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
209,
/**/
208,
/**/