patch 8.2.3268: cannot use a block with :autocmd like with :command

Problem:    Cannot use a block with :autocmd like with :command.
Solution:   Add support for a {} block after :autocmd. (closes #8620)
diff --git a/src/autocmd.c b/src/autocmd.c
index 4c12e72..83e990d 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -258,7 +258,7 @@
 
 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 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,7 +615,7 @@
 
     for (current_augroup = -1; current_augroup < augroups.ga_len;
 							    ++current_augroup)
-	do_autocmd((char_u *)"", TRUE);
+	do_autocmd(NULL, (char_u *)"", TRUE);
 
     for (i = 0; i < augroups.ga_len; ++i)
     {
@@ -823,20 +823,23 @@
  * :autocmd * *.c		show all autocommands for *.c files.
  *
  * Mostly a {group} argument can optionally appear before <event>.
+ * "eap" can be NULL.
  */
     void
-do_autocmd(char_u *arg_in, int forceit)
+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;
-    int		need_free = FALSE;
+    char_u	*tofree = NULL;
     int		nested = FALSE;
     int		once = FALSE;
     int		group;
     int		i;
+    int		flags = 0;
 
     if (*arg == '|')
     {
@@ -935,10 +938,14 @@
 	 */
 	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;
-	    need_free = TRUE;
+	    cmd_need_free = TRUE;
 	}
     }
 
@@ -962,19 +969,20 @@
 	    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)
+			     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) == FAIL)
+			  once, nested,	cmd, forceit, group, flags) == FAIL)
 		break;
     }
 
-    if (need_free)
+    if (cmd_need_free)
 	vim_free(cmd);
+    vim_free(tofree);
     vim_free(envpat);
 }
 
@@ -1024,7 +1032,8 @@
     int		nested,
     char_u	*cmd,
     int		forceit,
-    int		group)
+    int		group,
+    int		flags)
 {
     AutoPat	*ap;
     AutoPat	**prev_ap;
@@ -1251,6 +1260,8 @@
 		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
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index c72e9c1..f2ff787 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -5203,7 +5203,7 @@
 	      _(e_command_not_allowed_from_vimrc_in_current_dir_or_tag_search);
     }
     else if (eap->cmdidx == CMD_autocmd)
-	do_autocmd(eap->arg, eap->forceit);
+	do_autocmd(eap, eap->arg, eap->forceit);
     else
 	do_augroup(eap->arg, eap->forceit);
 }
diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro
index 88eae5a..24dd1ba 100644
--- a/src/proto/autocmd.pro
+++ b/src/proto/autocmd.pro
@@ -6,7 +6,7 @@
 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);
+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);
diff --git a/src/proto/usercmd.pro b/src/proto/usercmd.pro
index 9e16a80..e9230d5 100644
--- a/src/proto/usercmd.pro
+++ b/src/proto/usercmd.pro
@@ -10,6 +10,7 @@
 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);
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 8abf911..4a7dd60 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
Binary files differ
diff --git a/src/usercmd.c b/src/usercmd.c
index 09e7b26..48f84b1 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -114,9 +114,6 @@
     {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".
@@ -975,6 +972,49 @@
 }
 
 /*
+ * 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,38 +1083,7 @@
     {
 	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;
-	}
+	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);
diff --git a/src/version.c b/src/version.c
index 962f002..b5173e6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3268,
+/**/
     3267,
 /**/
     3266,
diff --git a/src/vim.h b/src/vim.h
index 54d507e..7d23986 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -2739,4 +2739,9 @@
 // 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