diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0d91514fca..c7319c96f9 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -142,6 +142,8 @@ typedef struct { expand_T xpc; OptInt *b_im_ptr; buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid + int cmdline_type; + bool event_cmdlineleavepre_triggered; } CommandLineState; typedef struct { @@ -795,9 +797,10 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear setmouse(); setcursor(); + s->cmdline_type = firstc > 0 ? firstc : '-'; Error err = ERROR_INIT; char firstcbuf[2]; - firstcbuf[0] = (char)(firstc > 0 ? firstc : '-'); + firstcbuf[0] = (char)s->cmdline_type; firstcbuf[1] = 0; if (has_event(EVENT_CMDLINEENTER)) { @@ -947,6 +950,11 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear need_wait_return = false; } + // Trigger CmdlineLeavePre autocommands if not already triggered. + if (!s->event_cmdlineleavepre_triggered) { + trigger_cmd_autocmd(s->cmdline_type, EVENT_CMDLINELEAVEPRE); + } + set_option_direct(kOptInccommand, CSTR_AS_OPTVAL(s->save_p_icm), 0, SID_NONE); State = s->save_State; if (cmdpreview != save_cmdpreview) { @@ -1304,9 +1312,10 @@ static int command_line_execute(VimState *state, int key) } // Trigger CmdlineLeavePre autocommand - if (s->c == '\n' || s->c == '\r' || s->c == K_KENTER - || s->c == ESC || s->c == Ctrl_C) { - trigger_cmd_autocmd(get_cmdline_type(), EVENT_CMDLINELEAVEPRE); + if ((KeyTyped && (s->c == '\n' || s->c == '\r' || s->c == K_KENTER || s->c == ESC)) + || s->c == Ctrl_C) { + trigger_cmd_autocmd(s->cmdline_type, EVENT_CMDLINELEAVEPRE); + s->event_cmdlineleavepre_triggered = true; } // The wildmenu is cleared if the pressed key is not used for @@ -2234,7 +2243,7 @@ end: static void may_trigger_cursormovedc(CommandLineState *s) { if (ccline.cmdpos != s->prev_cmdpos) { - trigger_cmd_autocmd(get_cmdline_type(), EVENT_CURSORMOVEDC); + trigger_cmd_autocmd(s->cmdline_type, EVENT_CURSORMOVEDC); s->prev_cmdpos = ccline.cmdpos; ccline.redraw_state = MAX(ccline.redraw_state, kCmdRedrawPos); } diff --git a/test/functional/legacy/autocmd_spec.lua b/test/functional/legacy/autocmd_spec.lua index 1071776b68..b4050c951e 100644 --- a/test/functional/legacy/autocmd_spec.lua +++ b/test/functional/legacy/autocmd_spec.lua @@ -91,3 +91,13 @@ it('WinScrolled and WinResized events can be ignored in a window', function() feed(':echo win_getid() g:afile g:resized g:scrolled') screen:expect({ any = '1000 1001 1 1.*' }) end) + +-- oldtest: Test_CmdlineLeavePre_cabbr() +it(':cabbr does not cause a spurious CmdlineLeavePre', function() + command('let g:a = 0') + command('cabbr v v') + command('command! -nargs=* Foo echo') + command('au! CmdlineLeavePre * let g:a += 1') + feed(':Foo v') + eq(1, api.nvim_get_var('a')) +end) diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 09c7adf6d3..887fb1dca6 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -1923,51 +1923,101 @@ endfunc func Test_Cmdline_Trigger() autocmd CmdlineLeavePre : let g:log = "CmdlineLeavePre" + autocmd CmdlineLeavePre : let g:log2 = "CmdlineLeave" new let g:log = '' + let g:log2 = '' nnoremap echo "hello" call feedkeys("\", 'x') call assert_equal('', g:log) + call assert_equal('', g:log2) nunmap + let g:log = '' + let g:log2 = '' nnoremap :echo "hello" call feedkeys("\", 'x') call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) nunmap + let g:log = '' + let g:log2 = '' + call feedkeys(":\", "tx") + call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + + let g:log = '' + let g:log2 = '' split call assert_equal('', g:log) call feedkeys(":echo hello", "tx") call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + let g:log = '' + let g:log2 = '' close call assert_equal('', g:log) call feedkeys(":echo hello", "tx") call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + let g:log = '' + let g:log2 = '' tabnew call assert_equal('', g:log) call feedkeys(":echo hello", "tx") call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + let g:log = '' + let g:log2 = '' split call assert_equal('', g:log) call feedkeys(":echo hello", "tx") call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + let g:log = '' + let g:log2 = '' tabclose call assert_equal('', g:log) call feedkeys(":echo hello", "tx") call assert_equal('CmdlineLeavePre', g:log) + call assert_equal('CmdlineLeave', g:log2) + let g:count = 0 autocmd CmdlineLeavePre * let g:count += 1 call feedkeys(":let c = input('? ')\B\", "tx") call assert_equal(2, g:count) unlet! g:count unlet! g:log + unlet! g:log2 bw! endfunc +" Ensure :cabbr does not cause a spurious CmdlineLeavePre. +func Test_CmdlineLeavePre_cabbr() + CheckFeature terminal + let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': 3}) + call assert_equal('running', term_getstatus(buf)) + call term_sendkeys(buf, ":let g:a=0\") + call term_wait(buf, 50) + call term_sendkeys(buf, ":cabbr v v\") + call term_wait(buf, 50) + call term_sendkeys(buf, ":command! -nargs=* Foo echo\") + call term_wait(buf, 50) + call term_sendkeys(buf, ":au! CmdlineLeavePre * :let g:a+=1\") + call term_wait(buf, 50) + call term_sendkeys(buf, ":Foo v\") + call term_wait(buf, 50) + call term_sendkeys(buf, ":echo g:a\") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('^2.*$', term_getline(buf, 3))}) + bwipe! +endfunc + func Test_Cmdline() au! CmdlineChanged : let g:text = getcmdline() let g:text = 0