]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0209: freeze during wildmenu completion v9.2.0209
authorYasuhiro Matsumoto <mattn.jp@gmail.com>
Thu, 19 Mar 2026 21:59:45 +0000 (21:59 +0000)
committerChristian Brabandt <cb@256bit.org>
Thu, 19 Mar 2026 21:59:45 +0000 (21:59 +0000)
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>
src/ex_getln.c
src/structs.h
src/testdir/test_cmdline.vim
src/version.c

index ce28088d56ddcb38fdb9e7dbfd2656eba7371710..917e67529bf3616f333a34e12c8421e719a148fe 100644 (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();
 
index 2b8cb3db1ff8f3de6d9371169ed2c5a36a174da0..0e61aedef4bc47c04d553365edcd292558a84c42 100644 (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;
 
 /*
index 419d487233bc5a8c529da2fb57a1d39f779159ed..2810e0b7e8e7435f553d45e7f1caef03c0cf7700 100644 (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()
index bd95e9e3c45a151b9c0248fb903fce25bc510c89..820096693416a9ca5720706a56348e27ab8ea0a0 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    209,
 /**/
     208,
 /**/