]> granicus.if.org Git - vim/commitdiff
patch 8.2.3297: cannot use all commands inside a {} block v8.2.3297
authorBram Moolenaar <Bram@vim.org>
Thu, 5 Aug 2021 18:40:03 +0000 (20:40 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 5 Aug 2021 18:40:03 +0000 (20:40 +0200)
Problem:    Cannot use all commands inside a {} block after :command and
            :autocmd.
Solution:   Do consider \n to separate commands. (closes #8620)

16 files changed:
runtime/doc/map.txt
src/errors.h
src/eval.c
src/evalvars.c
src/ex_cmds.c
src/ex_docmd.c
src/ex_eval.c
src/proto/ex_docmd.pro
src/proto/ex_eval.pro
src/syntax.c
src/testdir/test_autocmd.vim
src/testdir/test_usercommands.vim
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9script.c

index a10c85b7af7ed3d26180ccc422f1405c6377a3a4..57239923a4960f247ccb9dd57ef3403dcb6713af 100644 (file)
@@ -1580,8 +1580,11 @@ Example: >
                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`.
+<                                                      *E1231*
+There must be white space before the "{".  No nesting is supported, inline
+functions cannot be used.  Commands where a "|" may appear in the argument,
+such as commands with an expression argument, cannot be followed by a "|" and
+another command.
 
 The replacement text {repl} for a user defined command is scanned for special
 escape sequences, using <...> notation.  Escape sequences are replaced with
index 942cf658b49314a55a05e829980c253b5c339fae..24420e43efd9e6d5492562cc37e329139dffb2cd 100644 (file)
@@ -643,4 +643,6 @@ EXTERN char e_list_dict_or_blob_required_for_argument_nr[]
 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"));
index 550fe8e2ba91f2bb36c3017537c0a386d11ee8eb..a72519dc412ef30efa04ba634f752df7afb43146 100644 (file)
@@ -2314,7 +2314,7 @@ eval0(
     }
 
     if (eap != NULL)
-       eap->nextcmd = check_nextcmd(p);
+       set_nextcmd(eap, p);
 
     return ret;
 }
@@ -6173,7 +6173,7 @@ ex_echo(exarg_T *eap)
        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 @@ ex_execute(exarg_T *eap)
     if (eap->skip)
        --emsg_skip;
 
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
 /*
index dc747f717a58834e653b53482142a14f1f7f0c82..721b688d5835f6ba680122829739609a798202e1 100644 (file)
@@ -812,7 +812,7 @@ ex_let(exarg_T *eap)
            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 @@ ex_unletlock(
        arg = skipwhite(name_end);
     } while (!ends_excmd2(name_end, arg));
 
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
     static int
index d9ec4a44b34eeec7739894d9eea4f2914208c7e0..d30db91952ee7ab478f3e6af5bb52a048de8a726 100644 (file)
@@ -450,7 +450,7 @@ ex_sort(exarg_T *eap)
            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 @@ ex_substitute(exarg_T *eap)
     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);
index fde68be723aab85b6469c63ed1bf4ce35dbf3386..a0e8370c276a19c58bd4e73f06a826756f9c568a 100644 (file)
@@ -2314,22 +2314,24 @@ do_one_cmd(
        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)
        {
@@ -5409,6 +5411,21 @@ check_nextcmd(char_u *p)
        return NULL;
 }
 
+/*
+ * 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
@@ -7546,7 +7563,7 @@ ex_wincmd(exarg_T *eap)
     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 @@ ex_findpat(exarg_T *eap)
            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)
index 827f9cdcdb8eec8d19980c72eb86008ae5176c1c..77dceccf002c3e89a229c70f00533699a5d9649c 100644 (file)
@@ -1461,6 +1461,18 @@ ex_endblock(exarg_T *eap)
        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"
  */
index 419d00457cb4ce758294126a28724b6934574845..ae378d9ed7a2f524fc254927cf073d03765f5335 100644 (file)
@@ -33,6 +33,7 @@ int ends_excmd(int c);
 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);
index f1861612a589044a063cd47edda13a4194e21ac9..f5037c932506b38102e5f2bacda5f0dbcbd2e61e 100644 (file)
@@ -22,6 +22,7 @@ void ex_break(exarg_T *eap);
 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);
index fea317ab33359ac9efb904dc11942982a08e305c..b3545b37b64ac88954cb3e5af39514c029679cb0 100644 (file)
@@ -3789,7 +3789,7 @@ syn_cmd_enable(exarg_T *eap, int syncing UNUSED)
     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 @@ syn_cmd_onoff(exarg_T *eap, char *name)
 {
     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 @@ syn_cmd_list(
            arg = skipwhite(arg_end);
        }
     }
-    eap->nextcmd = check_nextcmd(arg);
+    set_nextcmd(eap, arg);
 }
 
     static void
@@ -4921,7 +4921,7 @@ error:
     }
 
     if (rest != NULL)
-       eap->nextcmd = check_nextcmd(rest);
+       set_nextcmd(eap, rest);
     else
        semsg(_(e_invarg2), arg);
 
@@ -4978,7 +4978,7 @@ syn_cmd_match(
        /*
         * 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 @@ syn_cmd_region(
         * 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 @@ syn_cmd_sync(exarg_T *eap, int syncing UNUSED)
        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.
     }
index 4a7dd60f6d8be52764a635a738a022c59a6036f5..b2e4952be089ea34c1baacd1b0b721a226741bf3 100644 (file)
@@ -2816,11 +2816,19 @@ func Test_autocmd_with_block()
             setlocal matchpairs+=<:>
             /<start
           }
+    au CursorHold * {
+        autocmd BufReadPre * ++once echo 'one' | echo 'two'
+        g:gotSafeState = 77
+      }
   augroup END
 
   let expected = "\n--- Autocommands ---\nblock_testing  BufRead\n    *.xml     {^@            setlocal matchpairs+=<:>^@            /<start^@          }"
   call assert_equal(expected, execute('au BufReadPost *.xml'))
 
+  doautocmd CursorHold
+  call assert_equal(77, g:gotSafeState)
+  unlet g:gotSafeState
+
   augroup block_testing
     au!
   augroup END
index 173b23ed2ed27a255a49b4456b3435d97fcac16b..9cb592e23018dfd6dae0ae55a5fd3e2ae0e63143 100644 (file)
@@ -645,6 +645,14 @@ func Test_usercmd_with_block()
          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
index 5cb3d92e6bb16603dfad0b1ea252fc6eb6c1add1..79a6621b249527e9814ddd92158498b538072368 100644 (file)
@@ -3842,7 +3842,7 @@ define_function(exarg_T *eap, char_u *name_arg)
     {
        if (!eap->skip)
            list_functions(NULL);
-       eap->nextcmd = check_nextcmd(eap->arg);
+       set_nextcmd(eap, eap->arg);
        return NULL;
     }
 
@@ -3869,7 +3869,7 @@ define_function(exarg_T *eap, char_u *name_arg)
        }
        if (*p == '/')
            ++p;
-       eap->nextcmd = check_nextcmd(p);
+       set_nextcmd(eap, p);
        return NULL;
     }
 
@@ -3947,7 +3947,7 @@ define_function(exarg_T *eap, char_u *name_arg)
            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 @@ ex_delfunction(exarg_T *eap)
        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 @@ ex_return(exarg_T *eap)
     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 @@ ex_call(exarg_T *eap)
            }
        }
        else
-           eap->nextcmd = check_nextcmd(arg);
+           set_nextcmd(eap, arg);
     }
 
 end:
index c6852f1e72f4ad912a23d2fcca729c18800c20e9..48df2c1bda8f70d4d9258555f3507c10d51ca054 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3297,
 /**/
     3296,
 /**/
index d2a6f68db002c603770c54cd67b9b8bc5ea8bf82..d96724b12c639ba0f616189b09c2f637e10f79e0 100644 (file)
@@ -5691,7 +5691,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
        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) != '(')
     {
index 40f857fe076908cc8b98048861a44d16d0087928..68919e8cc1ebf219bc148f9c2d4dafa7f3c4b583 100644 (file)
@@ -311,7 +311,7 @@ ex_import(exarg_T *eap)
     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);
 }