# HG changeset patch # User Bram Moolenaar # Date 1582307106 -3600 # Node ID b09afbebffee898b8b691dc275a989a04f3be7f1 # Parent fa1ea6285f8002879361ec5fabafd9f80c9eb8f6 patch 8.2.0294: cannot use Ex command that is also a function name Commit: https://github.com/vim/vim/commit/5b1c8fe3d588ab450d4646a0088db4efda88200a Author: Bram Moolenaar Date: Fri Feb 21 18:42:43 2020 +0100 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. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -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 @@ -140,6 +140,13 @@ identifier or can't be an Ex command. I "foobar"->Process() " does NOT work 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 ~ @@ -175,6 +182,9 @@ White space is not allowed: call Func(arg) " OK call Func( \ arg) " OK + call Func( + \ arg " OK + \ ) Conditions and expressions ~ @@ -254,6 +264,12 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHI :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[ssemble] {func} Show the instructions generated for {func}. This is for debugging and testing. diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -570,5 +570,12 @@ def Test_delfunc() delete('XToDelFunc') 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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 294, +/**/ 293, /**/ 292, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4739,6 +4739,8 @@ compile_def_function(ufunc_T *ufunc, int */ for (;;) { + int is_ex_command; + if (line != NULL && *line == '|') // the line continues after a '|' ++line; @@ -4793,6 +4795,7 @@ compile_def_function(ufunc_T *ufunc, int line = compile_block(ea.cmd, &cctx); continue; } + is_ex_command = *ea.cmd == ':'; /* * COMMAND MODIFIERS @@ -4810,48 +4813,53 @@ compile_def_function(ufunc_T *ufunc, int if (checkforcmd(&ea.cmd, "call", 3)) ea.cmd = skipwhite(ea.cmd); - // Assuming the command starts with a variable or function name, find - // 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) + if (!is_ex_command) { - int oplen; - int heredoc; - - // "funcname(" is always a function call. - // "varname[]" is an expression. - // "varname->expr" is an expression. - if (*p == '(' - || *p == '[' - || ((p - ea.cmd) > 2 && ea.cmd[1] == ':') - || (*p == '-' && p[1] == '>')) + // Assuming the command starts with a variable or function name, + // find 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) { - // TODO - } - - 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 == '@' + int oplen; + int heredoc; + + // "funcname(" is always a function call. + // "varname[]" is an expression. + // "varname->expr" is an expression. + if (*p == '(' + || *p == '[' || ((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) + || (*p == '-' && p[1] == '>')) + { + // TODO + } + + oplen = assignment_len(skipwhite(p), &heredoc); + if (oplen > 0) { - line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); - if (line == NULL) - goto erret; - continue; + // 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 * COMMAND after range */ 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) {