0
0
mirror of https://github.com/vim/vim.git synced 2025-10-28 09:27:14 -04:00

patch 8.1.1113: making an autocommand trigger once is not so easy

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)
This commit is contained in:
Bram Moolenaar
2019-04-04 15:04:56 +02:00
parent 87f59b09ea
commit eb93f3f0e2
5 changed files with 146 additions and 18 deletions

View File

@@ -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;