diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-04-03 10:55:41 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-04-06 05:44:30 +0800 |
commit | 74a27748e674de4b24af35a6cc3aec2abf8222b4 (patch) | |
tree | c529bfbc427238e87d3a0859617135b0344ea6b5 | |
parent | 128bedc0d2435bbc754cdb954447fc1cbfd4ac13 (diff) | |
download | rneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.tar.gz rneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.tar.bz2 rneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.zip |
fix(autocmd): restore autocmd showing behavior
-rw-r--r-- | src/nvim/autocmd.c | 105 | ||||
-rw-r--r-- | test/functional/autocmd/show_spec.lua | 150 |
2 files changed, 222 insertions, 33 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index bcac7fbc4a..5fc36a8412 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -135,7 +135,7 @@ static inline const char *get_deleted_augroup(void) FUNC_ATTR_ALWAYS_INLINE } // Show the autocommands for one AutoPat. -static void aupat_show(AutoPat *ap) +static void aupat_show(AutoPat *ap, event_T event, int previous_group) { // Check for "got_int" (here and at various places below), which is set // when "q" has been hit for the "--more--" prompt @@ -148,6 +148,31 @@ static void aupat_show(AutoPat *ap) return; } + char *name = augroup_name(ap->group); + + msg_putchar('\n'); + if (got_int) { + return; + } + // When switching groups, we need to show the new group information. + if (ap->group != previous_group) { + // show the group name, if it's not the default group + if (ap->group != AUGROUP_DEFAULT) { + if (name == NULL) { + msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E)); + } else { + msg_puts_attr(name, HL_ATTR(HLF_T)); + } + msg_puts(" "); + } + // show the event name + msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T)); + msg_putchar('\n'); + if (got_int) { + return; + } + } + msg_col = 4; msg_outtrans(ap->pat); @@ -180,53 +205,69 @@ static void aupat_show(AutoPat *ap) } } -static void au_show_for_all_events(int group) +static void au_show_for_all_events(int group, char_u *pat) { FOR_ALL_AUEVENTS(event) { - au_show_for_event(group, event); + au_show_for_event(group, event, pat); } } -static void au_show_for_event(int group, event_T event) +static void au_show_for_event(int group, event_T event, char_u *pat) { // Return early if there are no autocmds for this event if (au_event_is_empty(event)) { return; } + // always need to show group information before the first pattern for the event int previous_group = AUGROUP_ERROR; - FOR_ALL_AUPATS_IN_EVENT(event, ap) { - if (group != AUGROUP_ALL && group != ap->group) { - continue; - } - char *name = augroup_name(ap->group); - - msg_putchar('\n'); - // When switching groups, we need to show the new group information. - if (ap->group != previous_group) { - // show the group name, if it's not the default group - if (ap->group != AUGROUP_DEFAULT) { - if (name == NULL) { - msg_puts_attr(get_deleted_augroup(), HL_ATTR(HLF_E)); - } else { - msg_puts_attr(name, HL_ATTR(HLF_T)); - } - msg_puts(" "); + if (*pat == NUL) { + FOR_ALL_AUPATS_IN_EVENT(event, ap) { + if (group == AUGROUP_ALL || ap->group == group) { + aupat_show(ap, event, previous_group); + previous_group = ap->group; } - - // show the event name - msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T)); - msg_putchar('\n'); } + return; + } - if (got_int) { - return; + char_u buflocal_pat[BUFLOCAL_PAT_LEN]; // for "<buffer=X>" + // Loop through all the specified patterns. + int patlen = (int)aucmd_pattern_length(pat); + while (patlen) { + // detect special <buffer[=X]> buffer-local patterns + if (aupat_is_buflocal(pat, patlen)) { + // normalize pat into standard "<buffer>#N" form + aupat_normalize_buflocal_pat(buflocal_pat, pat, patlen, aupat_get_buflocal_nr(pat, patlen)); + pat = buflocal_pat; + patlen = (int)STRLEN(buflocal_pat); } - aupat_show(ap); + assert(*pat != NUL); - previous_group = ap->group; + // Find AutoPat entries with this pattern. + // always goes at or after the last one, so start at the end. + FOR_ALL_AUPATS_IN_EVENT(event, ap) { + if (ap->pat != NULL) { + // Accept a pattern when: + // - a group was specified and it's that group + // - the length of the pattern matches + // - the pattern matches. + // For <buffer[=X]>, this condition works because we normalize + // all buffer-local patterns. + if ((group == AUGROUP_ALL || ap->group == group) + && ap->patlen == patlen + && STRNCMP(pat, ap->pat, patlen) == 0) { + // Show autocmd's for this autopat, or buflocals <buffer=X> + aupat_show(ap, event, previous_group); + previous_group = ap->group; + } + } + } + + pat = aucmd_next_pattern(pat, (size_t)patlen); + patlen = (int)aucmd_pattern_length(pat); } } @@ -805,11 +846,11 @@ void do_autocmd(char_u *arg_in, int forceit) msg_puts_title(_("\n--- Autocommands ---")); if (*arg == '*' || *arg == '|' || *arg == NUL) { - au_show_for_all_events(group); + au_show_for_all_events(group, pat); } else { event_T event = event_name2nr(arg, &arg); assert(event < NUM_EVENTS); - au_show_for_event(group, event); + au_show_for_event(group, event, pat); } } else { if (*arg == '*' || *arg == NUL || *arg == '|') { @@ -900,7 +941,6 @@ int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, char_u * assert(*pat != NUL); // Find AutoPat entries with this pattern. - // always goes at or after the last one, so start at the end. prev_ap = &first_autopat[(int)event]; while ((ap = *prev_ap) != NULL) { if (ap->pat != NULL) { @@ -980,6 +1020,7 @@ int autocmd_register(int64_t id, event_T event, char_u *pat, int patlen, int gro patlen = (int)STRLEN(buflocal_pat); } + // always goes at or after the last one, so start at the end. if (last_autopat[(int)event] != NULL) { prev_ap = &last_autopat[(int)event]; } else { diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua index 59757a7d61..505bed834b 100644 --- a/test/functional/autocmd/show_spec.lua +++ b/test/functional/autocmd/show_spec.lua @@ -1,13 +1,19 @@ local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local dedent = helpers.dedent local eq = helpers.eq local funcs = helpers.funcs +local eval = helpers.eval +local exec = helpers.exec +local feed = helpers.feed describe(":autocmd", function() - before_each(clear) + before_each(function() + clear({'-u', 'NONE'}) + end) it("should not segfault when you just do autocmd", function() command ":autocmd" @@ -30,6 +36,148 @@ describe(":autocmd", function() * :echo "Line 1" :echo "Line 2"]]), funcs.execute('autocmd BufEnter')) + end) + + it('should not show group information if interrupted', function() + local screen = Screen.new(50, 6) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText + [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + [3] = {bold = true, foreground = Screen.colors.Magenta}, -- Title + }) + screen:attach() + exec([[ + set more + autocmd! BufEnter + augroup test_1 + autocmd BufEnter A echo 'A' + autocmd BufEnter B echo 'B' + autocmd BufEnter C echo 'C' + autocmd BufEnter D echo 'D' + autocmd BufEnter E echo 'E' + autocmd BufEnter F echo 'F' + augroup END + autocmd! BufLeave + augroup test_1 + autocmd BufLeave A echo 'A' + autocmd BufLeave B echo 'B' + autocmd BufLeave C echo 'C' + autocmd BufLeave D echo 'D' + autocmd BufLeave E echo 'E' + autocmd BufLeave F echo 'F' + augroup END + ]]) + feed(':autocmd<CR>') + screen:expect([[ + :autocmd | + {3:--- Autocommands ---} | + {3:test_1} {3:BufEnter} | + A echo 'A' | + B echo 'B' | + {2:-- More --}^ | + ]]) + feed('q') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) + + it('should not show group information for deleted pattern', function() + exec([[ + autocmd! BufEnter + augroup test_1 + autocmd BufEnter A echo 'A' + autocmd BufEnter B echo 'B' + autocmd BufEnter C echo 'C' + augroup END + augroup test_2 + autocmd BufEnter foo echo 'foo' + augroup END + augroup test_3 + autocmd BufEnter D echo 'D' + autocmd BufEnter E echo 'E' + autocmd BufEnter F echo 'F' + augroup END + + func Func() + autocmd! test_2 BufEnter + let g:output = execute('autocmd BufEnter') + endfunc + + autocmd User foo call Func() + doautocmd User foo + ]]) + eq(dedent([[ + + --- Autocommands --- + test_1 BufEnter + A echo 'A' + B echo 'B' + C echo 'C' + test_3 BufEnter + D echo 'D' + E echo 'E' + F echo 'F']]), eval('g:output')) + end) + + it('can filter by pattern #17973', function() + exec([[ + autocmd! BufEnter + autocmd! User + augroup test_1 + autocmd BufEnter A echo "A1" + autocmd BufEnter B echo "B1" + autocmd User A echo "A1" + autocmd User B echo "B1" + augroup END + augroup test_2 + autocmd BufEnter A echo "A2" + autocmd BufEnter B echo "B2" + autocmd User A echo "A2" + autocmd User B echo "B2" + augroup END + augroup test_3 + autocmd BufEnter A echo "A3" + autocmd BufEnter B echo "B3" + autocmd User A echo "A3" + autocmd User B echo "B3" + augroup END + ]]) + eq(dedent([[ + + --- Autocommands --- + test_1 User + A echo "A1" + test_2 User + A echo "A2" + test_3 User + A echo "A3"]]), funcs.execute('autocmd User A')) + eq(dedent([[ + + --- Autocommands --- + test_1 BufEnter + B echo "B1" + test_2 BufEnter + B echo "B2" + test_3 BufEnter + B echo "B3" + test_1 User + B echo "B1" + test_2 User + B echo "B2" + test_3 User + B echo "B3"]]), funcs.execute('autocmd * B')) + eq(dedent([[ + --- Autocommands --- + test_3 BufEnter + B echo "B3" + test_3 User + B echo "B3"]]), funcs.execute('autocmd test_3 * B')) end) end) |