@@ -52,6 +52,7 @@ typedef struct AutoCmd
5252{
5353 char_u * cmd ; // The command to be executed (NULL
5454 // when command has been removed).
55+ char once ; // "One shot": removed after execution
5556 char nested ; // If autocommands nest here.
5657 char last ; // last command in list
5758#ifdef FEAT_EVAL
@@ -256,7 +257,7 @@ static int au_need_clean = FALSE; /* need to delete marked patterns */
256257
257258static char_u * event_nr2name (event_T event );
258259static int au_get_grouparg (char_u * * argp );
259- static int do_autocmd_event (event_T event , char_u * pat , int nested , char_u * cmd , int forceit , int group );
260+ static int do_autocmd_event (event_T event , char_u * pat , int once , int nested , char_u * cmd , int forceit , int group );
260261static int apply_autocmds_group (event_T event , char_u * fname , char_u * fname_io , int force , int group , buf_T * buf , exarg_T * eap );
261262static void auto_next_pat (AutoPatCmd * apc , int stop_at_last );
262263static int au_find_group (char_u * name );
@@ -361,6 +362,13 @@ au_remove_cmds(AutoPat *ap)
361362 au_need_clean = TRUE;
362363}
363364
365+ // Delete one command from an autocmd pattern.
366+ static void au_del_cmd (AutoCmd * ac )
367+ {
368+ VIM_CLEAR (ac -> cmd );
369+ au_need_clean = TRUE;
370+ }
371+
364372/*
365373 * Cleanup autocommands and patterns that have been deleted.
366374 * This is only done when not executing autocommands.
@@ -385,6 +393,8 @@ au_cleanup(void)
385393 {
386394 // loop over all commands for this pattern
387395 prev_ac = & (ap -> cmds );
396+ int has_cmd = FALSE;
397+
388398 for (ac = * prev_ac ; ac != NULL ; ac = * prev_ac )
389399 {
390400 // remove the command if the pattern is to be deleted or when
@@ -395,8 +405,16 @@ au_cleanup(void)
395405 vim_free (ac -> cmd );
396406 vim_free (ac );
397407 }
398- else
408+ else {
409+ has_cmd = TRUE;
399410 prev_ac = & (ac -> next );
411+ }
412+ }
413+
414+ if (ap -> pat != NULL && !has_cmd ) {
415+ // Pattern was not marked for deletion, but all of its
416+ // commands were. So mark the pattern for deletion.
417+ au_remove_pat (ap );
400418 }
401419
402420 // remove the pattern if it has been marked for deletion
@@ -815,7 +833,9 @@ do_autocmd(char_u *arg_in, int forceit)
815833 event_T event ;
816834 int need_free = FALSE;
817835 int nested = FALSE;
836+ int once = FALSE;
818837 int group ;
838+ int i ;
819839
820840 if (* arg == '|' )
821841 {
@@ -874,15 +894,38 @@ do_autocmd(char_u *arg_in, int forceit)
874894 pat = envpat ;
875895 }
876896
877- /*
878- * Check for "nested" flag.
879- */
880897 cmd = skipwhite (cmd );
881- if (* cmd != NUL && STRNCMP (cmd , "nested" , 6 ) == 0
882- && VIM_ISWHITE (cmd [6 ]))
898+ for (i = 0 ; i < 2 ; i ++ )
883899 {
884- nested = TRUE;
885- cmd = skipwhite (cmd + 6 );
900+ if (* cmd != NUL )
901+ {
902+ // Check for "++once" flag.
903+ if (STRNCMP (cmd , "++once" , 6 ) == 0 && VIM_ISWHITE (cmd [6 ]))
904+ {
905+ if (once )
906+ semsg (_ (e_duparg2 ), "++once" );
907+ once = TRUE;
908+ cmd = skipwhite (cmd + 6 );
909+ }
910+
911+ // Check for "++nested" flag.
912+ if ((STRNCMP (cmd , "++nested" , 8 ) == 0 && VIM_ISWHITE (cmd [8 ])))
913+ {
914+ if (nested )
915+ semsg (_ (e_duparg2 ), "++nested" );
916+ nested = TRUE;
917+ cmd = skipwhite (cmd + 8 );
918+ }
919+
920+ // Check for the old "nested" flag.
921+ if (STRNCMP (cmd , "nested" , 6 ) == 0 && VIM_ISWHITE (cmd [6 ]))
922+ {
923+ if (nested )
924+ semsg (_ (e_duparg2 ), "nested" );
925+ nested = TRUE;
926+ cmd = skipwhite (cmd + 6 );
927+ }
928+ }
886929 }
887930
888931 /*
@@ -915,14 +958,14 @@ do_autocmd(char_u *arg_in, int forceit)
915958 for (event = (event_T )0 ; (int )event < (int )NUM_EVENTS ;
916959 event = (event_T )((int )event + 1 ))
917960 if (do_autocmd_event (event , pat ,
918- nested , cmd , forceit , group ) == FAIL )
961+ once , nested , cmd , forceit , group ) == FAIL )
919962 break ;
920963 }
921964 else
922965 {
923966 while (* arg && * arg != '|' && !VIM_ISWHITE (* arg ))
924967 if (do_autocmd_event (event_name2nr (arg , & arg ), pat ,
925- nested , cmd , forceit , group ) == FAIL )
968+ once , nested , cmd , forceit , group ) == FAIL )
926969 break ;
927970 }
928971
@@ -973,6 +1016,7 @@ au_get_grouparg(char_u **argp)
9731016do_autocmd_event (
9741017 event_T event ,
9751018 char_u * pat ,
1019+ int once ,
9761020 int nested ,
9771021 char_u * cmd ,
9781022 int forceit ,
@@ -1212,6 +1256,7 @@ do_autocmd_event(
12121256 }
12131257 ac -> next = NULL ;
12141258 * prev_ac = ac ;
1259+ ac -> once = once ;
12151260 ac -> nested = nested ;
12161261 }
12171262 }
@@ -2319,6 +2364,9 @@ getnextac(int c UNUSED, void *cookie, int indent UNUSED)
23192364 verbose_leave_scroll ();
23202365 }
23212366 retval = vim_strsave (ac -> cmd );
2367+ // Remove one-shot ("once") autocmd in anticipation of its execution.
2368+ if (ac -> once )
2369+ au_del_cmd (ac );
23222370 autocmd_nested = ac -> nested ;
23232371#ifdef FEAT_EVAL
23242372 current_sctx = ac -> script_ctx ;
0 commit comments