patch 8.2.3297: cannot use all commands inside a {} block

Problem:    Cannot use all commands inside a {} block after :command and
            :autocmd.
Solution:   Do consider \n to separate commands. (closes #8620)
diff --git a/src/errors.h b/src/errors.h
index 942cf65..24420e4 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -643,4 +643,6 @@
 EXTERN char e_expected_dictionary_for_using_key_str_but_got_str[]
 	INIT(= N_("E1229: Expected dictionary for using key \"%s\", but got %s"));
 EXTERN char e_encryption_sodium_mlock_failed[]
-	INIT(= N_("E1230: encryption: sodium_mlock() failed"));
+	INIT(= N_("E1230: Encryption: sodium_mlock() failed"));
+EXTERN char e_cannot_use_bar_to_separate_commands_here_str[]
+	INIT(= N_("E1231: Cannot use a bar to separate commands here: %s"));
diff --git a/src/eval.c b/src/eval.c
index 550fe8e..a72519d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2314,7 +2314,7 @@
     }
 
     if (eap != NULL)
-	eap->nextcmd = check_nextcmd(p);
+	set_nextcmd(eap, p);
 
     return ret;
 }
@@ -6173,7 +6173,7 @@
 	clear_tv(&rettv);
 	arg = skipwhite(arg);
     }
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
     clear_evalarg(&evalarg, eap);
 
     if (eap->skip)
@@ -6317,7 +6317,7 @@
     if (eap->skip)
 	--emsg_skip;
 
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
 /*
diff --git a/src/evalvars.c b/src/evalvars.c
index dc747f7..721b688 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -812,7 +812,7 @@
 	    list_func_vars(&first);
 	    list_vim_vars(&first);
 	}
-	eap->nextcmd = check_nextcmd(arg);
+	set_nextcmd(eap, arg);
     }
     else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
     {
@@ -1629,7 +1629,7 @@
 	arg = skipwhite(name_end);
     } while (!ends_excmd2(name_end, arg));
 
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
     static int
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index d9ec4a4..d30db91 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -450,7 +450,7 @@
 	    unique = TRUE;
 	else if (*p == '"')	// comment start
 	    break;
-	else if (check_nextcmd(p) != NULL)
+	else if (eap->nextcmd == NULL && check_nextcmd(p) != NULL)
 	{
 	    eap->nextcmd = check_nextcmd(p);
 	    break;
@@ -3930,7 +3930,7 @@
     cmd = skipwhite(cmd);
     if (*cmd && *cmd != '"')	    // if not end-of-line or comment
     {
-	eap->nextcmd = check_nextcmd(cmd);
+	set_nextcmd(eap, cmd);
 	if (eap->nextcmd == NULL)
 	{
 	    semsg(_(e_trailing_arg), cmd);
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index fde68be..a0e8370 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -2314,22 +2314,24 @@
 	ea.do_ecmd_cmd = getargcmd(&ea.arg);
 
     /*
-     * Check for '|' to separate commands and '"' or '#' to start comments.
-     * Don't do this for ":read !cmd" and ":write !cmd".
-     */
-    if ((ea.argt & EX_TRLBAR) && !ea.usefilter)
-	separate_nextcmd(&ea);
-
-    /*
-     * Check for <newline> to end a shell command.
+     * For commands that do not use '|' inside their argument: Check for '|' to
+     * separate commands and '"' or '#' to start comments.
+     *
+     * Otherwise: Check for <newline> to end a shell command.
      * Also do this for ":read !cmd", ":write !cmd" and ":global".
+     * Also do this inside a { - } block after :command and :autocmd.
      * Any others?
      */
