Problem: Vim9: no effect if user command is also a function.
Solution: Check for paren following. (closes #7960)
/*
* 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();
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;
{
// 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;
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;
|| *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;
// 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;
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);
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);
return F()
enddef
def Test()
- Foo
- ->Bar()
- ->setline(1)
+ Foo ->Bar()
+ ->setline(1)
enddef
Test()
assert_equal('the text', getline(1))
return F()
enddef
- Foo
- ->Bar()
+ Foo->Bar()
->setline(1)
END
CheckScriptSuccess(lines)
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 = []
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2603,
/**/
2602,
/**/
* 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;
}
/*
}
}
}
- 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)
{