Patch 8.2.3268
Problem:    Cannot use a block with :autocmd like with :command.
Solution:   Add support for a {} block after :autocmd. (closes #8620)
Files:      runtime/doc/autocmd.txt, runtime/doc/map.txt, src/autocmd.c,
            src/proto/autocmd.pro, src/usercmd.c, src/proto/usercmd.pro,
            src/ex_docmd.c, src/vim.h, src/testdir/test_autocmd.vim


*** ../vim-8.2.3267/runtime/doc/autocmd.txt     2021-01-31 17:02:06.246490203 
+0100
--- runtime/doc/autocmd.txt     2021-08-01 14:19:11.551359402 +0200
***************
*** 76,81 ****
--- 76,87 ----
  script.  Thus this depends on where the autocmd is defined, not where it is
  triggered.
  
+ {cmd} can use a block, like with `:command`, see |:command-repl|.  Example: >
+       au BufReadPost *.xml {
+                 setlocal matchpairs+=<:>
+                 /<start
+               }
+ 
  Note: The ":autocmd" command can only be followed by another command when the
  '|' appears before {cmd}.  This works: >
        :augroup mine | au! BufRead | augroup END
*** ../vim-8.2.3267/runtime/doc/map.txt 2021-07-27 21:17:28.483675842 +0200
--- runtime/doc/map.txt 2021-08-01 14:19:07.899370556 +0200
***************
*** 1552,1558 ****
  
  
  Replacement text ~
! 
  The {repl} argument is normally one long string, possibly with "|" separated
  commands.  A special case is when the argument is "{", then the following
  lines, up to a line starting with "}" are used and |Vim9| syntax applies.
--- 1571,1577 ----
  
  
  Replacement text ~
!                                                       *:command-repl*
  The {repl} argument is normally one long string, possibly with "|" separated
  commands.  A special case is when the argument is "{", then the following
  lines, up to a line starting with "}" are used and |Vim9| syntax applies.
***************
*** 1561,1567 ****
                echo 'hello'
                g:calledMyCommand = true
            }
! No nesting is supported.
  
  The replacement text {repl} for a user defined command is scanned for special
  escape sequences, using <...> notation.  Escape sequences are replaced with
--- 1580,1587 ----
                echo 'hello'
                g:calledMyCommand = true
            }
! No nesting is supported, inline functions cannot be used.  Using `:normal`
! directly does not work, you can use it indirectly with `:execute`.
  
  The replacement text {repl} for a user defined command is scanned for special
  escape sequences, using <...> notation.  Escape sequences are replaced with
*** ../vim-8.2.3267/src/autocmd.c       2021-04-03 13:19:23.102814497 +0200
--- src/autocmd.c       2021-08-01 14:35:10.456871122 +0200
***************
*** 258,264 ****
  
  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 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);
--- 258,264 ----
  
  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 once, int nested, 
char_u *cmd, int forceit, int group, int flags);
  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);
***************
*** 615,621 ****
  
      for (current_augroup = -1; current_augroup < augroups.ga_len;
                                                            ++current_augroup)
!       do_autocmd((char_u *)"", TRUE);
  
      for (i = 0; i < augroups.ga_len; ++i)
      {
--- 615,621 ----
  
      for (current_augroup = -1; current_augroup < augroups.ga_len;
                                                            ++current_augroup)
!       do_autocmd(NULL, (char_u *)"", TRUE);
  
      for (i = 0; i < augroups.ga_len; ++i)
      {
***************
*** 823,842 ****
   * :autocmd * *.c             show all autocommands for *.c files.
   *
   * Mostly a {group} argument can optionally appear before <event>.
   */
      void
! do_autocmd(char_u *arg_in, int forceit)
  {
      char_u    *arg = arg_in;
      char_u    *pat;
      char_u    *envpat = NULL;
      char_u    *cmd;
      event_T   event;
!     int               need_free = FALSE;
      int               nested = FALSE;
      int               once = FALSE;
      int               group;
      int               i;
  
      if (*arg == '|')
      {
--- 823,845 ----
   * :autocmd * *.c             show all autocommands for *.c files.
   *
   * Mostly a {group} argument can optionally appear before <event>.
+  * "eap" can be NULL.
   */
      void
! do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
  {
      char_u    *arg = arg_in;
      char_u    *pat;
      char_u    *envpat = NULL;
      char_u    *cmd;
+     int               cmd_need_free = FALSE;
      event_T   event;
!     char_u    *tofree = NULL;
      int               nested = FALSE;
      int               once = FALSE;
      int               group;
      int               i;
+     int               flags = 0;
  
      if (*arg == '|')
      {
***************
*** 935,944 ****
         */
        if (*cmd != NUL)
        {
            cmd = expand_sfile(cmd);
            if (cmd == NULL)        // some error
                return;
!           need_free = TRUE;
        }
      }
  
--- 938,951 ----
         */
        if (*cmd != NUL)
        {
+           if (eap != NULL)
+               // Read a {} block if it follows.
+               cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
+ 
            cmd = expand_sfile(cmd);
            if (cmd == NULL)        // some error
                return;
!           cmd_need_free = TRUE;
        }
      }
  
***************
*** 962,980 ****
            for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
                                             event = (event_T)((int)event + 1))
                if (do_autocmd_event(event, pat,
!                                   once, nested, cmd, forceit, group) == FAIL)
                    break;
      }
      else
      {
        while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
            if (do_autocmd_event(event_name2nr(arg, &arg), pat,
!                                once, nested,  cmd, forceit, group) == FAIL)
                break;
      }
  
!     if (need_free)
        vim_free(cmd);
      vim_free(envpat);
  }
  
--- 969,988 ----
            for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
                                             event = (event_T)((int)event + 1))
                if (do_autocmd_event(event, pat,
!                            once, nested, cmd, forceit, group, flags) == FAIL)
                    break;
      }
      else
      {
        while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
            if (do_autocmd_event(event_name2nr(arg, &arg), pat,
!                         once, nested, cmd, forceit, group, flags) == FAIL)
                break;
      }
  
