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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202103141222.12ECM1Mf220199%40masaka.moolenaar.net.

Raspunde prin e-mail lui