+    if ((ea.argt & EX_TRLBAR) && !ea.usefilter)
+    {
+	separate_nextcmd(&ea);
+    }
     else if (ea.cmdidx == CMD_bang
 	    || ea.cmdidx == CMD_terminal
 	    || ea.cmdidx == CMD_global
 	    || ea.cmdidx == CMD_vglobal
-	    || ea.usefilter)
+	    || ea.usefilter
+	    || inside_block(&ea))
     {
 	for (p = ea.arg; *p; ++p)
 	{
@@ -5410,6 +5412,21 @@
 }
 
 /*
+ * If "eap->nextcmd" is not set, check for a next command at "p".
+ */
+    void
+set_nextcmd(exarg_T *eap, char_u *arg)
+{
+    char_u *p = check_nextcmd(arg);
+
+    if (eap->nextcmd == NULL)
+	eap->nextcmd = p;
+    else if (p != NULL)
+	// cannot use "| command" inside a  {} block
+	semsg(_(e_cannot_use_bar_to_separate_commands_here_str), arg);
+}
+
+/*
  * - if there are more files to edit
  * - and this is the last window
  * - and forceit not used
@@ -7546,7 +7563,7 @@
     else
 	p = eap->arg + 1;
 
-    eap->nextcmd = check_nextcmd(p);
+    set_nextcmd(eap, p);
     p = skipwhite(p);
     if (*p != NUL && *p != (
 #ifdef FEAT_EVAL
@@ -8580,7 +8597,7 @@
 	    if (!ends_excmd2(eap->arg, p))
 		eap->errmsg = ex_errmsg(e_trailing_arg, p);
 	    else
-		eap->nextcmd = check_nextcmd(p);
+		set_nextcmd(eap, p);
 	}
     }
     if (!eap->skip)
diff --git a/src/ex_eval.c b/src/ex_eval.c
index 827f9cd..77dcecc 100644
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -1461,6 +1461,18 @@
 	leave_block(cstack);
 }
 
+    int
+inside_block(exarg_T *eap)
+{
+    cstack_T	*cstack = eap->cstack;
+    int		i;
+
+    for (i = 0; i <= cstack->cs_idx; ++i)
+	if (cstack->cs_flags[cstack->cs_idx] & CSF_BLOCK)
+	    return TRUE;
+    return FALSE;
+}
+
 /*
  * ":throw expr"
  */
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index 419d004..ae378d9 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -33,6 +33,7 @@
 int ends_excmd2(char_u *cmd_start, char_u *cmd);
 char_u *find_nextcmd(char_u *p);
 char_u *check_nextcmd(char_u *p);
+void set_nextcmd(exarg_T *eap, char_u *p);
 char_u *get_command_name(expand_T *xp, int idx);
 void not_exiting(void);
 int before_quit_autocmds(win_T *wp, int quit_all, int forceit);
diff --git a/src/proto/ex_eval.pro b/src/proto/ex_eval.pro
index f186161..f5037c9 100644
--- a/src/proto/ex_eval.pro
+++ b/src/proto/ex_eval.pro
@@ -22,6 +22,7 @@
 void ex_endwhile(exarg_T *eap);
 void ex_block(exarg_T *eap);
 void ex_endblock(exarg_T *eap);
+int inside_block(exarg_T *eap);
 void ex_throw(exarg_T *eap);
 void do_throw(cstack_T *cstack);
 void ex_try(exarg_T *eap);
diff --git a/src/syntax.c b/src/syntax.c
index fea317a..b3545b3 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3789,7 +3789,7 @@
     static void
 syn_cmd_reset(exarg_T *eap, int syncing UNUSED)
 {
-    eap->nextcmd = check_nextcmd(eap->arg);
+    set_nextcmd(eap, eap->arg);
     if (!eap->skip)
     {
 	set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset");
@@ -3821,7 +3821,7 @@
 {
     char_u	buf[100];
 
-    eap->nextcmd = check_nextcmd(eap->arg);
+    set_nextcmd(eap, eap->arg);
     if (!eap->skip)
     {
 	STRCPY(buf, "so ");
@@ -3928,7 +3928,7 @@
 	    arg = skipwhite(arg_end);
 	}
     }
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
     static void
@@ -4921,7 +4921,7 @@
     }
 
     if (rest != NULL)
-	eap->nextcmd = check_nextcmd(rest);
+	set_nextcmd(eap, rest);
     else
 	semsg(_(e_invarg2), arg);
 
@@ -4978,7 +4978,7 @@
 	/*
 	 * Check for trailing command and illegal trailing arguments.
 	 */
-	eap->nextcmd = check_nextcmd(rest);
+	set_nextcmd(eap, rest);
 	if (!ends_excmd2(eap->cmd, rest) || eap->skip)
 	    rest = NULL;
 	else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL
@@ -5218,7 +5218,7 @@
 	 * Check for trailing garbage or command.
 	 * If OK, add the item.
 	 */
-	eap->nextcmd = check_nextcmd(rest);
+	set_nextcmd(eap, rest);
 	if (!ends_excmd(*rest) || eap->skip)
 	    rest = NULL;
 	else if (ga_grow(&(curwin->w_s->b_syn_patterns), pat_count) != FAIL
@@ -5896,7 +5896,7 @@
 	semsg(_("E404: Illegal arguments: %s"), arg_start);
     else if (!finished)
     {
-	eap->nextcmd = check_nextcmd(arg_start);
+	set_nextcmd(eap, arg_start);
 	redraw_curbuf_later(SOME_VALID);
 	syn_stack_free_all(curwin->w_s);	// Need to recompute all syntax.
     }
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 4a7dd60..b2e4952 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
Binary files differ
diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim
index 173b23e..9cb592e 100644
--- a/src/testdir/test_usercommands.vim
+++ b/src/testdir/test_usercommands.vim
@@ -645,6 +645,14 @@
          echo 'hello'
   END
   call CheckScriptFailure(lines, 'E1026:')
+
+  let lines =<< trim END
+      command BarCommand {
+         echo 'hello' | echo 'there'
+        }
+      BarCommand
+  END
+  call CheckScriptFailure(lines, 'E1231:')
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/userfunc.c b/src/userfunc.c
index 5cb3d92..79a6621 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3842,7 +3842,7 @@
     {
 	if (!eap->skip)
 	    list_functions(NULL);
-	eap->nextcmd = check_nextcmd(eap->arg);
+	set_nextcmd(eap, eap->arg);
 	return NULL;
     }
 
@@ -3869,7 +3869,7 @@
 	}
 	if (*p == '/')
 	    ++p;
-	eap->nextcmd = check_nextcmd(p);
+	set_nextcmd(eap, p);
 	return NULL;
     }
 
@@ -3947,7 +3947,7 @@
 	    semsg(_(e_trailing_arg), p);
 	    goto ret_free;
 	}
