Patch 8.2.5030
Problem:    autocmd_add() can only handle one event and pattern.
Solution:   Support a list of events and patterns. (Yegappan Lakshmanan,
            closes #10483)
Files:      runtime/doc/builtin.txt, src/autocmd.c, src/errors.h,
            src/testdir/test_autocmd.vim


*** ../vim-8.2.5029/runtime/doc/builtin.txt     2022-05-26 12:10:33.589893490 
+0100
--- runtime/doc/builtin.txt     2022-05-27 17:57:45.760052327 +0100
***************
*** 938,944 ****
                                item is ignored.
                    cmd         Ex command to execute for this autocmd event
                    event       autocmd event name. Refer to |autocmd-events|.
!                               TODO: currently only accepts one event.
                    group       autocmd group name. Refer to |autocmd-groups|.
                                If this group doesn't exist then it is
                                created.  If not specified or empty, then the
--- 938,945 ----
                                item is ignored.
                    cmd         Ex command to execute for this autocmd event
                    event       autocmd event name. Refer to |autocmd-events|.
!                               This can be either a String with a single
!                               event name or a List of event names.
                    group       autocmd group name. Refer to |autocmd-groups|.
                                If this group doesn't exist then it is
                                created.  If not specified or empty, then the
***************
*** 950,956 ****
                                |autocmd-once|.
                    pattern     autocmd pattern string. Refer to
                                |autocmd-patterns|.  If "bufnr" item is
!                               present, then this item is ignored.
                    replace     boolean flag, set to v:true to remove all the
                                commands associated with the specified autocmd
                                event and group and add the {cmd}.  This is
--- 951,959 ----
                                |autocmd-once|.
                    pattern     autocmd pattern string. Refer to
                                |autocmd-patterns|.  If "bufnr" item is
!                               present, then this item is ignored.  This can
!                               be a String with a single pattern or a List of
!                               patterns.
                    replace     boolean flag, set to v:true to remove all the
                                commands associated with the specified autocmd
                                event and group and add the {cmd}.  This is
*** ../vim-8.2.5029/src/autocmd.c       2022-05-24 11:40:07.514685757 +0100
--- src/autocmd.c       2022-05-27 17:57:45.764052324 +0100
***************
*** 2754,2769 ****
      static void
  autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
  {
!     list_T    *event_list;
      listitem_T        *li;
      dict_T    *event_dict;
      char_u    *event_name = NULL;
      event_T   event;
      char_u    *group_name = NULL;
      int               group;
      char_u    *pat = NULL;
      char_u    *cmd = NULL;
      char_u    *end;
      int               once;
      int               nested;
      int               replace;                // replace the cmd for a 
group/event
--- 2754,2775 ----
      static void
  autocmd_add_or_delete(typval_T *argvars, typval_T *rettv, int delete)
  {
!     list_T    *aucmd_list;
      listitem_T        *li;
      dict_T    *event_dict;
+     dictitem_T        *di;
      char_u    *event_name = NULL;
+     list_T    *event_list;
+     listitem_T        *eli;
      event_T   event;
      char_u    *group_name = NULL;
      int               group;
      char_u    *pat = NULL;
+     list_T    *pat_list;
+     listitem_T        *pli;
      char_u    *cmd = NULL;
      char_u    *end;
+     char_u    *p;
      int               once;
      int               nested;
      int               replace;                // replace the cmd for a 
group/event
***************
*** 2776,2791 ****
      if (check_for_list_arg(argvars, 0) == FAIL)
        return;
  
!     event_list = argvars[0].vval.v_list;
!     if (event_list == NULL)
        return;
  
!     FOR_ALL_LIST_ITEMS(event_list, li)
      {
-       VIM_CLEAR(event_name);
        VIM_CLEAR(group_name);
-       VIM_CLEAR(pat);
        VIM_CLEAR(cmd);
  
        if (li->li_tv.v_type != VAR_DICT)
            continue;
--- 2782,2799 ----
      if (check_for_list_arg(argvars, 0) == FAIL)
        return;
  
!     aucmd_list = argvars[0].vval.v_list;
!     if (aucmd_list == NULL)
        return;
  
!     FOR_ALL_LIST_ITEMS(aucmd_list, li)
      {
        VIM_CLEAR(group_name);
        VIM_CLEAR(cmd);
+       event_name = NULL;
+       event_list = NULL;
+       pat = NULL;
+       pat_list = NULL;
  
        if (li->li_tv.v_type != VAR_DICT)
            continue;
***************
*** 2794,2823 ****
        if (event_dict == NULL)
            continue;
  
!       event_name = dict_get_string(event_dict, (char_u *)"event", TRUE);
!       if (event_name == NULL)
        {
!           if (delete)
!               // if the event name is not specified, delete all the events
!               event = NUM_EVENTS;
!           else
!               continue;
!       }
!       else
!       {
!           if (delete && event_name[0] == '*' && event_name[1] == NUL)
!               // if the event name is '*', delete all the events
!               event = NUM_EVENTS;
!           else
            {
!               event = event_name2nr(event_name, &end);
!               if (event == NUM_EVENTS)
                {
!                   semsg(_(e_no_such_event_str), event_name);
!                   retval = VVAL_FALSE;
!                   break;
                }
            }
        }
  
        group_name = dict_get_string(event_dict, (char_u *)"group", TRUE);
--- 2802,2833 ----
        if (event_dict == NULL)
            continue;
  
!       di = dict_find(event_dict, (char_u *)"event", -1);
!       if (di != NULL)
        {
!           if (di->di_tv.v_type == VAR_STRING)
            {
!               event_name = di->di_tv.vval.v_string;
!               if (event_name == NULL)
                {
!                   emsg(_(e_string_required));
!                   continue;
!               }
!           }
!           else if (di->di_tv.v_type == VAR_LIST)
!           {
!               event_list = di->di_tv.vval.v_list;
!               if (event_list == NULL)
!               {
!                   emsg(_(e_list_required));
!                   continue;
                }
            }
+           else
+           {
+               emsg(_(e_string_or_list_expected));
+               continue;
+           }
        }
  
        group_name = dict_get_string(event_dict, (char_u *)"group", TRUE);
***************
*** 2859,2879 ****
            if (bnum == -1)
                continue;
  
!           pat = alloc(128 + 1);
!           if (pat == NULL)
!               continue;
!           vim_snprintf((char *)pat, 128, "<buffer=%d>", (int)bnum);
        }
        else
        {
!           pat = dict_get_string(event_dict, (char_u *)"pattern", TRUE);
!           if (pat == NULL)
            {
!               if (delete)
!                   pat = vim_strsave((char_u *)"");
                else
                    continue;
            }
        }
  
        once = dict_get_bool(event_dict, (char_u *)"once", FALSE);
--- 2869,2908 ----
            if (bnum == -1)
                continue;
  
!           vim_snprintf((char *)IObuff, IOSIZE, "<buffer=%d>", (int)bnum);
!           pat = IObuff;
        }
        else
        {
!           di = dict_find(event_dict, (char_u *)"pattern", -1);
!           if (di != NULL)
            {
!               if (di->di_tv.v_type == VAR_STRING)
!               {
!                   pat = di->di_tv.vval.v_string;
!                   if (pat == NULL)
!                   {
!                       emsg(_(e_string_required));
!                       continue;
!                   }
!               }
!               else if (di->di_tv.v_type == VAR_LIST)
!               {
!                   pat_list = di->di_tv.vval.v_list;
!                   if (pat_list == NULL)
!                   {
!                       emsg(_(e_list_required));
!                       continue;
!                   }
!               }
                else
+               {
+                   emsg(_(e_string_or_list_expected));
                    continue;
+               }
            }
+           else if (delete)
+               pat = (char_u *)"";
        }
  
        once = dict_get_bool(event_dict, (char_u *)"once", FALSE);
***************
*** 2891,2899 ****
                continue;
        }
  
!       if (event == NUM_EVENTS)
        {
!           // event is '*', apply for all the events
            for (event = (event_T)0; (int)event < NUM_EVENTS;
                    event = (event_T)((int)event + 1))
            {
--- 2920,2929 ----
                continue;
        }
  
!       if (delete && (event_name == NULL
!                   || (event_name[0] == '*' && event_name[1] == NUL)))
        {
!           // if the event name is not specified or '*', delete all the events
            for (event = (event_T)0; (int)event < NUM_EVENTS;
                    event = (event_T)((int)event + 1))
            {
***************
*** 2907,2917 ****
        }
        else
        {
!           if (do_autocmd_event(event, pat, once, nested, cmd,
!                                       delete | replace, group, 0) == FAIL)
            {
!               retval = VVAL_FALSE;
!               break;
            }
        }
  
--- 2937,3012 ----
        }
        else
        {
!           eli = NULL;
!           end = NULL;
!           while (TRUE)
            {
!               if (event_list != NULL)
!               {
!                   if (eli == NULL)
!                       eli = event_list->lv_first;
!                   else
!                       eli = eli->li_next;
!                   if (eli == NULL)
!                       break;
!                   if (eli->li_tv.v_type != VAR_STRING
!                           || eli->li_tv.vval.v_string == NULL)
!                   {
!                       emsg(_(e_string_required));
!                       continue;
!                   }
!                   p = eli->li_tv.vval.v_string;
!               }
!               else
!               {
!                   if (end == NULL)
!                       p = end = event_name;
!                   if (end == NULL || *end == NUL)
!                       break;
!               }
!               if (p == NULL)
!                   continue;
! 
!               event = event_name2nr(p, &end);
!               if (event == NUM_EVENTS || *end != NUL)
!               {
!                   semsg(_(e_no_such_event_str), p);
!                   retval = VVAL_FALSE;
!                   break;
!               }
!               if (pat != NULL)
!               {
!                   if (do_autocmd_event(event, pat, once, nested, cmd,
!                               delete | replace, group, 0) == FAIL)
!                   {
!                       retval = VVAL_FALSE;
!                       break;
!                   }
!               }
!               else if (pat_list != NULL)
!               {
!                   FOR_ALL_LIST_ITEMS(pat_list, pli)
!                   {
!                       if (pli->li_tv.v_type != VAR_STRING
!                               || pli->li_tv.vval.v_string == NULL)
!                       {
!                           emsg(_(e_string_required));
!                           continue;
!                       }
!                       if (do_autocmd_event(event,
!                                   pli->li_tv.vval.v_string, once, nested,
!                                   cmd, delete | replace, group, 0) ==
!                               FAIL)
!                       {
!                           retval = VVAL_FALSE;
!                           break;
!                       }
!                   }
!                   if (retval == VVAL_FALSE)
!                       break;
!               }
!               if (event_name != NULL)
!                   p = end;
            }
        }
  
***************
*** 2925,2933 ****
            au_del_group(group_name);
      }
  
-     VIM_CLEAR(event_name);
      VIM_CLEAR(group_name);
-     VIM_CLEAR(pat);
      VIM_CLEAR(cmd);
  
      current_augroup = save_augroup;
--- 3020,3026 ----
*** ../vim-8.2.5029/src/errors.h        2022-05-27 17:26:50.538119977 +0100
--- src/errors.h        2022-05-27 17:57:45.764052324 +0100
***************
*** 1184,1190 ****
        INIT(= N_("E475: Invalid argument: %s"));
  EXTERN char e_invalid_value_for_argument_str[]
        INIT(= N_("E475: Invalid value for argument %s"));
! #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_PROP_POPUP)
  EXTERN char e_invalid_value_for_argument_str_str[]
        INIT(= N_("E475: Invalid value for argument %s: %s"));
  #endif
--- 1184,1190 ----
        INIT(= N_("E475: Invalid argument: %s"));
  EXTERN char e_invalid_value_for_argument_str[]
        INIT(= N_("E475: Invalid value for argument %s"));
! #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_PROP_POPUP) || 
defined(FEAT_EVAL)
  EXTERN char e_invalid_value_for_argument_str_str[]
        INIT(= N_("E475: Invalid value for argument %s: %s"));
  #endif
***************
*** 3280,3286 ****
        INIT(= N_("E1281: Atom '\\%%#=%c' must be at the start of the 
pattern"));
  #ifdef FEAT_EVAL
  EXTERN char e_bitshift_ops_must_be_number[]
!       INIT(= N_("E1282: bitshift operands must be numbers"));
  EXTERN char e_bitshift_ops_must_be_postive[]
!       INIT(= N_("E1283: bitshift amount must be a positive number"));
  #endif
--- 3280,3286 ----
        INIT(= N_("E1281: Atom '\\%%#=%c' must be at the start of the 
pattern"));
  #ifdef FEAT_EVAL
  EXTERN char e_bitshift_ops_must_be_number[]
!       INIT(= N_("E1282: Bitshift operands must be numbers"));
  EXTERN char e_bitshift_ops_must_be_postive[]
!       INIT(= N_("E1283: Bitshift amount must be a positive number"));
  #endif
*** ../vim-8.2.5029/src/testdir/test_autocmd.vim        2022-05-24 
11:40:07.518685751 +0100
--- src/testdir/test_autocmd.vim        2022-05-27 17:57:45.764052324 +0100
***************
*** 3429,3434 ****
--- 3429,3511 ----
          \ cmd: 'echo "bufadd"'}]
    call assert_fails('call autocmd_add(l)', 'E216:')
  
+   " Test for using a list of events and patterns
+   call autocmd_delete([#{group: 'TestAcSet'}])
+   let l = [#{group: 'TestAcSet', event: ['BufEnter', 'BufLeave'],
+         \ pattern: ['*.py', '*.sh'], cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   call assert_equal([
+         \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py',
+         \   nested: v:false,  once: v:false, event: 'BufEnter'},
+         \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh',
+         \   nested: v:false,  once: v:false, event: 'BufEnter'},
+         \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.py',
+         \   nested: v:false,  once: v:false, event: 'BufLeave'},
+         \ #{cmd: 'echo "bufcmds"', group: 'TestAcSet', pattern: '*.sh',
+         \   nested: v:false,  once: v:false, event: 'BufLeave'}],
+         \   autocmd_get(#{group: 'TestAcSet'}))
+ 
+   " Test for invalid values for 'event' item
+   call autocmd_delete([#{group: 'TestAcSet'}])
+   let l = [#{group: 'TestAcSet', event: test_null_string(),
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E928:')
+   let l = [#{group: 'TestAcSet', event: test_null_list(),
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E714:')
+   let l = [#{group: 'TestAcSet', event: {},
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E777:')
+   let l = [#{group: 'TestAcSet', event: [{}],
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E928:')
+   let l = [#{group: 'TestAcSet', event: [test_null_string()],
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E928:')
+   let l = [#{group: 'TestAcSet', event: 'BufEnter,BufLeave',
+         \ pattern: '*.py', cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E216:')
+   let l = [#{group: 'TestAcSet', event: [],
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   let l = [#{group: 'TestAcSet', event: [""],
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E216:')
+   let l = [#{group: 'TestAcSet', event: "",
+         \ pattern: "*.py", cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
+ 
+   " Test for invalid values for 'pattern' item
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: test_null_string(), cmd: 'echo "bufcmds"'}]
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: test_null_list(), cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E714:')
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: {}, cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E777:')
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: [{}], cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E928:')
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: [test_null_string()], cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E928:')
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: [], cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: [""], cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   let l = [#{group: 'TestAcSet', event: "BufEnter",
+         \ pattern: "", cmd: 'echo "bufcmds"'}]
+   call autocmd_add(l)
+   call assert_equal([], autocmd_get(#{group: 'TestAcSet'}))
+ 
+   let l = [#{group: 'TestAcSet', event: 'BufEnter,abc,BufLeave',
+         \ pattern: '*.py', cmd: 'echo "bufcmds"'}]
+   call assert_fails('call autocmd_add(l)', 'E216:')
+ 
    call assert_fails("call autocmd_add({})", 'E1211:')
    call assert_equal(v:false,  autocmd_add(test_null_list()))
    call assert_true(autocmd_add([[]]))
*** ../vim-8.2.5029/src/version.c       2022-05-27 17:26:50.546119970 +0100
--- src/version.c       2022-05-27 18:04:38.939665812 +0100
***************
*** 736,737 ****
--- 736,739 ----
  {   /* Add new patch number below this line */
+ /**/
+     5030,
  /**/

-- 
LAUNCELOT: At last!   A call!  A cry of distress ...
           (he draws his sword, and turns to CONCORDE)
           Concorde!  Brave, Concorde ... you shall not have died in vain!
CONCORDE:  I'm not quite dead, sir ...
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220527170644.0AD341C1929%40moolenaar.net.

Raspunde prin e-mail lui