Skip to content

Commit 77b10ff

Browse files
committed
patch 8.2.2603: Vim9: no effect if user command is also a function
Problem: Vim9: no effect if user command is also a function. Solution: Check for paren following. (closes #7960)
1 parent 2e34c34 commit 77b10ff

7 files changed

Lines changed: 76 additions & 29 deletions

File tree

src/evalvars.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,12 +2805,15 @@ get_script_local_ht(void)
28052805

28062806
/*
28072807
* Look for "name[len]" in script-local variables and functions.
2808+
* When "cmd" is TRUE it must look like a command, a function must be followed
2809+
* by "(" or "->".
28082810
* Return OK when found, FAIL when not found.
28092811
*/
28102812
int
28112813
lookup_scriptitem(
28122814
char_u *name,
28132815
size_t len,
2816+
int cmd,
28142817
cctx_T *dummy UNUSED)
28152818
{
28162819
hashtab_T *ht = get_script_local_ht();
@@ -2845,19 +2848,26 @@ lookup_scriptitem(
28452848
if (p != buffer)
28462849
vim_free(p);
28472850

2851+
// Find a function, so that a following "->" works.
2852+
// When used as a command require "(" or "->" to follow, "Cmd" is a user
2853+
// command while "Cmd()" is a function call.
28482854
if (res != OK)
28492855
{
2850-
// Find a function, so that a following "->" works. Skip "g:" before a
2851-
// function name.
2852-
// Do not check for an internal function, since it might also be a
2853-
// valid command, such as ":split" versuse "split()".
2854-
if (name[0] == 'g' && name[1] == ':')
2856+
p = skipwhite(name + len);
2857+
2858+
if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
28552859
{
2856-
is_global = TRUE;
2857-
fname = name + 2;
2860+
// Do not check for an internal function, since it might also be a
2861+
// valid command, such as ":split" versus "split()".
2862+
// Skip "g:" before a function name.
2863+
if (name[0] == 'g' && name[1] == ':')
2864+
{
2865+
is_global = TRUE;
2866+
fname = name + 2;
2867+
}
2868+
if (find_func(fname, is_global, NULL) != NULL)
2869+
res = OK;
28582870
}
2859-
if (find_func(fname, is_global, NULL) != NULL)
2860-
res = OK;
28612871
}
28622872

28632873
return res;
@@ -3288,7 +3298,7 @@ set_var_const(
32883298
{
32893299
// Item not found, check if a function already exists.
32903300
if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
3291-
&& lookup_scriptitem(name, STRLEN(name), NULL) == OK)
3301+
&& lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
32923302
{
32933303
semsg(_(e_redefining_script_item_str), name);
32943304
goto failed;

src/ex_docmd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3311,7 +3311,7 @@ skip_option_env_lead(char_u *start)
33113311
find_ex_command(
33123312
exarg_T *eap,
33133313
int *full UNUSED,
3314-
int (*lookup)(char_u *, size_t, cctx_T *) UNUSED,
3314+
int (*lookup)(char_u *, size_t, int cmd, cctx_T *) UNUSED,
33153315
cctx_T *cctx UNUSED)
33163316
{
33173317
int len;
@@ -3430,7 +3430,7 @@ find_ex_command(
34303430
|| *eap->cmd == '&'
34313431
|| *eap->cmd == '$'
34323432
|| *eap->cmd == '@'
3433-
|| lookup(eap->cmd, p - eap->cmd, cctx) == OK)
3433+
|| lookup(eap->cmd, p - eap->cmd, TRUE, cctx) == OK)
34343434
{
34353435
eap->cmdidx = CMD_var;
34363436
return eap->cmd;
@@ -3449,7 +3449,7 @@ find_ex_command(
34493449
// If it is an ID it might be a variable with an operator on the next
34503450
// line, if the variable exists it can't be an Ex command.
34513451
if (p > eap->cmd && ends_excmd(*skipwhite(p))
3452-
&& (lookup(eap->cmd, p - eap->cmd, cctx) == OK
3452+
&& (lookup(eap->cmd, p - eap->cmd, TRUE, cctx) == OK
34533453
|| (ASCII_ISALPHA(eap->cmd[0]) && eap->cmd[1] == ':')))
34543454
{
34553455
eap->cmdidx = CMD_eval;

src/proto/evalvars.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void check_vars(char_u *name, int len);
6161
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
6262
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
6363
hashtab_T *get_script_local_ht(void);
64-
int lookup_scriptitem(char_u *name, size_t len, cctx_T *dummy);
64+
int lookup_scriptitem(char_u *name, size_t len, int cmd, cctx_T *dummy);
6565
hashtab_T *find_var_ht(char_u *name, char_u **varname);
6666
char_u *get_var_value(char_u *name);
6767
void new_script_vars(scid_T id);

src/proto/ex_docmd.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ void undo_cmdmod(cmdmod_T *cmod);
1313
int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
1414
int checkforcmd(char_u **pp, char *cmd, int len);
1515
char_u *skip_option_env_lead(char_u *start);
16-
char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
16+
char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, int cmd, cctx_T *), cctx_T *cctx);
1717
int modifier_len(char_u *cmd);
1818
int cmd_exists(char_u *name);
1919
void f_fullcommand(typval_T *argvars, typval_T *rettv);

src/testdir/test_vim9_cmd.vim

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,8 @@ def Test_method_call_linebreak()
364364
return F()
365365
enddef
366366
def Test()
367-
Foo
368-
->Bar()
369-
->setline(1)
367+
Foo ->Bar()
368+
->setline(1)
370369
enddef
371370
Test()
372371
assert_equal('the text', getline(1))
@@ -401,8 +400,7 @@ def Test_method_call_linebreak()
401400
return F()
402401
enddef
403402

404-
Foo
405-
->Bar()
403+
Foo->Bar()
406404
->setline(1)
407405
END
408406
CheckScriptSuccess(lines)
@@ -424,6 +422,33 @@ def Test_method_call_whitespace()
424422
CheckDefAndScriptSuccess(lines)
425423
enddef
426424

425+
def Test_method_and_user_command()
426+
var lines =<< trim END
427+
vim9script
428+
def Cmd()
429+
g:didFunc = 1
430+
enddef
431+
command Cmd g:didCmd = 1
432+
Cmd
433+
assert_equal(1, g:didCmd)
434+
Cmd()
435+
assert_equal(1, g:didFunc)
436+
unlet g:didFunc
437+
unlet g:didCmd
438+
439+
def InDefFunc()
440+
Cmd
441+
assert_equal(1, g:didCmd)
442+
Cmd()
443+
assert_equal(1, g:didFunc)
444+
unlet g:didFunc
445+
unlet g:didCmd
446+
enddef
447+
InDefFunc()
448+
END
449+
CheckScriptSuccess(lines)
450+
enddef
451+
427452
def Test_skipped_expr_linebreak()
428453
if 0
429454
var x = []

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2603,
753755
/**/
754756
2602,
755757
/**/

src/vim9compile.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -391,19 +391,29 @@ variable_exists(char_u *name, size_t len, cctx_T *cctx)
391391
* imported or function.
392392
*/
393393
static int
394-
item_exists(char_u *name, size_t len, cctx_T *cctx)
394+
item_exists(char_u *name, size_t len, int cmd UNUSED, cctx_T *cctx)
395395
{
396396
int is_global;
397+
char_u *p;
397398

398399
if (variable_exists(name, len, cctx))
399400
return TRUE;
400401

401-
// Find a function, so that a following "->" works. Skip "g:" before a
402-
// function name.
403-
// Do not check for an internal function, since it might also be a
404-
// valid command, such as ":split" versuse "split()".
405-
is_global = (name[0] == 'g' && name[1] == ':');
406-
return find_func(is_global ? name + 2 : name, is_global, cctx) != NULL;
402+
// This is similar to what is in lookup_scriptitem():
403+
// Find a function, so that a following "->" works.
404+
// Require "(" or "->" to follow, "Cmd" is a user command while "Cmd()" is
405+
// a function call.
406+
p = skipwhite(name + len);
407+
408+
if (name[len] == '(' || (p[0] == '-' && p[1] == '>'))
409+
{
410+
// Do not check for an internal function, since it might also be a
411+
// valid command, such as ":split" versuse "split()".
412+
// Skip "g:" before a function name.
413+
is_global = (name[0] == 'g' && name[1] == ':');
414+
return find_func(is_global ? name + 2 : name, is_global, cctx) != NULL;
415+
}
416+
return FALSE;
407417
}
408418

409419
/*
@@ -8429,8 +8439,8 @@ compile_def_function(
84298439
}
84308440
}
84318441
}
8432-
p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
8433-
: (int (*)(char_u *, size_t, cctx_T *))item_exists, &cctx);
8442+
p = find_ex_command(&ea, NULL, starts_with_colon
8443+
? NULL : item_exists, &cctx);
84348444

84358445
if (p == NULL)
84368446
{

0 commit comments

Comments
 (0)