To: vim_dev@googlegroups.com Subject: Patch 8.2.4123 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4123 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) Files: src/userfunc.c, src/eval.c, src/testdir/test_vim9_import.vim *** ../vim-8.2.4122/src/userfunc.c 2022-01-16 18:06:17.723808427 +0000 --- src/userfunc.c 2022-01-17 19:23:22.299766567 +0000 *************** *** 3119,3136 **** /* * Return TRUE if "name" looks like a builtin function name: starts with a ! * lower case letter and doesn't contain AUTOLOAD_CHAR or ':'. * "len" is the length of "name", or -1 for NUL terminated. */ int builtin_function(char_u *name, int len) { ! char_u *p; if (!ASCII_ISLOWER(name[0]) || name[1] == ':') return FALSE; ! p = vim_strchr(name, AUTOLOAD_CHAR); ! return p == NULL || (len > 0 && p > name + len); } int --- 3119,3148 ---- /* * Return TRUE if "name" looks like a builtin function name: starts with a ! * 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) { ! int i; if (!ASCII_ISLOWER(name[0]) || name[1] == ':') return FALSE; ! 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 *** ../vim-8.2.4122/src/eval.c 2022-01-16 21:18:49.419329705 +0000 --- src/eval.c 2022-01-17 19:54:45.130914748 +0000 *************** *** 626,631 **** --- 626,688 ---- } /* + * "*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] * should have type VAR_UNKNOWN. *************** *** 640,654 **** { int ret; funcexe_T funcexe; 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); if (ret == FAIL) clear_tv(rettv); return ret; } --- 697,723 ---- { 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; ! ! // 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,4035 **** 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) { *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); *paren = '('; } --- 4048,4063 ---- if (**arg != '(' && alias == NULL && (paren = vim_strchr(*arg, '(')) != NULL) { *arg = name; *paren = NUL; ! name = deref_function_name(arg, &tofree, evalarg, verbose); ! if (name == NULL) { *arg = name + len; ret = FAIL; } else ! len = STRLEN(name); *paren = '('; } *** ../vim-8.2.4122/src/testdir/test_vim9_import.vim 2022-01-16 21:18:49.419329705 +0000 --- src/testdir/test_vim9_import.vim 2022-01-17 20:03:56.425467411 +0000 *************** *** 580,585 **** --- 580,608 ---- nunmap enddef + def Test_use_import_in_completion() + var lines =<< trim END + vim9script + export def Complete(..._): list + 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\\#\", '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:') *** ../vim-8.2.4122/src/version.c 2022-01-17 19:06:52.458100460 +0000 --- src/version.c 2022-01-17 19:24:13.267788083 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4123, /**/ -- WOMAN: I didn't know we had a king. I thought we were an autonomous collective. DENNIS: You're fooling yourself. We're living in a dictatorship. A self-perpetuating autocracy in which the working classes-- WOMAN: Oh there you go, bringing class into it again. DENNIS: That's what it's all about if only people would-- The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///