0
0
mirror of https://github.com/vim/vim.git synced 2025-09-14 23:14:27 -04:00

patch 8.2.0294: cannot use Ex command that is also a function name

Problem:    Cannot use Ex command that is also a function name.
Solution:   Recognize an Ex command by a colon prefix.
This commit is contained in:
Bram Moolenaar 2020-02-21 18:42:43 +01:00
parent 818fc9ad14
commit 5b1c8fe3d5
4 changed files with 73 additions and 39 deletions

View File

@ -1,4 +1,4 @@
*vim9.txt* For Vim version 8.2. Last change: 2020 Feb 13 *vim9.txt* For Vim version 8.2. Last change: 2020 Feb 21
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -140,6 +140,13 @@ identifier or can't be an Ex command. It does not work for string constants: >
"foobar"->Process() " does NOT work "foobar"->Process() " does NOT work
eval "foobar"->Process() " works eval "foobar"->Process() " works
In case there is ambiguity between a function name and an Ex command, use ":"
to make clear you want to use the Ex command. For example, there is both the
`:substitute` command and the `substitute()` function. When the line starts
with `substitute(` this will use the function, prepend a colon to use the
command instead: >
:substitute(pattern(replacement(
No curly braces expansion ~ No curly braces expansion ~
@ -175,6 +182,9 @@ White space is not allowed:
call Func(arg) " OK call Func(arg) " OK
call Func( call Func(
\ arg) " OK \ arg) " OK
call Func(
\ arg " OK
\ )
Conditions and expressions ~ Conditions and expressions ~
@ -254,6 +264,12 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
:enddef End of a function defined with `:def`. :enddef End of a function defined with `:def`.
If the script the function is defined in is Vim9 script, then script-local
variables can be accessed without the "s:" prefix. They must be defined
before the function. If the script the function is defined in is legacy
script, then script-local variables must be accessed with the "s:" prefix.
*:disa* *:disassemble* *:disa* *:disassemble*
:disa[ssemble] {func} Show the instructions generated for {func}. :disa[ssemble] {func} Show the instructions generated for {func}.
This is for debugging and testing. This is for debugging and testing.

View File

@ -570,5 +570,12 @@ def Test_delfunc()
delete('XToDelFunc') delete('XToDelFunc')
enddef enddef
def Test_substitute_cmd()
new
setline(1, 'something')
:substitute(some(other(
assert_equal('otherthing', getline(1))
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@ -738,6 +738,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
294,
/**/ /**/
293, 293,
/**/ /**/

View File

@ -4739,6 +4739,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
*/ */
for (;;) for (;;)
{ {
int is_ex_command;
if (line != NULL && *line == '|') if (line != NULL && *line == '|')
// the line continues after a '|' // the line continues after a '|'
++line; ++line;
@ -4793,6 +4795,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
line = compile_block(ea.cmd, &cctx); line = compile_block(ea.cmd, &cctx);
continue; continue;
} }
is_ex_command = *ea.cmd == ':';
/* /*
* COMMAND MODIFIERS * COMMAND MODIFIERS
@ -4810,48 +4813,53 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
if (checkforcmd(&ea.cmd, "call", 3)) if (checkforcmd(&ea.cmd, "call", 3))
ea.cmd = skipwhite(ea.cmd); ea.cmd = skipwhite(ea.cmd);
// Assuming the command starts with a variable or function name, find if (!is_ex_command)
// what follows. Also "&opt = val", "$ENV = val" and "@r = val".
p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@')
? ea.cmd + 1 : ea.cmd;
p = to_name_end(p);
if (p > ea.cmd && *p != NUL)
{ {
int oplen; // Assuming the command starts with a variable or function name,
int heredoc; // find what follows. Also "&opt = val", "$ENV = val" and "@r =
// val".
// "funcname(" is always a function call. p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@')
// "varname[]" is an expression. ? ea.cmd + 1 : ea.cmd;
// "varname->expr" is an expression. p = to_name_end(p);
if (*p == '(' if (p > ea.cmd && *p != NUL)
|| *p == '['
|| ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
|| (*p == '-' && p[1] == '>'))
{ {
// TODO int oplen;
} int heredoc;
oplen = assignment_len(skipwhite(p), &heredoc); // "funcname(" is always a function call.
if (oplen > 0) // "varname[]" is an expression.
{ // "varname->expr" is an expression.
// Recognize an assignment if we recognize the variable name: if (*p == '('
// "g:var = expr" || *p == '['
// "var = expr" where "var" is a local var name.
// "&opt = expr"
// "$ENV = expr"
// "@r = expr"
if (*ea.cmd == '&'
|| *ea.cmd == '$'
|| *ea.cmd == '@'
|| ((p - ea.cmd) > 2 && ea.cmd[1] == ':') || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
|| lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0 || (*p == '-' && p[1] == '>'))
|| lookup_script(ea.cmd, p - ea.cmd) == OK
|| find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
{ {
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); // TODO
if (line == NULL) }
goto erret;
continue; oplen = assignment_len(skipwhite(p), &heredoc);
if (oplen > 0)
{
// Recognize an assignment if we recognize the variable
// name:
// "g:var = expr"
// "var = expr" where "var" is a local var name.
// "&opt = expr"
// "$ENV = expr"
// "@r = expr"
if (*ea.cmd == '&'
|| *ea.cmd == '$'
|| *ea.cmd == '@'
|| ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
|| lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
|| lookup_script(ea.cmd, p - ea.cmd) == OK
|| find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
{
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
if (line == NULL)
goto erret;
continue;
}
} }
} }
} }
@ -4860,7 +4868,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
* COMMAND after range * COMMAND after range
*/ */
ea.cmd = skip_range(ea.cmd, NULL); ea.cmd = skip_range(ea.cmd, NULL);
p = find_ex_command(&ea, NULL, lookup_local, &cctx); p = find_ex_command(&ea, NULL, is_ex_command ? NULL : lookup_local,
&cctx);
if (p == ea.cmd && ea.cmdidx != CMD_SIZE) if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
{ {