vim-patch:3920bb4: runtime(doc): document how to minimize fold computation costs

closes: vim/vim#16224

3920bb4356

Co-authored-by: Konfekt <Konfekt@users.noreply.github.com>
This commit is contained in:
zeertzjq 2024-12-17 08:22:19 +08:00
parent 59f38ef3c4
commit 7d082d4816

View File

@ -82,9 +82,11 @@ The most efficient is to call a function without arguments: >
The function must use v:lnum. See |expr-option-function|. The function must use v:lnum. See |expr-option-function|.
These are the conditions with which the expression is evaluated: These are the conditions with which the expression is evaluated:
- The current buffer and window are set for the line. - The current buffer and window are set for the line.
- The variable "v:lnum" is set to the line number. - The variable "v:lnum" is set to the line number.
- The result is used for the fold level in this way:
The result of foldexpr then determines the fold level as follows:
value meaning ~ value meaning ~
0 the line is not in a fold 0 the line is not in a fold
1, 2, .. the line is in a fold with this level 1, 2, .. the line is in a fold with this level
@ -99,6 +101,8 @@ These are the conditions with which the expression is evaluated:
"<1", "<2", .. a fold with this level ends at this line "<1", "<2", .. a fold with this level ends at this line
">1", ">2", .. a fold with this level starts at this line ">1", ">2", .. a fold with this level starts at this line
The result values "=", "s" and "a" are more expensive, please see |fold-expr-slow|.
It is not required to mark the start (end) of a fold with ">1" ("<1"), a fold It is not required to mark the start (end) of a fold with ">1" ("<1"), a fold
will also start (end) when the fold level is higher (lower) than the fold will also start (end) when the fold level is higher (lower) than the fold
level of the previous line. level of the previous line.
@ -112,12 +116,6 @@ recognized, there is no error message and the fold level will be zero.
For debugging the 'debug' option can be set to "msg", the error messages will For debugging the 'debug' option can be set to "msg", the error messages will
be visible then. be visible then.
Note: Since the expression has to be evaluated for every line, this fold
method can be very slow!
Try to avoid the "=", "a" and "s" return values, since Vim often has to search
backwards for a line for which the fold level is defined. This can be slow.
If the 'foldexpr' expression starts with s: or |<SID>|, then it is replaced If the 'foldexpr' expression starts with s: or |<SID>|, then it is replaced
with the script ID (|local-function|). Examples: > with the script ID (|local-function|). Examples: >
set foldexpr=s:MyFoldExpr() set foldexpr=s:MyFoldExpr()
@ -143,6 +141,35 @@ end in that line.
It may happen that folds are not updated properly. You can use |zx| or |zX| It may happen that folds are not updated properly. You can use |zx| or |zX|
to force updating folds. to force updating folds.
Minimizing Computational Cost *fold-expr-slow*
Due to its computational cost, this fold method can make Vim unresponsive,
especially when the fold level of all lines have to be initially computed.
Afterwards, after each change, Vim restricts the computation of foldlevels
to those lines whose fold level was affected by it (and reuses the known
foldlevels of all the others).
The fold expression should therefore strive to minimize the number of dependent
lines needed for the computation of a given line: For example, try to avoid the
"=", "a" and "s" return values, because these will require the evaluation of the
fold levels on previous lines until an independent fold level is found.
If this proves difficult, the next best thing could be to cache all fold levels
in a buffer-local variable (b:foldlevels) that is only updated on |b:changedtick|:
>vim
func MyFoldFunc()
if b:lasttick == b:changedtick
return b:foldlevels[v:lnum - 1]
endif
let b:lasttick = b:changedtick
let b:foldlevels = []
" compute foldlevels ...
return b:foldlevels[v:lnum - 1]
enddef
set foldexpr=s:MyFoldFunc()
<
In above example further speedup was gained by using a function without
arguments (that must still use v:lnum). See |expr-option-function|.
SYNTAX *fold-syntax* SYNTAX *fold-syntax*