diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index eaee6c07a3..a156b83c7d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -134,6 +134,7 @@ typedef struct { int save_msg_scroll; int save_State; // remember State when called int prev_cmdpos; + char *prev_cmdbuff; char *save_p_icm; bool some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are @@ -1013,12 +1014,14 @@ theend: ccline.cmdbuff = NULL; } + xfree(s->prev_cmdbuff); return (uint8_t *)p; } static int command_line_check(VimState *state) { CommandLineState *s = (CommandLineState *)state; + s->prev_cmdpos = ccline.cmdpos; redir_off = true; // Don't redirect the typed command. // Repeated, because a ":redir" inside @@ -1029,6 +1032,10 @@ static int command_line_check(VimState *state) // that occurs while typing a command should // cause the command not to be executed. + if (ccline.cmdbuff != NULL) { + s->prev_cmdbuff = xmemdupz(ccline.cmdbuff, (size_t)ccline.cmdpos); + } + // Trigger SafeState if nothing is pending. may_trigger_safestate(s->xpc.xp_numfiles <= 0); @@ -2288,7 +2295,6 @@ static void may_trigger_cursormovedc(CommandLineState *s) { if (ccline.cmdpos != s->prev_cmdpos) { trigger_cmd_autocmd(s->cmdline_type, EVENT_CURSORMOVEDC); - s->prev_cmdpos = ccline.cmdpos; ccline.redraw_state = MAX(ccline.redraw_state, kCmdRedrawPos); } } @@ -2296,12 +2302,14 @@ static void may_trigger_cursormovedc(CommandLineState *s) static int command_line_not_changed(CommandLineState *s) { may_trigger_cursormovedc(s); + s->prev_cmdpos = ccline.cmdpos; // Incremental searches for "/" and "?": // Enter command_line_not_changed() when a character has been read but the // command line did not change. Then we only search and redraw if something // changed in the past. // Enter command_line_changed() when the command line did change. if (!s->is_state.incsearch_postponed) { + XFREE_CLEAR(s->prev_cmdbuff); return 1; } return command_line_changed(s); @@ -2772,8 +2780,14 @@ static void do_autocmd_cmdlinechanged(int firstc) static int command_line_changed(CommandLineState *s) { - // Trigger CmdlineChanged autocommands. - do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-'); + if (ccline.cmdpos != s->prev_cmdpos + || (s->prev_cmdbuff != NULL + && strncmp(s->prev_cmdbuff, ccline.cmdbuff, (size_t)s->prev_cmdpos) != 0)) { + // Trigger CmdlineChanged autocommands. + do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-'); + } + + XFREE_CLEAR(s->prev_cmdbuff); may_trigger_cursormovedc(s); diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 3e8592a7d8..a49603311e 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -4719,4 +4719,53 @@ func Test_pum_scroll_noselect() call StopVimInTerminal(buf) endfunc +" CmdlineChanged shouldn't trigger if command-line text is unchanged +func Test_cmdline_changed() + let g:cmdchg_count = 0 + let g:cmdprefix = '' + augroup test_CmdlineAugrp | autocmd! + autocmd CmdlineChanged * if getcmdline() =~ g:cmdprefix | let g:cmdchg_count += 1 | endif + augroup END + + new + set wildmenu + set wildmode=full + + let g:cmdprefix = 'echomsg' + let g:cmdchg_count = 0 + call feedkeys(":echomsg\", "tx") + call assert_equal(1, g:cmdchg_count) " once only for 'g', not again for + + let g:cmdchg_count = 0 + let g:cmdprefix = 'echo' + call feedkeys(":ech\", "tx") + call assert_equal(1, g:cmdchg_count) " (once for 'h' and) once for 'o' + + set wildmode=noselect,full + let g:cmdchg_count = 0 + let g:cmdprefix = 'ech' + call feedkeys(":ech\", "tx") + call assert_equal(1, g:cmdchg_count) " once for 'h', not again for + + command! -nargs=+ -complete=custom,TestComplete Test echo + + func TestComplete(arglead, cmdline, cursorpos) + return "AbC" + endfunc + + set wildoptions=fuzzy wildmode=full + let g:cmdchg_count = 0 + let g:cmdprefix = 'Test \(AbC\|abc\)' + call feedkeys(":Test abc\", "tx") + call assert_equal(2, g:cmdchg_count) " once for 'c', again for 'AbC' + + bw! + set wildmode& wildmenu& wildoptions& + augroup test_CmdlineAugrp | autocmd! | augroup END + unlet g:cmdchg_count + unlet g:cmdprefix + delfunc TestComplete + delcommand Test +endfunc + " vim: shiftwidth=2 sts=2 expandtab