Mercurial > vim
diff src/autocmd.c @ 16217:81e6940504e8 v8.1.1113
patch 8.1.1113: making an autocommand trigger once is not so easy
commit https://github.com/vim/vim/commit/eb93f3f0e2b2ae65c5c3f55be3e62d64e3066f35
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Apr 4 15:04:56 2019 +0200
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)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 04 Apr 2019 15:15:05 +0200 |
parents | cd5c83115ec6 |
children | 331dc836f866 |
line wrap: on
line diff
--- 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; /* n 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, in 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;