Merge pull request #17979 from zeertzjq/autocmd-show-fix

fix(autocmd): restore autocmd showing behavior
This commit is contained in:
bfredl 2022-04-07 11:42:16 +02:00 committed by GitHub
commit dc9e436986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 222 additions and 33 deletions

View File

@ -135,7 +135,7 @@ static inline const char *get_deleted_augroup(void) FUNC_ATTR_ALWAYS_INLINE
} }
// Show the autocommands for one AutoPat. // 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 // Check for "got_int" (here and at various places below), which is set
// when "q" has been hit for the "--more--" prompt // when "q" has been hit for the "--more--" prompt
@ -148,6 +148,31 @@ static void aupat_show(AutoPat *ap)
return; 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_col = 4;
msg_outtrans(ap->pat); 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) { 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 // Return early if there are no autocmds for this event
if (au_event_is_empty(event)) { if (au_event_is_empty(event)) {
return; return;
} }
// always need to show group information before the first pattern for the event
int previous_group = AUGROUP_ERROR; 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); if (*pat == NUL) {
FOR_ALL_AUPATS_IN_EVENT(event, ap) {
msg_putchar('\n'); if (group == AUGROUP_ALL || ap->group == group) {
// When switching groups, we need to show the new group information. aupat_show(ap, event, previous_group);
if (ap->group != previous_group) { previous_group = ap->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(" ");
} }
}
return;
}
// show the event name char_u buflocal_pat[BUFLOCAL_PAT_LEN]; // for "<buffer=X>"
msg_puts_attr(event_nr2name(event), HL_ATTR(HLF_T)); // Loop through all the specified patterns.
msg_putchar('\n'); 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);
} }
if (got_int) { assert(*pat != NUL);
return;
// 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;
}
}
} }
aupat_show(ap); pat = aucmd_next_pattern(pat, (size_t)patlen);
patlen = (int)aucmd_pattern_length(pat);
previous_group = ap->group;
} }
} }
@ -805,11 +846,11 @@ void do_autocmd(char_u *arg_in, int forceit)
msg_puts_title(_("\n--- Autocommands ---")); msg_puts_title(_("\n--- Autocommands ---"));
if (*arg == '*' || *arg == '|' || *arg == NUL) { if (*arg == '*' || *arg == '|' || *arg == NUL) {
au_show_for_all_events(group); au_show_for_all_events(group, pat);
} else { } else {
event_T event = event_name2nr(arg, &arg); event_T event = event_name2nr(arg, &arg);
assert(event < NUM_EVENTS); assert(event < NUM_EVENTS);
au_show_for_event(group, event); au_show_for_event(group, event, pat);
} }
} else { } else {
if (*arg == '*' || *arg == NUL || *arg == '|') { 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); assert(*pat != NUL);
// Find AutoPat entries with this pattern. // 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]; prev_ap = &first_autopat[(int)event];
while ((ap = *prev_ap) != NULL) { while ((ap = *prev_ap) != NULL) {
if (ap->pat != 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); patlen = (int)STRLEN(buflocal_pat);
} }
// always goes at or after the last one, so start at the end.
if (last_autopat[(int)event] != NULL) { if (last_autopat[(int)event] != NULL) {
prev_ap = &last_autopat[(int)event]; prev_ap = &last_autopat[(int)event];
} else { } else {

View File

@ -1,13 +1,19 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear local clear = helpers.clear
local command = helpers.command local command = helpers.command
local dedent = helpers.dedent local dedent = helpers.dedent
local eq = helpers.eq local eq = helpers.eq
local funcs = helpers.funcs local funcs = helpers.funcs
local eval = helpers.eval
local exec = helpers.exec
local feed = helpers.feed
describe(":autocmd", function() describe(":autocmd", function()
before_each(clear) before_each(function()
clear({'-u', 'NONE'})
end)
it("should not segfault when you just do autocmd", function() it("should not segfault when you just do autocmd", function()
command ":autocmd" command ":autocmd"
@ -30,6 +36,148 @@ describe(":autocmd", function()
* :echo "Line 1" * :echo "Line 1"
:echo "Line 2"]]), :echo "Line 2"]]),
funcs.execute('autocmd BufEnter')) 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)
end) end)