summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-08-05 20:40:03 +0200
committerBram Moolenaar <Bram@vim.org>2021-08-05 20:40:03 +0200
commit63b9173693015b135aad8e3657bef5e7f776787e (patch)
tree562fd413b11ae6a4c45f39538b89ec881aebf2cb
parentaf647e76cacc60d3cfc5df3ff5b3d9d4b69b519d (diff)
downloadvim-git-63b9173693015b135aad8e3657bef5e7f776787e.tar.gz
patch 8.2.3297: cannot use all commands inside a {} blockv8.2.3297
Problem: Cannot use all commands inside a {} block after :command and :autocmd. Solution: Do consider \n to separate commands. (closes #8620)
-rw-r--r--runtime/doc/map.txt7
-rw-r--r--src/errors.h4
-rw-r--r--src/eval.c6
-rw-r--r--src/evalvars.c4
-rw-r--r--src/ex_cmds.c4
-rw-r--r--src/ex_docmd.c39
-rw-r--r--src/ex_eval.c12
-rw-r--r--src/proto/ex_docmd.pro1
-rw-r--r--src/proto/ex_eval.pro1
-rw-r--r--src/syntax.c14
-rw-r--r--src/testdir/test_autocmd.vim8
-rw-r--r--src/testdir/test_usercommands.vim8
-rw-r--r--src/userfunc.c12
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c2
-rw-r--r--src/vim9script.c2
16 files changed, 90 insertions, 36 deletions
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index a10c85b7a..57239923a 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -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
diff --git a/src/errors.h b/src/errors.h
index 942cf658b..24420e43e 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -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"));
diff --git a/src/eval.c b/src/eval.c
index 550fe8e2b..a72519dc4 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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);
}
/*
diff --git a/src/evalvars.c b/src/evalvars.c
index dc747f717..721b688d5 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -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
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index d9ec4a44b..d30db9195 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -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);
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index fde68be72..a0e8370c2 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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)
{
@@ -5410,6 +5412,21 @@ check_nextcmd(char_u *p)
}
/*
+ * 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 @@ 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)
diff --git a/src/ex_eval.c b/src/ex_eval.c
index 827f9cdcd..77dceccf0 100644
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -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"
*/
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index 419d00457..ae378d9ed 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -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);
diff --git a/src/proto/ex_eval.pro b/src/proto/ex_eval.pro
index f1861612a..f5037c932 100644
--- a/src/proto/ex_eval.pro
+++ b/src/proto/ex_eval.pro
@@ -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);
diff --git a/src/syntax.c b/src/syntax.c
index fea317ab3..b3545b37b 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -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.
}
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 4a7dd60f6..b2e4952be 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -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
diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim
index 173b23ed2..9cb592e23 100644
--- a/src/testdir/test_usercommands.vim
+++ b/src/testdir/test_usercommands.vim
@@ -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
diff --git a/src/userfunc.c b/src/userfunc.c
index 5cb3d92e6..79a6621b2 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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:
diff --git a/src/version.c b/src/version.c
index c6852f1e7..48df2c1bd 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
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 d2a6f68db..d96724b12 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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) != '(')
{
diff --git a/src/vim9script.c b/src/vim9script.c
index 40f857fe0..68919e8cc 100644
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -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);
}