summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-03-14 13:21:35 +0100
committerBram Moolenaar <Bram@vim.org>2021-03-14 13:21:35 +0100
commit77b10ffad4ebad15022614be4db2745f6a90f405 (patch)
tree8319b6d1ba747e28f7ef57082978d9be464049c5
parent2e34c34be1393027a761ecbccd8f267d52ca7bc1 (diff)
downloadvim-git-77b10ffad4ebad15022614be4db2745f6a90f405.tar.gz
patch 8.2.2603: Vim9: no effect if user command is also a functionv8.2.2603
Problem: Vim9: no effect if user command is also a function. Solution: Check for paren following. (closes #7960)
-rw-r--r--src/evalvars.c30
-rw-r--r--src/ex_docmd.c6
-rw-r--r--src/proto/evalvars.pro2
-rw-r--r--src/proto/ex_docmd.pro2
-rw-r--r--src/testdir/test_vim9_cmd.vim35
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c28
7 files changed, 76 insertions, 29 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index eefd05f36..79c7a9c8c 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -2805,12 +2805,15 @@ get_script_local_ht(void)
/*
* Look for "name[len]" in script-local variables and functions.
+ * When "cmd" is TRUE it must look like a command, a function must be followed
+ * by "(" or "->".
* Return OK when found, FAIL when not found.
*/
int
lookup_scriptitem(
char_u *name,
size_t len,
+ int cmd,
cctx_T *dummy UNUSED)
{
hashtab_T *ht = get_script_local_ht();
@@ -2845,19 +2848,26 @@ lookup_scriptitem(
if (p != buffer)
vim_free(p);
+ // Find a function, so that a following "->" works.
+ // When used as a command require "(" or "->" to follow, "Cmd" is a user
+ // command while "Cmd()" is a function call.
if (res != OK)
{
- // Find a function, so that a following "->" works. Skip "g:" before a
- // function name.
- // Do not check for an internal function, since it might also be a
- // valid command, such as ":split" versuse "split()".
- if (name[0] == 'g' && name[1] == ':')
+ p = skipwhite(name + len);
+
+ if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
{
- is_global = TRUE;
- fname = name + 2;
+ // Do not check for an internal function, since it might also be a
+ // valid command, such as ":split" versus "split()".
+ // Skip "g:" before a function name.
+ if (name[0] == 'g' && name[1] == ':')
+ {
+ is_global = TRUE;
+ fname = name + 2;
+ }
+ if (find_func(fname, is_global, NULL) != NULL)
+ res = OK;
}
- if (find_func(fname, is_global, NULL) != NULL)
- res = OK;
}
return res;
@@ -3288,7 +3298,7 @@ set_var_const(
{
// Item not found, check if a function already exists.
if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
- && lookup_scriptitem(name, STRLEN(name), NULL) == OK)
+ && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
{
semsg(_(e_redefining_script_item_str), name);
goto failed;
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index c7b57ba99..477d140bd 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3311,7 +3311,7 @@ skip_option_env_lead(char_u *start)
find_ex_command(
exarg_T *eap,
int *full UNUSED,
- int (*lookup)(char_u *, size_t, cctx_T *) UNUSED,
+ int (*lookup)(char_u *, size_t, int cmd, cctx_T *) UNUSED,
cctx_T *cctx UNUSED)
{
int len;
@@ -3430,7 +3430,7 @@ find_ex_command(
|| *eap->cmd == '&'
|| *eap->cmd == '$'
|| *eap->cmd == '@'
- || lookup(eap->cmd, p - eap->cmd, cctx) == OK)
+ || lookup(eap->cmd, p - eap->cmd, TRUE, cctx) == OK)
{
eap->cmdidx = CMD_var;
return eap->cmd;
@@ -3449,7 +3449,7 @@ find_ex_command(
// If it is an ID it might be a variable with an operator on the next
// line, if the variable exists it can't be an Ex command.
if (p > eap->cmd && ends_excmd(*skipwhite(p))
- && (lookup(eap->cmd, p - eap->cmd, cctx) == OK
+ && (lookup(eap->cmd, p - eap->cmd, TRUE, cctx) == OK
|| (ASCII_ISALPHA(eap->cmd[0]) && eap->cmd[1] == ':')))
{
eap->cmdidx = CMD_eval;
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 1094d4563..c75f80a86 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -61,7 +61,7 @@ void check_vars(char_u *name, int len);
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
hashtab_T *get_script_local_ht(void);
-int lookup_scriptitem(char_u *name, size_t len, cctx_T *dummy);
+int lookup_scriptitem(char_u *name, size_t len, int cmd, cctx_T *dummy);
hashtab_T *find_var_ht(char_u *name, char_u **varname);
char_u *get_var_value(char_u *name);
void new_script_vars(scid_T id);
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index dcd9f3940..9ac8eaf52 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -13,7 +13,7 @@ void undo_cmdmod(cmdmod_T *cmod);
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
int checkforcmd(char_u **pp, char *cmd, int len);
char_u *skip_option_env_lead(char_u *start);
-char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
+char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, int cmd, cctx_T *), cctx_T *cctx);
int modifier_len(char_u *cmd);
int cmd_exists(char_u *name);
void f_fullcommand(typval_T *argvars, typval_T *rettv);
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index dd6e966de..c21e55a47 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -364,9 +364,8 @@ def Test_method_call_linebreak()
return F()
enddef
def Test()
- Foo
- ->Bar()
- ->setline(1)
+ Foo ->Bar()
+ ->setline(1)
enddef
Test()
assert_equal('the text', getline(1))
@@ -401,8 +400,7 @@ def Test_method_call_linebreak()
return F()
enddef
- Foo
- ->Bar()
+ Foo->Bar()
->setline(1)
END
CheckScriptSuccess(lines)
@@ -424,6 +422,33 @@ def Test_method_call_whitespace()
CheckDefAndScriptSuccess(lines)
enddef
+def Test_method_and_user_command()
+ var lines =<< trim END
+ vim9script
+ def Cmd()
+ g:didFunc = 1
+ enddef
+ command Cmd g:didCmd = 1
+ Cmd
+ assert_equal(1, g:didCmd)
+ Cmd()
+ assert_equal(1, g:didFunc)
+ unlet g:didFunc
+ unlet g:didCmd
+
+ def InDefFunc()
+ Cmd
+ assert_equal(1, g:didCmd)
+ Cmd()
+ assert_equal(1, g:didFunc)
+ unlet g:didFunc
+ unlet g:didCmd
+ enddef
+ InDefFunc()
+ END
+ CheckScriptSuccess(lines)
+enddef
+
def Test_skipped_expr_linebreak()
if 0
var x = []
diff --git a/src/version.c b/src/version.c
index 5f950831b..14bf96bba 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2603,
+/**/
2602,
/**/
2601,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 1bb30ca0c..3fef9bd6b 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -391,19 +391,29 @@ variable_exists(char_u *name, size_t len, cctx_T *cctx)
* imported or function.
*/
static int
-item_exists(char_u *name, size_t len, cctx_T *cctx)
+item_exists(char_u *name, size_t len, int cmd UNUSED, cctx_T *cctx)
{
int is_global;
+ char_u *p;
if (variable_exists(name, len, cctx))
return TRUE;
- // Find a function, so that a following "->" works. Skip "g:" before a
- // function name.
- // Do not check for an internal function, since it might also be a
- // valid command, such as ":split" versuse "split()".
- is_global = (name[0] == 'g' && name[1] == ':');
- return find_func(is_global ? name + 2 : name, is_global, cctx) != NULL;
+ // This is similar to what is in lookup_scriptitem():
+ // Find a function, so that a following "->" works.
+ // Require "(" or "->" to follow, "Cmd" is a user command while "Cmd()" is
+ // a function call.
+ p = skipwhite(name + len);
+
+ if (name[len] == '(' || (p[0] == '-' && p[1] == '>'))
+ {
+ // Do not check for an internal function, since it might also be a
+ // valid command, such as ":split" versuse "split()".
+ // Skip "g:" before a function name.
+ is_global = (name[0] == 'g' && name[1] == ':');
+ return find_func(is_global ? name + 2 : name, is_global, cctx) != NULL;
+ }
+ return FALSE;
}
/*
@@ -8429,8 +8439,8 @@ compile_def_function(
}
}
}
- p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
- : (int (*)(char_u *, size_t, cctx_T *))item_exists, &cctx);
+ p = find_ex_command(&ea, NULL, starts_with_colon
+ ? NULL : item_exists, &cctx);
if (p == NULL)
{