autocmd: do not show empty section after ++once handlers expire

Problem: If autocmd pattern only contained `++once` handlers, and
         all of them completed, then there would be an empty group
         displayed by `:autocmd Foo`.
Solution: Delete the pattern if all of its commands were deleted.
This commit is contained in:
Justin M. Keyes 2019-03-13 22:31:07 +01:00
parent 3259e45f92
commit b1f25ea187
2 changed files with 42 additions and 14 deletions

View File

@ -5591,39 +5591,48 @@ static void au_del_cmd(AutoCmd *ac)
au_need_clean = true;
}
/*
* Cleanup autocommands and patterns that have been deleted.
* This is only done when not executing autocommands.
*/
/// Cleanup autocommands and patterns that have been deleted.
/// This is only done when not executing autocommands.
static void au_cleanup(void)
{
AutoPat *ap, **prev_ap;
AutoCmd *ac, **prev_ac;
event_T event;
if (autocmd_busy || !au_need_clean)
if (autocmd_busy || !au_need_clean) {
return;
}
/* loop over all events */
// Loop over all events.
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1)) {
/* loop over all autocommand patterns */
// Loop over all autocommand patterns.
prev_ap = &(first_autopat[(int)event]);
for (ap = *prev_ap; ap != NULL; ap = *prev_ap) {
/* loop over all commands for this pattern */
// Loop over all commands for this pattern.
prev_ac = &(ap->cmds);
bool has_cmd = false;
for (ac = *prev_ac; ac != NULL; ac = *prev_ac) {
/* remove the command if the pattern is to be deleted or when
* the command has been marked for deletion */
// Remove the command if the pattern is to be deleted or when
// the command has been marked for deletion.
if (ap->pat == NULL || ac->cmd == NULL) {
*prev_ac = ac->next;
xfree(ac->cmd);
xfree(ac);
} else
} else {
has_cmd = true;
prev_ac = &(ac->next);
}
}
/* remove the pattern if it has been marked for deletion */
if (ap->pat != NULL && !has_cmd) {
// Pattern was not marked for deletion, but all of its commands were.
// So mark the pattern for deletion.
au_remove_pat(ap);
}
// Remove the pattern if it has been marked for deletion.
if (ap->pat == NULL) {
if (ap->next == NULL) {
if (prev_ap == &(first_autopat[(int)event])) {
@ -5637,12 +5646,13 @@ static void au_cleanup(void)
*prev_ap = ap->next;
vim_regfree(ap->reg_prog);
xfree(ap);
} else
} else {
prev_ap = &(ap->next);
}
}
}
au_need_clean = FALSE;
au_need_clean = false;
}
/*

View File

@ -125,5 +125,23 @@ describe('autocmd', function()
command("put ='foo bar baz'")
feed('0llhlh')
eq(expected, eval('g:foo'))
--
-- :autocmd should not show empty section after ++once handlers expire.
--
expected = {
'Once1',
'Once2',
}
command('let g:foo = []')
command('autocmd! TabNew') -- Clear all TabNew handlers.
command('autocmd TabNew * ++once :call add(g:foo, "Once1")')
command('autocmd TabNew * ++once :call add(g:foo, "Once2")')
command('tabnew')
eq(expected, eval('g:foo'))
eq(dedent([[
--- Autocommands ---]]),
funcs.execute('autocmd Tabnew'))
end)
end)