aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-04-03 10:55:41 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-04-06 05:44:30 +0800
commit74a27748e674de4b24af35a6cc3aec2abf8222b4 (patch)
treec529bfbc427238e87d3a0859617135b0344ea6b5
parent128bedc0d2435bbc754cdb954447fc1cbfd4ac13 (diff)
downloadrneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.tar.gz
rneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.tar.bz2
rneovim-74a27748e674de4b24af35a6cc3aec2abf8222b4.zip
fix(autocmd): restore autocmd showing behavior
-rw-r--r--src/nvim/autocmd.c105
-rw-r--r--test/functional/autocmd/show_spec.lua150
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)