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'
diff --git a/src/userfunc.c b/src/userfunc.c
index 92b5203..14d1c72 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3447,12 +3447,12 @@
* Nothing if "error" is FCERR_NONE.
*/
void
-user_func_error(int error, char_u *name, funcexe_T *funcexe)
+user_func_error(int error, char_u *name, int found_var)
{
switch (error)
{
case FCERR_UNKNOWN:
- if (funcexe->fe_found_var)
+ if (found_var)
emsg_funcname(e_not_callable_type_str, name);
else
emsg_funcname(e_unknown_function_str, name);
@@ -3702,7 +3702,8 @@
* 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
while (argv_clear > 0)
@@ -3714,6 +3715,77 @@
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.
+ */
+ int
+call_simple_func(
+ char_u *funcname, // name of the function
+ int len, // length of "name" or -1 to use strlen()
+ typval_T *rettv) // return value goes here
+{
+ int ret = FAIL;
+ int error = FCERR_NONE;
+ char_u fname_buf[FLEN_FIXED + 1];
+ char_u *tofree = NULL;
+ char_u *name;
+ char_u *fname;
+ char_u *rfname;
+ int is_global = FALSE;
+ ufunc_T *fp;
+
+ 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.
+ name = vim_strnsave(funcname, len);
+ if (name == NULL)
+ return ret;
+
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+
+ // Skip "g:" before a function name.
+ if (fname[0] == 'g' && fname[1] == ':')
+ {
+ is_global = TRUE;
+ rfname = fname + 2;
+ }
+ else
+ rfname = fname;
+ fp = find_func(rfname, is_global);
+ if (fp != NULL && !is_global && in_vim9script()
+ && func_requires_g_prefix(fp))
+ // In Vim9 script g: is required to find a global non-autoload
+ // function.
+ fp = NULL;
+ 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];
+ funcexe_T funcexe;
+
+ argvars[0].v_type = VAR_UNKNOWN;
+ CLEAR_FIELD(funcexe);
+ 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);
+ vim_free(tofree);
+ vim_free(name);
+
+ return ret;
+}
+
char_u *
printable_func_name(ufunc_T *fp)
{
@@ -5676,7 +5748,7 @@
if (error != FCERR_UNKNOWN)
{
- user_func_error(error, name, NULL);
+ user_func_error(error, name, FALSE);
r = FAIL;
}
}