]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4123: complete function cannot be import.Name v8.2.4123
authorBram Moolenaar <Bram@vim.org>
Mon, 17 Jan 2022 20:09:08 +0000 (20:09 +0000)
committerBram Moolenaar <Bram@vim.org>
Mon, 17 Jan 2022 20:09:08 +0000 (20:09 +0000)
Problem:    Complete function cannot be import.Name.
Solution:   Dereference the function name if needed.  Also: do not see
            "import.Name" as a builtin function. (closes #9541)

src/eval.c
src/testdir/test_vim9_import.vim
src/userfunc.c
src/version.c

index a21fbba8515941190e002905e19c34e51f5b8d13..df73ba1aee3c677931a48cf3bfff5427e0ef807c 100644 (file)
@@ -625,6 +625,63 @@ eval_expr(char_u *arg, exarg_T *eap)
     return tv;
 }
 
+/*
+ * "*arg" points to what can be a function name in the form of "import.Name" or
+ * "Funcref".  Return the name of the function.  Set "tofree" to something that
+ * was allocated.
+ * If "verbose" is FALSE no errors are given.
+ * Return NULL for any failure.
+ */
+    static char_u *
+deref_function_name(
+           char_u **arg,
+           char_u **tofree,
+           evalarg_T *evalarg,
+           int verbose)
+{
+    typval_T   ref;
+    char_u     *name = *arg;
+
+    ref.v_type = VAR_UNKNOWN;
+    if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
+       return NULL;
+    if (*skipwhite(*arg) != NUL)
+    {
+       if (verbose)
+           semsg(_(e_trailing_characters_str), *arg);
+       name = NULL;
+    }
+    else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
+    {
+       name = ref.vval.v_string;
+       ref.vval.v_string = NULL;
+       *tofree = name;
+    }
+    else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
+    {
+       if (ref.vval.v_partial->pt_argc > 0
+               || ref.vval.v_partial->pt_dict != NULL)
+       {
+           if (verbose)
+               emsg(_(e_cannot_use_partial_here));
+           name = NULL;
+       }
+       else
+       {
+           name = vim_strsave(partial_name(ref.vval.v_partial));
+           *tofree = name;
+       }
+    }
+    else
+    {
+       if (verbose)
+           semsg(_(e_not_callable_type_str), name);
+       name = NULL;
+    }
+    clear_tv(&ref);
+    return name;
+}
+
 /*
  * Call some Vim script function and return the result in "*rettv".
  * Uses argv[0] to argv[argc - 1] for the function arguments.  argv[argc]
@@ -640,15 +697,27 @@ call_vim_function(
 {
     int                ret;
     funcexe_T  funcexe;
+    char_u     *arg;
+    char_u     *name;
+    char_u     *tofree = NULL;
 
     rettv->v_type = VAR_UNKNOWN;               // clear_tv() uses this
     CLEAR_FIELD(funcexe);
     funcexe.fe_firstline = curwin->w_cursor.lnum;
     funcexe.fe_lastline = curwin->w_cursor.lnum;
     funcexe.fe_evaluate = TRUE;
-    ret = call_func(func, -1, rettv, argc, argv, &funcexe);
+
+    // The name might be "import.Func" or "Funcref".
+    arg = func;
+    name = deref_function_name(&arg, &tofree, &EVALARG_EVALUATE, FALSE);
+    if (name == NULL)
+       name = func;
+
+    ret = call_func(name, -1, rettv, argc, argv, &funcexe);
+
     if (ret == FAIL)
        clear_tv(rettv);
+    vim_free(tofree);
 
     return ret;
 }
@@ -3979,57 +4048,16 @@ eval_method(
        if (**arg != '(' && alias == NULL
                                    && (paren = vim_strchr(*arg, '(')) != NULL)
        {
-           typval_T ref;
-
            *arg = name;
            *paren = NUL;
-           ref.v_type = VAR_UNKNOWN;
-           if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
+           name = deref_function_name(arg, &tofree, evalarg, verbose);
+           if (name == NULL)
            {
                *arg = name + len;
                ret = FAIL;
            }
-           else if (*skipwhite(*arg) != NUL)
-           {
-               if (verbose)
-                   semsg(_(e_trailing_characters_str), *arg);
-               ret = FAIL;
-           }
-           else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
-           {
-               name = ref.vval.v_string;
-               ref.vval.v_string = NULL;
-               tofree = name;
-               len = STRLEN(name);
-           }
-           else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
-           {
-               if (ref.vval.v_partial->pt_argc > 0
-                                       || ref.vval.v_partial->pt_dict != NULL)
-               {
-                   emsg(_(e_cannot_use_partial_here));
-                   ret = FAIL;
-               }
-               else
-               {
-                   name = vim_strsave(partial_name(ref.vval.v_partial));
-                   tofree = name;
-                   if (name == NULL)
-                   {
-                       ret = FAIL;
-                       name = *arg;
-                   }
-                   else
-                       len = STRLEN(name);
-               }
-           }
            else
-           {
-               if (verbose)
-                   semsg(_(e_not_callable_type_str), name);
-               ret = FAIL;
-           }
-               clear_tv(&ref);
+               len = STRLEN(name);
            *paren = '(';
        }
 
index 36caf70068a05b78ed1089b3390f67adb7683396..1378261f7adf5a6d5143bc8103d1e437bf0c6370 100644 (file)
@@ -580,6 +580,29 @@ def Test_use_import_in_mapping()
   nunmap <F3>
 enddef
 
+def Test_use_import_in_completion()
+  var lines =<< trim END
+      vim9script
+      export def Complete(..._): list<string>
+        return ['abcd']
+      enddef
+  END
+  writefile(lines, 'Xscript.vim')
+
+  lines =<< trim END
+      vim9script
+      import './Xscript.vim'
+
+      command -nargs=1 -complete=customlist,Xscript.Complete Cmd echo 'ok'
+      feedkeys(":Cmd ab\<Tab>\<C-B>#\<CR>", 'xnt')
+      assert_equal('#Cmd abcd', @:)
+  END
+  CheckScriptSuccess(lines)
+
+  delcommand Cmd
+  delete('Xscript.vim')
+enddef
+
 def Test_export_fails()
   CheckScriptFailure(['export var some = 123'], 'E1042:')
   CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
index 0fb042e38725768675c1eb6688b523f525080e42..e6c9ab06c28acbe1118bbe1ce26669a55619c3d9 100644 (file)
@@ -3119,18 +3119,30 @@ free_all_functions(void)
 
 /*
  * Return TRUE if "name" looks like a builtin function name: starts with a
- * lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
+ * lower case letter, doesn't contain AUTOLOAD_CHAR or ':', no "." after the
+ * name.
  * "len" is the length of "name", or -1 for NUL terminated.
  */
     int
 builtin_function(char_u *name, int len)
 {
-    char_u *p;
+    int i;
 
     if (!ASCII_ISLOWER(name[0]) || name[1] == ':')
        return FALSE;
-    p = vim_strchr(name, AUTOLOAD_CHAR);
-    return p == NULL || (len > 0 && p > name + len);
+    for (i = 0; name[i] != NUL && (len < 0 || i < len); ++i)
+    {
+       if (name[i] == AUTOLOAD_CHAR)
+           return FALSE;
+       if (!eval_isnamec(name[i]))
+       {
+           // "name.something" is not a builtin function
+           if (name[i] == '.')
+               return FALSE;
+           break;
+       }
+    }
+    return TRUE;
 }
 
     int
index bee41fdedf352a2b61b4985d9fe8c0d36a763c7e..dbbf7d777f9c08fe6f729a9dc9688daae0ea765a 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4123,
 /**/
     4122,
 /**/