diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index b4b6cfc9c0..e6652bb83e 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2392,6 +2392,9 @@ A jump table for the options with a short description can be found at |Q_op|. Otherwise this is a comma-separated list of event names. Example: >vim set ei=WinEnter,WinLeave < + To ignore all but some events, a "-" prefix can be used: >vim + :set ei=all,-WinLeave +< *'eventignorewin'* *'eiw'* 'eventignorewin' 'eiw' string (default "") diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 189f21b4ad..aa6e7b94de 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -2047,6 +2047,12 @@ vim.go.efm = vim.go.errorformat --- set ei=WinEnter,WinLeave --- ``` --- +--- To ignore all but some events, a "-" prefix can be used: +--- +--- ```vim +--- :set ei=all,-WinLeave +--- ``` +--- --- --- @type string vim.o.eventignore = "" diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index d57c72313e..2460119123 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -661,15 +661,22 @@ const char *event_nr2name(event_T event) bool event_ignored(event_T event, char *ei) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { + bool ignored = false; while (*ei != NUL) { + bool unignore = *ei == '-'; + ei += unignore; if (STRNICMP(ei, "all", 3) == 0 && (ei[3] == NUL || ei[3] == ',')) { - return true; + ignored = ei == p_ei || event_names[event].event <= 0; + ei += 3 + (ei[3] == ','); } else if (event_name2nr(ei, &ei) == event) { - return true; + if (unignore) { + return false; + } + ignored = true; } } - return false; + return ignored; } /// Return OK when the contents of 'eventignore' or 'eventignorewin' is valid, @@ -680,11 +687,9 @@ int check_ei(char *ei) while (*ei) { if (STRNICMP(ei, "all", 3) == 0 && (ei[3] == NUL || ei[3] == ',')) { - ei += 3; - if (*ei == ',') { - ei++; - } + ei += 3 + (ei[3] == ','); } else { + ei += (*ei == '-'); event_T event = event_name2nr(ei, &ei); if (event == NUM_EVENTS || (win && event_names[event].event > 0)) { return FAIL; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index f9c6ec1171..549492555a 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2699,6 +2699,9 @@ local options = { Otherwise this is a comma-separated list of event names. Example: >vim set ei=WinEnter,WinLeave < + To ignore all but some events, a "-" prefix can be used: >vim + :set ei=all,-WinLeave + < ]=], expand_cb = 'expand_set_eventignore', full_name = 'eventignore', diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 5442fc40e0..5c4ae8a696 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1110,12 +1110,20 @@ static bool expand_eiw = false; static char *get_eventignore_name(expand_T *xp, int idx) { + bool subtract = *xp->xp_pattern == '-'; // 'eventignore(win)' allows special keyword "all" in addition to // all event names. - if (idx == 0) { + if (!subtract && idx == 0) { return "all"; } - return get_event_name_no_group(xp, idx - 1, expand_eiw); + + char *name = get_event_name_no_group(xp, idx - 1 + subtract, expand_eiw); + if (name == NULL) { + return NULL; + } + + snprintf(IObuff, IOSIZE, "%s%s", subtract ? "-" : "", name); + return IObuff; } int expand_set_eventignore(optexpand_T *args, int *numMatches, char ***matches) diff --git a/test/old/testdir/gen_opt_test.vim b/test/old/testdir/gen_opt_test.vim index 16e165cc13..776162fb32 100644 --- a/test/old/testdir/gen_opt_test.vim +++ b/test/old/testdir/gen_opt_test.vim @@ -226,9 +226,9 @@ let test_values = { \ ['xxx']], \ 'eadirection': [['both', 'ver', 'hor'], ['xxx', 'ver,hor']], "\ 'encoding': [['latin1'], ['xxx', '']], - \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'], + \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter', 'all,-WinLeave'], \ ['xxx']], - \ 'eventignorewin': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'], + \ 'eventignorewin': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter', 'all,-WinLeave'], \ ['xxx', 'WinNew']], \ 'fileencoding': [['', 'latin1', 'xxx'], []], \ 'fileformat': [['dos', 'unix', 'mac'], ['xxx']], diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 9a625195b0..b6f823895a 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -4556,4 +4556,20 @@ func Test_reuse_curbuf_switch() %bw! endfunc +func Test_eventignore_subtract() + set eventignore=all,-WinEnter + augroup testing + autocmd! + autocmd WinEnter * ++once let s:triggered = 1 + augroup END + + new + call assert_equal(1, s:triggered) + + set eventignore& + unlet! s:triggered + call CleanUpTestAuGroup() + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 34a0665ba4..3fb12b4016 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -597,6 +597,7 @@ func Test_set_completion_string_values() " Other string options that queries the system rather than fixed enum names call assert_equal(['all', 'BufAdd'], getcompletion('set eventignore=', 'cmdline')[0:1]) + call assert_equal(['-BufAdd', '-BufCreate'], getcompletion('set eventignore=all,-', 'cmdline')[0:1]) call assert_equal(['WinLeave', 'WinResized', 'WinScrolled'], getcompletion('set eiw=', 'cmdline')[-3:-1]) call assert_equal('latin1', getcompletion('set fileencodings=', 'cmdline')[1]) " call assert_equal('top', getcompletion('set printoptions=', 'cmdline')[0])