!     if (cmd_need_free)
        vim_free(cmd);
+     vim_free(tofree);
      vim_free(envpat);
  }
  
***************
*** 1024,1030 ****
      int               nested,
      char_u    *cmd,
      int               forceit,
!     int               group)
  {
      AutoPat   *ap;
      AutoPat   **prev_ap;
--- 1032,1039 ----
      int               nested,
      char_u    *cmd,
      int               forceit,
!     int               group,
!     int               flags)
  {
      AutoPat   *ap;
      AutoPat   **prev_ap;
***************
*** 1251,1256 ****
--- 1260,1267 ----
                return FAIL;
            ac->cmd = vim_strsave(cmd);
            ac->script_ctx = current_sctx;
+           if (flags & UC_VIM9)
+               ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
  #ifdef FEAT_EVAL
            ac->script_ctx.sc_lnum += SOURCING_LNUM;
  #endif
*** ../vim-8.2.3267/src/proto/autocmd.pro       2020-08-20 15:02:38.536534973 
+0200
--- src/proto/autocmd.pro       2021-08-01 14:31:16.769427927 +0200
***************
*** 6,12 ****
  int check_ei(void);
  char_u *au_event_disable(char *what);
  void au_event_restore(char_u *old_ei);
! void do_autocmd(char_u *arg_in, int forceit);
  int do_doautocmd(char_u *arg, int do_msg, int *did_something);
  void ex_doautoall(exarg_T *eap);
  int check_nomodeline(char_u **argp);
--- 6,12 ----
  int check_ei(void);
  char_u *au_event_disable(char *what);
  void au_event_restore(char_u *old_ei);
! void do_autocmd(exarg_T *eap, char_u *arg_in, int forceit);
  int do_doautocmd(char_u *arg, int do_msg, int *did_something);
  void ex_doautoall(exarg_T *eap);
  int check_nomodeline(char_u **argp);
*** ../vim-8.2.3267/src/usercmd.c       2021-07-27 21:17:28.483675842 +0200
--- src/usercmd.c       2021-08-01 14:35:29.132827267 +0200
***************
*** 114,122 ****
      {ADDR_NONE, NULL, NULL}
  };
  
- #define UC_BUFFER     1       // -buffer: local to current buffer
- #define UC_VIM9               2       // {} argument: Vim9 syntax.
- 
  /*
   * Search for a user command that matches "eap->cmd".
   * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in 
"eap->useridx".
--- 114,119 ----
***************
*** 975,980 ****
--- 972,1020 ----
  }
  
  /*
+  * If "p" starts with "{" then read a block of commands until "}".
+  * Used for ":command" and ":autocmd".
+  */
+     char_u *
+ may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int *flags)
+ {
+     char_u *retp = p;
+ 
+     if (*p == '{' && ends_excmd2(eap->arg, skipwhite(p + 1))
+                                                      && eap->getline != NULL)
+     {
+       garray_T        ga;
+       char_u  *line = NULL;
+ 
+       ga_init2(&ga, sizeof(char_u *), 10);
+       if (ga_add_string(&ga, p) == FAIL)
+           return retp;
+ 
+       // Read lines between '{' and '}'.  Does not support nesting or
+       // here-doc constructs.
+       for (;;)
+       {
+           vim_free(line);
+           if ((line = eap->getline(':', eap->cookie,
+                                      0, GETLINE_CONCAT_CONTBAR)) == NULL)
+           {
+               emsg(_(e_missing_rcurly));
+               break;
+           }
+           if (ga_add_string(&ga, line) == FAIL)
+               break;
+           if (*skipwhite(line) == '}')
+               break;
+       }
+       vim_free(line);
+       retp = *tofree = ga_concat_strings(&ga, "\n");
+       ga_clear_strings(&ga);
+       *flags |= UC_VIM9;
+     }
+     return retp;
+ }
+ 
+ /*
   * ":command ..." implementation
   */
      void
