aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-08-01 10:13:45 +0800
committerzeertzjq <zeertzjq@outlook.com>2024-08-02 11:56:51 +0800
commitf7fde0173af95925e7324b7d3c09776173dab8a7 (patch)
treec7a54472837afe4baf13e66855265cc8a003805a /src/nvim/eval.c
parent48e4589eaded3213956aa9ddbcc0aa6971a974e5 (diff)
downloadrneovim-f7fde0173af95925e7324b7d3c09776173dab8a7.tar.gz
rneovim-f7fde0173af95925e7324b7d3c09776173dab8a7.tar.bz2
rneovim-f7fde0173af95925e7324b7d3c09776173dab8a7.zip
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 <Bram@vim.org>
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index b8c3df5688..c8451b7a28 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1349,7 +1349,7 @@ int eval_foldexpr(win_T *wp, int *cp)
const sctx_T saved_sctx = current_sctx;
const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
- char *arg = wp->w_p_fde;
+ char *arg = skipwhite(wp->w_p_fde);
current_sctx = wp->w_p_script_ctx[WV_FDE].script_ctx;
emsg_off++;
@@ -1360,8 +1360,23 @@ int eval_foldexpr(win_T *wp, int *cp)
*cp = NUL;
typval_T tv;
+ int r = NOTDONE;
+
+ // If the expression is "FuncName()" then we can skip a lot of overhead.
+ char *parens = strstr(arg, "()");
+ if (parens != NULL && *skipwhite(parens + 2) == NUL) {
+ char *p = strncmp(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg;
+ if (to_name_end(p, true) == parens) {
+ r = call_simple_func(arg, (int)(parens - arg), &tv);
+ }
+ }
+
+ if (r == NOTDONE) {
+ r = eval0(arg, &tv, NULL, &EVALARG_EVALUATE);
+ }
+
varnumber_T retval;
- if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
+ if (r == FAIL) {
retval = 0;
} else {
// If the result is a number, just return the number.
@@ -1428,6 +1443,31 @@ Object eval_foldtext(win_T *wp)
return retval;
}
+/// Find the end of a variable or function name. Unlike find_name_end() this
+/// does not recognize magic braces.
+/// When "use_namespace" is true recognize "b:", "s:", etc.
+/// Return a pointer to just after the name. Equal to "arg" if there is no
+/// valid name.
+static char *to_name_end(char *arg, bool use_namespace)
+{
+ // Quick check for valid starting character.
+ if (!eval_isnamec1(*arg)) {
+ return arg;
+ }
+
+ char *p;
+ for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p)) {
+ // Include a namespace such as "s:var" and "v:var". But "n:" is not
+ // and can be used in slice "[n:]".
+ if (*p == ':' && (p != arg + 1
+ || !use_namespace
+ || vim_strchr("bgstvw", *arg) == NULL)) {
+ break;
+ }
+ }
+ return p;
+}
+
/// Get an Dict lval variable that can be assigned a value to: "name",
/// "name[expr]", "name[expr][expr]", "name.key", "name.key[expr]" etc.
/// "name" points to the start of the name.