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