***************
*** 1043,1080 ****
      {
        char_u *tofree = NULL;
  
!       if (*p == '{' && ends_excmd2(eap->arg, skipwhite(p + 1))
!                                                      && eap->getline != NULL)
!       {
!           garray_T    ga;
!           char_u      *line = NULL;
! 
!           ga_init2(&ga, sizeof(char_u *), 10);
!           if (ga_add_string(&ga, p) == FAIL)
!               return;
! 
!           // Read lines between '{' and '}'.  Does not support nesting or
!           // here-doc constructs.
!           //
!           for (;;)
!           {
!               vim_free(line);
!               if ((line = eap->getline(':', eap->cookie,
!                                          0, GETLINE_CONCAT_CONTBAR)) == NULL)
!               {
!                   emsg(_(e_missing_rcurly));
!                   break;
!               }
!               if (ga_add_string(&ga, line) == FAIL)
!                   break;
!               if (*skipwhite(line) == '}')
!                   break;
!           }
!           vim_free(line);
!           p = tofree = ga_concat_strings(&ga, "\n");
!           ga_clear_strings(&ga);
!           flags |= UC_VIM9;
!       }
  
        uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
                                                  addr_type_arg, eap->forceit);
--- 1083,1089 ----
      {
        char_u *tofree = NULL;
  
!       p = may_get_cmd_block(eap, p, &tofree, &flags);
  
        uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
                                                  addr_type_arg, eap->forceit);
*** ../vim-8.2.3267/src/proto/usercmd.pro       2020-10-26 18:46:49.480589241 
+0100
--- src/proto/usercmd.pro       2021-08-01 14:28:59.305764688 +0200
***************
*** 10,15 ****
--- 10,16 ----
  int cmdcomplete_str_to_type(char_u *complete_str);
  char *uc_fun_cmd(void);
  int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, 
char_u **compl_arg);
+ char_u *may_get_cmd_block(exarg_T *eap, char_u *p, char_u **tofree, int 
*flags);
  void ex_command(exarg_T *eap);
  void ex_comclear(exarg_T *eap);
  void uc_clear(garray_T *gap);
*** ../vim-8.2.3267/src/ex_docmd.c      2021-07-31 22:17:25.045867805 +0200
--- src/ex_docmd.c      2021-08-01 14:30:32.953534388 +0200
***************
*** 5203,5209 ****
              _(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search);
      }
      else if (eap->cmdidx == CMD_autocmd)
!       do_autocmd(eap->arg, eap->forceit);
      else
        do_augroup(eap->arg, eap->forceit);
  }
--- 5203,5209 ----
              _(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search);
      }
      else if (eap->cmdidx == CMD_autocmd)
!       do_autocmd(eap, eap->arg, eap->forceit);
      else
        do_augroup(eap->arg, eap->forceit);
  }
*** ../vim-8.2.3267/src/vim.h   2021-07-29 22:48:50.107129898 +0200
--- src/vim.h   2021-08-01 14:36:02.344749512 +0200
***************
*** 2739,2742 ****
--- 2739,2747 ----
  // flags for equal_type()
  #define ETYPE_ARG_UNKNOWN 1
  
+ // flags used by user commands and :autocmd
+ #define UC_BUFFER     1       // -buffer: local to current buffer
+ #define UC_VIM9               2       // {} argument: Vim9 syntax.
+ 
+ 
  #endif // VIM__H
*** ../vim-8.2.3267/src/testdir/test_autocmd.vim        2021-03-13 
15:47:51.577753545 +0100
--- src/testdir/test_autocmd.vim        2021-08-01 14:44:52.523534994 +0200
***************
*** 2810,2814 ****
--- 2810,2830 ----
    augroup END
  endfunc
  
+ func Test_autocmd_with_block()
+   augroup block_testing
+     au BufReadPost *.xml {
+             setlocal matchpairs+=<:>
+             /<start
+           }
+   augroup END
+ 
+   let expected = "\n--- Autocommands ---\nblock_testing  BufRead\n    *.xml   
  {^@            setlocal matchpairs+=<:>^@            /<start^@          }"
+   call assert_equal(expected, execute('au BufReadPost *.xml'))
+ 
+   augroup block_testing
+     au!
+   augroup END
+ endfunc
+ 
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.3267/src/version.c       2021-08-01 14:08:50.780946552 +0200
--- src/version.c       2021-08-01 14:45:53.627397054 +0200
***************
*** 757,758 ****
--- 757,760 ----
  {   /* Add new patch number below this line */
+ /**/
+     3268,
  /**/

-- 
"My particular problem is with registry entries, which seem to just
accumulate like plastic coffee cups..."           -- Paul Moore

 /// 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/202108011253.171Cr24f247665%40masaka.moolenaar.net.

Raspunde prin e-mail lui