-	eap->nextcmd = check_nextcmd(p);
+	set_nextcmd(eap, p);
 	if (eap->nextcmd != NULL)
 	    *p = NUL;
 	if (!eap->skip && !got_int)
@@ -4655,7 +4655,7 @@
 	semsg(_(e_trailing_arg), p);
 	return;
     }
-    eap->nextcmd = check_nextcmd(p);
+    set_nextcmd(eap, p);
     if (eap->nextcmd != NULL)
 	*p = NUL;
 
@@ -4844,7 +4844,7 @@
     if (returning)
 	eap->nextcmd = NULL;
     else if (eap->nextcmd == NULL)	    // no argument
-	eap->nextcmd = check_nextcmd(arg);
+	set_nextcmd(eap, arg);
 
     if (eap->skip)
 	--emsg_skip;
@@ -5004,7 +5004,7 @@
 	    }
 	}
 	else
-	    eap->nextcmd = check_nextcmd(arg);
+	    set_nextcmd(eap, arg);
     }
 
 end:
diff --git a/src/version.c b/src/version.c
index c6852f1..48df2c1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3297,
+/**/
     3296,
 /**/
     3295,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index d2a6f68..d96724b 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -5691,7 +5691,7 @@
 	name_end = skip_regexp(name_start + 1, '/', TRUE);
 	if (*name_end == '/')
 	    ++name_end;
-	eap->nextcmd = check_nextcmd(name_end);
+	set_nextcmd(eap, name_end);
     }
     if (name_end == name_start || *skipwhite(name_end) != '(')
     {
diff --git a/src/vim9script.c b/src/vim9script.c
index 40f857f..68919e8 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -311,7 +311,7 @@
     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
 							       &evalarg, NULL);
     if (cmd_end != NULL)
-	eap->nextcmd = check_nextcmd(cmd_end);
+	set_nextcmd(eap, cmd_end);
     clear_evalarg(&evalarg, eap);
 }