From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/eval/userfunc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 39bd63462c..00fb896797 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" -- cgit From bbd2f340a2895ed59785f952b2585e6590602cad Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 11 Jun 2024 10:25:32 +0200 Subject: refactor(memory): use builtin strcat() instead of STRCAT() The latter was mostly relevant with the past char_u madness. NOTE: STRCAT also functioned as a counterfeit "NOLINT" for clint apparently. But NOLINT-ing every usecase is just the same as disabling the check entirely. --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 00fb896797..122a1ac8ab 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -265,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name) if ((uint8_t)name[0] == K_SPECIAL) { fp->uf_name_exp = xmalloc(strlen(name) + 3); STRCPY(fp->uf_name_exp, ""); - STRCAT(fp->uf_name_exp, fp->uf_name + 3); + strcat(fp->uf_name_exp, fp->uf_name + 3); } } @@ -2062,7 +2062,7 @@ char *get_scriptlocal_funcname(char *funcname) const int off = *funcname == 's' ? 2 : 5; char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1); STRCPY(newname, sid_buf); - STRCAT(newname, funcname + off); + strcat(newname, funcname + off); return newname; } -- cgit From 545aafbeb80eb52c182ce139800489b392a12d0d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 10 Jul 2024 08:07:16 +0800 Subject: vim-patch:9.1.0547: No way to get the arity of a Vim function (#29638) Problem: No way to get the arity of a Vim function (Austin Ziegler) Solution: Enhance get() Vim script function to return the function argument info using get(func, "arity") (LemonBoy) fixes: vim/vim#15097 closes: vim/vim#15109 https://github.com/vim/vim/commit/48b7d05a4f88c4326bd5d7a73a523f2d953b3e51 Co-authored-by: LemonBoy --- src/nvim/eval/userfunc.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 122a1ac8ab..42391ecec7 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -642,6 +642,44 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char return fname; } +int get_func_arity(const char *name, int *required, int *optional, bool *varargs) +{ + int argcount = 0; + int min_argcount = 0; + + const EvalFuncDef *fdef = find_internal_func(name); + if (fdef != NULL) { + argcount = fdef->max_argc; + min_argcount = fdef->min_argc; + *varargs = false; + } else { + char fname_buf[FLEN_FIXED + 1]; + char *tofree = NULL; + int error = FCERR_NONE; + + // May need to translate 123_ to K_SNR. + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); + ufunc_T *ufunc = NULL; + if (error == FCERR_NONE) { + ufunc = find_func(fname); + } + xfree(tofree); + + if (ufunc == NULL) { + return FAIL; + } + + argcount = ufunc->uf_args.ga_len; + min_argcount = ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len; + *varargs = ufunc->uf_varargs; + } + + *required = min_argcount; + *optional = argcount - min_argcount; + + return OK; +} + /// Find a function by name, return pointer to it in ufuncs. /// /// @return NULL for unknown function. -- cgit From 48e4589eaded3213956aa9ddbcc0aa6971a974e5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 10:58:10 +0800 Subject: vim-patch:8.2.4416: Vim9: using a script-local function requires using "s:" (#29950) Problem: Vim9: using a script-local function requires using "s:" when setting 'completefunc'. Solution: Do not require "s:" in Vim9 script. (closes vim/vim#9796) https://github.com/vim/vim/commit/1fca5f3e86f08e696058fc7e86dfe41b415a78e6 vim-patch:8.2.4417: using NULL pointer Problem: Using NULL pointer. Solution: Set offset after checking for NULL pointer. https://github.com/vim/vim/commit/e89bfd212b21c227f026e467f882c62cdd6e642d Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 42391ecec7..ab8e67016f 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -2084,7 +2084,7 @@ char *get_scriptlocal_funcname(char *funcname) if (strncmp(funcname, "s:", 2) != 0 && strncmp(funcname, "", 5) != 0) { - // The function name is not a script-local function name + // The function name does not have a script-local prefix. return NULL; } -- cgit From f7fde0173af95925e7324b7d3c09776173dab8a7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Aug 2024 10:13:45 +0800 Subject: vim-patch:9.0.0632: calling a function from an "expr" option has overhead Problem: Calling a function from an "expr" option has too much overhead. Solution: Add call_simple_func() and use it for 'foldexpr' https://github.com/vim/vim/commit/87b4e5c5db9d1cfd6f2e79656e1a6cff3c69d15f Cherry-pick a call_func() change from patch 8.2.1343. Add expr-option-function docs to options.txt. Co-authored-by: Bram Moolenaar --- src/nvim/eval/userfunc.c | 69 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 10 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index ab8e67016f..f7d1e7e0f8 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1561,12 +1561,12 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv /// Give an error message for the result of a function. /// Nothing if "error" is FCERR_NONE. -static void user_func_error(int error, const char *name, funcexe_T *funcexe) +static void user_func_error(int error, const char *name, bool found_var) FUNC_ATTR_NONNULL_ARG(2) { switch (error) { case FCERR_UNKNOWN: - if (funcexe->fe_found_var) { + if (found_var) { semsg(_(e_not_callable_type_str), name); } else { emsg_funcname(e_unknown_function_str, name); @@ -1686,12 +1686,9 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t } if (error == FCERR_NONE && funcexe->fe_evaluate) { - char *rfname = fname; - - // Ignore "g:" before a function name. - if (fp == NULL && fname[0] == 'g' && fname[1] == ':') { - rfname = fname + 2; - } + // Skip "g:" before a function name. + bool is_global = fp == NULL && fname[0] == 'g' && fname[1] == ':'; + char *rfname = is_global ? fname + 2 : fname; rettv->v_type = VAR_NUMBER; // default rettv is number zero rettv->vval.v_number = 0; @@ -1765,7 +1762,7 @@ theend: // Report an error unless the argument evaluation or function call has been // cancelled due to an aborting error, an interrupt, or an exception. if (!aborting()) { - user_func_error(error, (name != NULL) ? name : funcname, funcexe); + user_func_error(error, (name != NULL) ? name : funcname, funcexe->fe_found_var); } // clear the copies made from the partial @@ -1779,6 +1776,58 @@ theend: return ret; } +/// Call a function without arguments, partial or dict. +/// This is like call_func() when the call is only "FuncName()". +/// To be used by "expr" options. +/// Returns NOTDONE when the function could not be found. +/// +/// @param funcname name of the function +/// @param len length of "name" or -1 to use strlen() +/// @param rettv return value goes here +int call_simple_func(const char *funcname, int len, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + int ret = FAIL; + + rettv->v_type = VAR_NUMBER; // default rettv is number zero + rettv->vval.v_number = 0; + + // Make a copy of the name, an option can be changed in the function. + char *name = xstrnsave(funcname, (size_t)len); + + int error = FCERR_NONE; + char *tofree = NULL; + char fname_buf[FLEN_FIXED + 1]; + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); + + // Skip "g:" before a function name. + bool is_global = fname[0] == 'g' && fname[1] == ':'; + char *rfname = is_global ? fname + 2 : fname; + + ufunc_T *fp = find_func(rfname); + if (fp == NULL) { + ret = NOTDONE; + } else if (fp != NULL && (fp->uf_flags & FC_DELETED)) { + error = FCERR_DELETED; + } else if (fp != NULL) { + typval_T argvars[1]; + argvars[0].v_type = VAR_UNKNOWN; + funcexe_T funcexe = FUNCEXE_INIT; + funcexe.fe_evaluate = true; + + error = call_user_func_check(fp, 0, argvars, rettv, &funcexe, NULL); + if (error == FCERR_NONE) { + ret = OK; + } + } + + user_func_error(error, name, false); + xfree(tofree); + xfree(name); + + return ret; +} + char *printable_func_name(ufunc_T *fp) { return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; @@ -3248,7 +3297,7 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial if (ufunc != NULL) { int error = check_user_func_argcount(ufunc, argcount); if (error != FCERR_UNKNOWN) { - user_func_error(error, name, NULL); + user_func_error(error, name, false); r = FAIL; } } -- cgit From 6d722f33098da447ac29496b71dd58f2ae337996 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 11:49:00 +0800 Subject: vim-patch:9.1.0649: Wrong comment for "len" argument of call_simple_func() Problem: Wrong comment for "len" argument of call_simple_func(). Solution: Remove the "or -1 to use strlen()". Also change its type to size_t to remove one cast. (zeertzjq) closes: vim/vim#15410 https://github.com/vim/vim/commit/c1ed788c1b41db9b5f1ef548dc877f771f535bbe --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f7d1e7e0f8..3690ab5d7b 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1782,9 +1782,9 @@ theend: /// Returns NOTDONE when the function could not be found. /// /// @param funcname name of the function -/// @param len length of "name" or -1 to use strlen() +/// @param len length of "name" /// @param rettv return value goes here -int call_simple_func(const char *funcname, int len, typval_T *rettv) +int call_simple_func(const char *funcname, size_t len, typval_T *rettv) FUNC_ATTR_NONNULL_ALL { int ret = FAIL; @@ -1793,7 +1793,7 @@ int call_simple_func(const char *funcname, int len, typval_T *rettv) rettv->vval.v_number = 0; // Make a copy of the name, an option can be changed in the function. - char *name = xstrnsave(funcname, (size_t)len); + char *name = xstrnsave(funcname, len); int error = FCERR_NONE; char *tofree = NULL; -- cgit From 99bb0a10d3400ee8b9b2773d51a957dacbf52b33 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 12:16:04 +0800 Subject: refactor(eval): treat v:lua call as simple function --- src/nvim/eval/userfunc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 3690ab5d7b..f7ce5334f0 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1776,6 +1776,15 @@ theend: return ret; } +int call_simple_luafunc(const char *funcname, size_t len, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL +{ + typval_T argvars[1]; + argvars[0].v_type = VAR_UNKNOWN; + nlua_typval_call(funcname, len, argvars, 0, rettv); + return OK; +} + /// Call a function without arguments, partial or dict. /// This is like call_func() when the call is only "FuncName()". /// To be used by "expr" options. -- cgit From 2a3561819e0e80150986779cee87659b7c92d0c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 2 Aug 2024 16:00:27 +0800 Subject: fix(eval): handle wrong v:lua in expr option properly (#29953) --- src/nvim/eval/userfunc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index f7ce5334f0..d2bae72531 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1779,6 +1779,9 @@ theend: int call_simple_luafunc(const char *funcname, size_t len, typval_T *rettv) FUNC_ATTR_NONNULL_ALL { + rettv->v_type = VAR_NUMBER; // default rettv is number zero + rettv->vval.v_number = 0; + typval_T argvars[1]; argvars[0].v_type = VAR_UNKNOWN; nlua_typval_call(funcname, len, argvars, 0, rettv); -- cgit From 737f58e23230ea14f1648ac1fc7f442ea0f8563c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 20 Sep 2024 07:34:50 +0200 Subject: refactor(api)!: rename Dictionary => Dict In the api_info() output: :new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val') ... {'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1} The `ArrayOf(Integer, 2)` return type didn't break clients when we added it, which is evidence that clients don't use the `return_type` field, thus renaming Dictionary => Dict in api_info() is not (in practice) a breaking change. --- src/nvim/eval/userfunc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/eval/userfunc.c') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index d2bae72531..4f1098632c 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -955,7 +955,7 @@ void remove_funccal(void) /// @param[out] rettv Return value. /// @param[in] firstline First line of range. /// @param[in] lastline Last line of range. -/// @param selfdict Dictionary for "self" for dictionary functions. +/// @param selfdict Dict for "self" for dictionary functions. void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict) FUNC_ATTR_NONNULL_ARG(1, 3, 4) @@ -1922,7 +1922,7 @@ static int list_func_head(ufunc_T *fp, bool indent, bool force) } /// Get a function name, translating "" and "". -/// Also handles a Funcref in a List or Dictionary. +/// Also handles a Funcref in a List or Dict. /// flags: /// TFN_INT: internal function name OK /// TFN_QUIET: be quiet @@ -3242,7 +3242,7 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, break; } - // Handle a function returning a Funcref, Dictionary or List. + // Handle a function returning a Funcref, Dict or List. if (handle_subscript((const char **)arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) { failed = true; break; -- cgit