summaryrefslogtreecommitdiffstats
path: root/src/autocmd.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-04-04 15:04:56 +0200
committerBram Moolenaar <Bram@vim.org>2019-04-04 15:04:56 +0200
commiteb93f3f0e2b2ae65c5c3f55be3e62d64e3066f35 (patch)
treee69acd4b5050a07bfc91cb180831c5cd1bb41b1f /src/autocmd.c
parent87f59b09ea4b9af2712598374a6044f5fa1b54a4 (diff)
patch 8.1.1113: making an autocommand trigger once is not so easyv8.1.1113
Problem: Making an autocommand trigger once is not so easy. Solution: Add the ++once argument. Also add ++nested as an alias for "nested". (Justin M. Keyes, closes #4100)
Diffstat (limited to 'src/autocmd.c')
-rw-r--r--src/autocmd.c70
1 files changed, 59 insertions, 11 deletions
diff --git a/src/autocmd.c b/src/autocmd.c
index d81615ba8f..9a758c8a45 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -52,6 +52,7 @@ typedef struct AutoCmd
{
char_u *cmd; // The command to be executed (NULL
// when command has been removed).
+ char once; // "One shot": removed after execution
char nested; // If autocommands nest here.
char last; // last command in list
#ifdef FEAT_EVAL
@@ -256,7 +257,7 @@ static int au_need_clean = FALSE; /* need to delete marked patterns */
static char_u *event_nr2name(event_T event);
static int au_get_grouparg(char_u **argp);
-static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group);
+static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group);
static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
static int au_find_group(char_u *name);
@@ -361,6 +362,13 @@ au_remove_cmds(AutoPat *ap)
au_need_clean = TRUE;
}
+// Delete one command from an autocmd pattern.
+static void au_del_cmd(AutoCmd *ac)
+{
+ VIM_CLEAR(ac->cmd);
+ au_need_clean = TRUE;
+}
+
/*
* Cleanup autocommands and patterns that have been deleted.
* This is only done when not executing autocommands.
@@ -385,6 +393,8 @@ au_cleanup(void)
{
// loop over all commands for this pattern
prev_ac = &(ap->cmds);
+ int has_cmd = FALSE;
+
for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
{
// remove the command if the pattern is to be deleted or when
@@ -395,8 +405,16 @@ au_cleanup(void)
vim_free(ac->cmd);
vim_free(ac);
}
- else
+ else {
+ has_cmd = TRUE;
prev_ac = &(ac->next);
+ }
+ }
+
+ 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
@@ -815,7 +833,9 @@ do_autocmd(char_u *arg_in, int forceit)
event_T event;
int need_free = FALSE;
int nested = FALSE;
+ int once = FALSE;
int group;
+ int i;
if (*arg == '|')
{
@@ -874,15 +894,38 @@ do_autocmd(char_u *arg_in, int forceit)
pat = envpat;
}
- /*
- * Check for "nested" flag.
- */
cmd = skipwhite(cmd);
- if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0
- && VIM_ISWHITE(cmd[6]))
+ for (i = 0; i < 2; i++)
{
- nested = TRUE;
- cmd = skipwhite(cmd + 6);
+ if (*cmd != NUL)
+ {
+ // Check for "++once" flag.
+ if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
+ {
+ if (once)
+ semsg(_(e_duparg2), "++once");
+ once = TRUE;
+ cmd = skipwhite(cmd + 6);
+ }
+
+ // Check for "++nested" flag.
+ if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
+ {
+ if (nested)
+ semsg(_(e_duparg2), "++nested");
+ nested = TRUE;
+ cmd = skipwhite(cmd + 8);
+ }
+
+ // Check for the old "nested" flag.
+ if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
+ {
+ if (nested)
+ semsg(_(e_duparg2), "nested");
+ nested = TRUE;
+ cmd = skipwhite(cmd + 6);
+ }
+ }
}
/*
@@ -915,14 +958,14 @@ do_autocmd(char_u *arg_in, int forceit)
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1))
if (do_autocmd_event(event, pat,
- nested, cmd, forceit, group) == FAIL)
+ once, nested, cmd, forceit, group) == FAIL)
break;
}
else
{
while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
if (do_autocmd_event(event_name2nr(arg, &arg), pat,
- nested, cmd, forceit, group) == FAIL)
+ once, nested, cmd, forceit, group) == FAIL)
break;
}
@@ -973,6 +1016,7 @@ au_get_grouparg(char_u **argp)
do_autocmd_event(
event_T event,
char_u *pat,
+ int once,
int nested,
char_u *cmd,
int forceit,
@@ -1212,6 +1256,7 @@ do_autocmd_event(
}
ac->next = NULL;
*prev_ac = ac;
+ ac->once = once;
ac->nested = nested;
}
}
@@ -2319,6 +2364,9 @@ getnextac(int c UNUSED, void *cookie, int indent UNUSED)
verbose_leave_scroll();
}
retval = vim_strsave(ac->cmd);
+ // Remove one-shot ("once") autocmd in anticipation of its execution.
+ if (ac->once)
+ au_del_cmd(ac);
autocmd_nested = ac->nested;
#ifdef FEAT_EVAL
current_sctx = ac->script_ctx;