aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/autocmd.txt16
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt2
-rw-r--r--runtime/doc/usr_40.txt8
-rw-r--r--runtime/doc/vim_diff.txt2
-rw-r--r--runtime/doc/windows.txt8
-rw-r--r--src/nvim/fileio.c52
-rw-r--r--src/nvim/tui/input.c4
-rw-r--r--test/functional/autocmd/autocmd_spec.lua38
8 files changed, 79 insertions, 51 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index b0b36271e9..4372342c02 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -40,7 +40,7 @@ effects. Be careful not to destroy your text.
2. Defining autocommands *autocmd-define*
*:au* *:autocmd*
-:au[tocmd] [group] {event} {pat} [-once] [-nested] {cmd}
+:au[tocmd] [group] {event} {pat} [++once] [++nested] {cmd}
Add {cmd} to the list of commands that Vim will
execute automatically on {event} for a file matching
{pat} |autocmd-patterns|.
@@ -48,9 +48,9 @@ effects. Be careful not to destroy your text.
:autocmd and won't start a comment.
Nvim always adds {cmd} after existing autocommands so
they execute in the order in which they were defined.
- See |autocmd-nested| for [-nested].
+ See |autocmd-nested| for [++nested].
*autocmd-once*
- If [-once] is supplied the command is executed once,
+ If [++once] is supplied the command is executed once,
then removed ("one shot").
The special pattern <buffer> or <buffer=N> defines a buffer-local autocommand.
@@ -119,11 +119,11 @@ prompt. When one command outputs two messages this can happen anyway.
==============================================================================
3. Removing autocommands *autocmd-remove*
-:au[tocmd]! [group] {event} {pat} [-once] [-nested] {cmd}
+:au[tocmd]! [group] {event} {pat} [++once] [++nested] {cmd}
Remove all autocommands associated with {event} and
{pat}, and add the command {cmd}.
- See |autocmd-once| for [-once].
- See |autocmd-nested| for [-nested].
+ See |autocmd-once| for [++once].
+ See |autocmd-nested| for [++nested].
:au[tocmd]! [group] {event} {pat}
Remove all autocommands associated with {event} and
@@ -1446,9 +1446,9 @@ instead of ":q!".
*autocmd-nested* *E218*
By default, autocommands do not nest. If you use ":e" or ":w" in an
autocommand, Vim does not execute the BufRead and BufWrite autocommands for
-those commands. If you do want this, use the "-nested" flag for those
+those commands. If you do want this, use the "++nested" flag for those
commands in which you want nesting. For example: >
- :autocmd FileChangedShell *.c -nested e!
+ :autocmd FileChangedShell *.c ++nested e!
The nesting is limited to 10 levels to get out of recursive loops.
It's possible to use the ":au" command in an autocommand. This can be a
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index 2eaaf82934..af94c60629 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -35,7 +35,7 @@ There are 3 ways to create a terminal buffer:
<
Note: The "term://" pattern is handled by a BufReadCmd handler, so the
|autocmd-nested| modifier is required to use it in an autocmd. >
- autocmd VimEnter * -nested split term://sh
+ autocmd VimEnter * ++nested split term://sh
< This is only mentioned for reference; use |:terminal| instead.
When the terminal starts, the buffer contents are updated and the buffer is
diff --git a/runtime/doc/usr_40.txt b/runtime/doc/usr_40.txt
index abb4a1dbfa..9a1fe50f31 100644
--- a/runtime/doc/usr_40.txt
+++ b/runtime/doc/usr_40.txt
@@ -453,14 +453,14 @@ matching BufWritePre autocommands and executes them, and then it
performs the ":write".
The general form of the :autocmd command is as follows: >
- :autocmd [group] {events} {file_pattern} [-nested] {command}
+ :autocmd [group] {events} {file_pattern} [++nested] {command}
The [group] name is optional. It is used in managing and calling the commands
(more on this later). The {events} parameter is a list of events (comma
separated) that trigger the command.
{file_pattern} is a filename, usually with wildcards. For example, using
"*.txt" makes the autocommand be used for all files whose name end in ".txt".
-The optional [-nested] flag allows for nesting of autocommands (see below),
+The optional [++nested] flag allows for nesting of autocommands (see below),
and finally, {command} is the command to be executed.
@@ -576,9 +576,9 @@ NESTING
Generally, commands executed as the result of an autocommand event will not
trigger any new events. If you read a file in response to a FileChangedShell
event, it will not trigger the autocommands that would set the syntax, for
-example. To make the events triggered, add the "-nested" flag: >
+example. To make the events triggered, add the "++nested" flag: >
- :autocmd FileChangedShell * -nested edit
+ :autocmd FileChangedShell * ++nested edit
EXECUTING AUTOCOMMANDS
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 3b5a5cded2..55c3be9a57 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -133,7 +133,7 @@ Command-line highlighting:
removed in the future).
Commands:
- |:autocmd| accepts the `once` flag
+ |:autocmd| accepts the `++once` flag
|:checkhealth|
|:cquit| can use [count] to set the exit code
|:drop| is always available
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 65ce72d62c..63ffd91bfc 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -880,15 +880,15 @@ CTRL-W g } *CTRL-W_g}*
cursor. This is less clever than using |:ptag|, but you don't
need a tags file and it will also find matches in system
include files. Example: >
- :au! CursorHold *.[ch] -nested exe "silent! psearch " . expand("<cword>")
+ :au! CursorHold *.[ch] ++nested exe "silent! psearch " . expand("<cword>")
< Warning: This can be slow.
Example *CursorHold-example* >
- :au! CursorHold *.[ch] -nested exe "silent! ptag " . expand("<cword>")
+ :au! CursorHold *.[ch] ++nested exe "silent! ptag " . expand("<cword>")
This will cause a ":ptag" to be executed for the keyword under the cursor,
-when the cursor hasn't moved for the time set with 'updatetime'. "-nested"
+when the cursor hasn't moved for the time set with 'updatetime'. "++nested"
makes other autocommands be executed, so that syntax highlighting works in the
preview window. The "silent!" avoids an error message when the tag could not
be found. Also see |CursorHold|. To disable this again: >
@@ -898,7 +898,7 @@ be found. Also see |CursorHold|. To disable this again: >
A nice addition is to highlight the found tag, avoid the ":ptag" when there
is no word under the cursor, and a few other things: >
- :au! CursorHold *.[ch] -nested call PreviewWord()
+ :au! CursorHold *.[ch] ++nested call PreviewWord()
:func PreviewWord()
: if &previewwindow " don't do this in the preview window
: return
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 51180c4939..7be4107c94 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -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;
}
/*
@@ -6050,18 +6060,18 @@ void do_autocmd(char_u *arg_in, int forceit)
cmd = skipwhite(cmd);
for (size_t i = 0; i < 2; i++) {
if (*cmd != NUL) {
- // Check for "-once" flag.
- if (!once && STRNCMP(cmd, "-once", 5) == 0 && ascii_iswhite(cmd[5])) {
+ // Check for "++once" flag.
+ if (!once && STRNCMP(cmd, "++once", 6) == 0 && ascii_iswhite(cmd[6])) {
once = true;
- cmd = skipwhite(cmd + 5);
+ cmd = skipwhite(cmd + 6);
}
- // Check for "-nested" flag.
+ // Check for "++nested" flag.
if (!nested
- && ((STRNCMP(cmd, "-nested", 7) == 0 && ascii_iswhite(cmd[7]))
- // Deprecated form (without "-").
+ && ((STRNCMP(cmd, "++nested", 8) == 0 && ascii_iswhite(cmd[8]))
+ // Deprecated form (without "++").
|| (STRNCMP(cmd, "nested", 6) == 0 && ascii_iswhite(cmd[6])))) {
nested = true;
- cmd = skipwhite(cmd + ('-' == cmd[0] ? 7 : 6));
+ cmd = skipwhite(cmd + ('+' == cmd[0] ? 8 : 6));
}
}
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 703feac305..0bdda17299 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -363,8 +363,8 @@ static void set_bg_deferred(void **argv)
if (starting) {
// Wait until after startup, so OptionSet is triggered.
do_cmdline_cmd((bgvalue[0] == 'l')
- ? "autocmd VimEnter * once nested set background=light"
- : "autocmd VimEnter * once nested set background=dark");
+ ? "autocmd VimEnter * ++once ++nested set bg=light"
+ : "autocmd VimEnter * ++once ++nested set bg=dark");
} else {
set_option_value("bg", 0L, bgvalue, 0);
reset_option_was_set("bg");
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 4efabd37fb..814624d8e2 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -59,9 +59,9 @@ describe('autocmd', function()
end)
end)
- it('-once', function() -- :help autocmd-once
+ it('++once', function() -- :help autocmd-once
--
- -- ":autocmd ... -once" executes its handler once, then removes the handler.
+ -- ":autocmd ... ++once" executes its handler once, then removes the handler.
--
local expected = {
'Many1',
@@ -76,10 +76,10 @@ describe('autocmd', function()
}
command('let g:foo = []')
command('autocmd TabNew * :call add(g:foo, "Many1")')
- command('autocmd TabNew * -once :call add(g:foo, "Once1")')
- command('autocmd TabNew * -once :call add(g:foo, "Once2")')
+ command('autocmd TabNew * ++once :call add(g:foo, "Once1")')
+ command('autocmd TabNew * ++once :call add(g:foo, "Once2")')
command('autocmd TabNew * :call add(g:foo, "Many2")')
- command('autocmd TabNew * -once :call add(g:foo, "Once3")')
+ command('autocmd TabNew * ++once :call add(g:foo, "Once3")')
eq(dedent([[
--- Autocommands ---
@@ -103,27 +103,45 @@ describe('autocmd', function()
funcs.execute('autocmd Tabnew'))
--
- -- ":autocmd ... -once" handlers can be deleted.
+ -- ":autocmd ... ++once" handlers can be deleted.
--
expected = {}
command('let g:foo = []')
- command('autocmd TabNew * -once :call add(g:foo, "Once1")')
+ command('autocmd TabNew * ++once :call add(g:foo, "Once1")')
command('autocmd! TabNew')
command('tabnew')
eq(expected, eval('g:foo'))
--
- -- ":autocmd ... <buffer> -once -nested"
+ -- ":autocmd ... <buffer> ++once ++nested"
--
expected = {
'OptionSet-Once',
'CursorMoved-Once',
}
command('let g:foo = []')
- command('autocmd OptionSet binary -nested -once :call add(g:foo, "OptionSet-Once")')
- command('autocmd CursorMoved <buffer> -once -nested setlocal binary|:call add(g:foo, "CursorMoved-Once")')
+ command('autocmd OptionSet binary ++nested ++once :call add(g:foo, "OptionSet-Once")')
+ command('autocmd CursorMoved <buffer> ++once ++nested setlocal binary|:call add(g:foo, "CursorMoved-Once")')
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)