To: vim_dev@googlegroups.com Subject: Patch 8.2.2603 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2603 Problem: Vim9: no effect if user command is also a function. Solution: Check for paren following. (closes #7960) Files: src/evalvars.c, src/proto/evalvars.pro, src/ex_docmd.c, src/proto/ex_docmd.pro, src/vim9compile.c, src/testdir/test_vim9_cmd.vim *** ../vim-8.2.2602/src/evalvars.c 2021-03-13 20:57:15.855515074 +0100 --- src/evalvars.c 2021-03-14 13:21:05.809109446 +0100 *************** *** 2805,2816 **** --- 2805,2819 ---- /* * 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,2863 **** if (p != buffer) vim_free(p); 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] == ':') { ! is_global = TRUE; ! fname = name + 2; } - if (find_func(fname, is_global, NULL) != NULL) - res = OK; } return res; --- 2848,2873 ---- 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) { ! p = skipwhite(name + len); ! ! if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>')) { ! // 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; } } return res; *************** *** 3288,3294 **** { // 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) { semsg(_(e_redefining_script_item_str), name); goto failed; --- 3298,3304 ---- { // 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), FALSE, NULL) == OK) { semsg(_(e_redefining_script_item_str), name); goto failed; *** ../vim-8.2.2602/src/proto/evalvars.pro 2021-03-13 20:57:15.855515074 +0100 --- src/proto/evalvars.pro 2021-03-14 12:35:30.444537708 +0100 *************** *** 61,67 **** 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); 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); --- 61,67 ---- 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, 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); *** ../vim-8.2.2602/src/ex_docmd.c 2021-03-13 21:07:17.742458250 +0100 --- src/ex_docmd.c 2021-03-14 12:32:04.745121747 +0100 *************** *** 3311,3317 **** find_ex_command( exarg_T *eap, int *full UNUSED, ! int (*lookup)(char_u *, size_t, cctx_T *) UNUSED, cctx_T *cctx UNUSED) { int len; --- 3311,3317 ---- find_ex_command( exarg_T *eap, int *full UNUSED, ! int (*lookup)(char_u *, size_t, int cmd, cctx_T *) UNUSED, cctx_T *cctx UNUSED) { int len; *************** *** 3430,3436 **** || *eap->cmd == '&' || *eap->cmd == '$' || *eap->cmd == '@' ! || lookup(eap->cmd, p - eap->cmd, cctx) == OK) { eap->cmdidx = CMD_var; return eap->cmd; --- 3430,3436 ---- || *eap->cmd == '&' || *eap->cmd == '$' || *eap->cmd == '@' ! || lookup(eap->cmd, p - eap->cmd, TRUE, cctx) == OK) { eap->cmdidx = CMD_var; return eap->cmd; *************** *** 3449,3455 **** // 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 || (ASCII_ISALPHA(eap->cmd[0]) && eap->cmd[1] == ':'))) { eap->cmdidx = CMD_eval; --- 3449,3455 ---- // 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, TRUE, cctx) == OK || (ASCII_ISALPHA(eap->cmd[0]) && eap->cmd[1] == ':'))) { eap->cmdidx = CMD_eval; *** ../vim-8.2.2602/src/proto/ex_docmd.pro 2021-02-17 14:52:10.539374448 +0100 --- src/proto/ex_docmd.pro 2021-03-14 12:36:15.644409316 +0100 *************** *** 13,19 **** 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); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); void f_fullcommand(typval_T *argvars, typval_T *rettv); --- 13,19 ---- 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, 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); *** ../vim-8.2.2602/src/vim9compile.c 2021-03-13 21:14:15.165663825 +0100 --- src/vim9compile.c 2021-03-14 12:52:30.129640837 +0100 *************** *** 391,409 **** * imported or function. */ static int ! item_exists(char_u *name, size_t len, cctx_T *cctx) { int is_global; 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; } /* --- 391,419 ---- * imported or function. */ static int ! 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; ! // 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,8436 **** } } } ! p = find_ex_command(&ea, NULL, starts_with_colon ? NULL ! : (int (*)(char_u *, size_t, cctx_T *))item_exists, &cctx); if (p == NULL) { --- 8439,8446 ---- } } } ! p = find_ex_command(&ea, NULL, starts_with_colon ! ? NULL : item_exists, &cctx); if (p == NULL) { *** ../vim-8.2.2602/src/testdir/test_vim9_cmd.vim 2021-03-06 21:01:05.865089577 +0100 --- src/testdir/test_vim9_cmd.vim 2021-03-14 13:03:28.750325986 +0100 *************** *** 364,372 **** return F() enddef def Test() ! Foo ! ->Bar() ! ->setline(1) enddef Test() assert_equal('the text', getline(1)) --- 364,371 ---- return F() enddef def Test() ! Foo ->Bar() ! ->setline(1) enddef Test() assert_equal('the text', getline(1)) *************** *** 401,408 **** return F() enddef ! Foo ! ->Bar() ->setline(1) END CheckScriptSuccess(lines) --- 400,406 ---- return F() enddef ! Foo->Bar() ->setline(1) END CheckScriptSuccess(lines) *************** *** 424,429 **** --- 422,454 ---- 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 = [] *** ../vim-8.2.2602/src/version.c 2021-03-14 12:13:30.192279488 +0100 --- src/version.c 2021-03-14 12:27:38.717876588 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2603, /**/ -- Are leaders born or made? And if they're made, can we return them under warranty? (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///