mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 21:02:11 +00:00
vim-patch:9.2.0209: freeze during wildmenu completion (#38386)
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: vim/vim#19742
closes: vim/vim#19744
332dd22ed4
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
This commit is contained in:
@@ -1261,21 +1261,23 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
return (res == OK) ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED;
|
||||
}
|
||||
|
||||
static void command_line_end_wildmenu(CommandLineState *s, bool key_is_wc)
|
||||
static void command_line_end_wildmenu(CommandLineState *s, bool key_is_wc, int c)
|
||||
{
|
||||
if (cmdline_pum_active()) {
|
||||
s->skip_pum_redraw = (s->skip_pum_redraw && !key_is_wc
|
||||
&& !ascii_iswhite(s->c)
|
||||
&& (vim_isprintc(s->c)
|
||||
|| s->c == K_BS || s->c == Ctrl_H || s->c == K_DEL
|
||||
|| s->c == K_KDEL || s->c == Ctrl_W || s->c == Ctrl_U));
|
||||
cmdline_pum_remove(s->skip_pum_redraw);
|
||||
if (c != -1) {
|
||||
s->skip_pum_redraw = (s->skip_pum_redraw && !key_is_wc
|
||||
&& !ascii_iswhite(c)
|
||||
&& (vim_isprintc(c)
|
||||
|| c == K_BS || c == Ctrl_H || c == K_DEL
|
||||
|| c == K_KDEL || c == Ctrl_W || c == Ctrl_U));
|
||||
}
|
||||
cmdline_pum_remove(c != -1 && s->skip_pum_redraw);
|
||||
}
|
||||
if (s->xpc.xp_numfiles != -1) {
|
||||
ExpandOne(&s->xpc, NULL, NULL, 0, WILD_FREE);
|
||||
}
|
||||
s->did_wild_list = false;
|
||||
if (!p_wmnu || (s->c != K_UP && s->c != K_DOWN)) {
|
||||
if (!p_wmnu || (c != K_UP && c != K_DOWN)) {
|
||||
s->xpc.xp_context = EXPAND_NOTHING;
|
||||
}
|
||||
s->wim_index = 0;
|
||||
@@ -1292,6 +1294,14 @@ static int command_line_execute(VimState *state, int key)
|
||||
CommandLineState *s = (CommandLineState *)state;
|
||||
s->c = key;
|
||||
|
||||
// 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 && s->xpc.xp_numfiles > 0) {
|
||||
command_line_end_wildmenu(s, false, -1);
|
||||
}
|
||||
ccline.cmdbuff_replaced = false;
|
||||
|
||||
// Skip wildmenu during history navigation via Up/Down keys
|
||||
if (s->c == K_WILD && s->did_hist_navigate) {
|
||||
s->did_hist_navigate = false;
|
||||
@@ -1322,7 +1332,7 @@ static int command_line_execute(VimState *state, int key)
|
||||
nextwild(&s->xpc, WILD_PUM_WANT, 0, s->firstc != '@');
|
||||
if (pum_want.finish) {
|
||||
nextwild(&s->xpc, WILD_APPLY, WILD_NO_BEEP, s->firstc != '@');
|
||||
command_line_end_wildmenu(s, false);
|
||||
command_line_end_wildmenu(s, false, s->c);
|
||||
}
|
||||
}
|
||||
pum_want.active = false;
|
||||
@@ -1430,7 +1440,7 @@ static int command_line_execute(VimState *state, int key)
|
||||
|
||||
// free expanded names when finished walking through matches
|
||||
if (end_wildmenu) {
|
||||
command_line_end_wildmenu(s, key_is_wc);
|
||||
command_line_end_wildmenu(s, key_is_wc, s->c);
|
||||
}
|
||||
|
||||
if (p_wmnu) {
|
||||
@@ -4388,6 +4398,7 @@ static int set_cmdline_str(const char *str, int pos)
|
||||
|
||||
p->cmdpos = pos < 0 || pos > p->cmdlen ? p->cmdlen : pos;
|
||||
new_cmdpos = p->cmdpos;
|
||||
p->cmdbuff_replaced = true;
|
||||
|
||||
redrawcmd();
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ struct cmdline_info {
|
||||
int xp_context; ///< type of expansion
|
||||
char *xp_arg; ///< user-defined expansion arg
|
||||
int input_fn; ///< when true Invoked for input() function
|
||||
bool cmdbuff_replaced; ///< when true cmdline was replaced externally
|
||||
///< (e.g. by setcmdline())
|
||||
unsigned prompt_id; ///< Prompt number, used to disable coloring on errors.
|
||||
Callback highlight_callback; ///< Callback used for coloring user input.
|
||||
ColoredCmdline last_colors; ///< Last cmdline colors
|
||||
|
||||
@@ -4410,6 +4410,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()
|
||||
|
||||
Reference in New Issue
Block a user