Skip to content

Commit

Permalink
Merge pull request #1877 from h-east/update-fold
Browse files Browse the repository at this point in the history
Update fold.{txt,jax}
  • Loading branch information
h-east authored Dec 29, 2024
2 parents 13fbaa9 + 8868f07 commit 9054565
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 26 deletions.
54 changes: 41 additions & 13 deletions doc/fold.jax
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*fold.txt* For Vim バージョン 9.1. Last change: 2023 Mar 24
*fold.txt* For Vim バージョン 9.1. Last change: 2024 Dec 17


VIMリファレンスマニュアル by Bram Moolenaar
Expand Down Expand Up @@ -77,18 +77,20 @@
同じ事(「段落」を折り畳みに)をする別の表現: >
:set foldexpr=getline(v:lnum-1)=~'^\\s*$'&&getline(v:lnum)=~'\\S'?'>1':1
バックスラッシュ(日本では \ 記号)が ":set" の流儀で、通常とは異なるキャラクタ
(空白文字、バックスラッシュ、ダブルクォート、その他、詳細は|option-backslash|
参照)をエスケープしていることに注意。
Note バックスラッシュ (日本では \ 記号) が ":set" の流儀で、通常とは異なるキャ
ラクタ (空白文字、バックスラッシュ、ダブルクォート、その他、詳細は
|option-backslash| 参照) をエスケープしていることに注意。

最も効果的なのはコンパイル済み関数を引数なしで呼ぶ: >
:set foldexpr=MyFoldLevel()
関数は v:lnum を使用しなくてはいけない。|expr-option-function| を参照。

式が評価される際の前提条件は以下の通り:

- その行について現在のバッファとウィンドウが常に存在している。
- 変数 "v:lnum" には評価対象となる行番号が設定されている。
- 式の結果(戻り値)は以下の形式で折り畳みレベルを示す:

foldexpr の結果によって、以下のように折り畳みレベルが決定される:
値 意味 ~
0 対象行は折り畳みに含まれない
1, 2, .. 対象行はこのレベルの折り畳みに含まれる
Expand All @@ -102,6 +104,8 @@
"<1", "<2", .. 指定したレベルの折り畳みを対象行で終了する
">1", ">2", .. 指定したレベルの折り畳みを対象行から開始する

結果の値 "="、"s" および "a" はより高価である。|fold-expr-slow| を参照。

折り畳みは直前の行の折り畳みレベルより高い(低い)行から開始(終了)されるので、折
り畳みの開始 (終了)マーク ">1" ("<1") は明示的に指定する必要は無い。

Expand All @@ -113,13 +117,6 @@
折り畳みレベルは0に設定される。'debug' オプションに "msg" を設定すれば、エラー
メッセージが表示されるようになるので、デバッグに利用できる。

NOTE: 各行について式評価が実行されるので、この折り畳み方式は非常に動作が遅くな
る可能性がある!

"=", "a", そして "s" は極力避けるようにする。なぜならVimはそれらが使われると、
折り畳みレベルが定義された行が見つかるまで戻って、幾度も検索を行わなければなら
ないからだ。これは動作が遅くなることがある。

'foldexpr' の式が s: か |<SID>| で始まる場合、スクリプトID(|local-function|)
に置き換えられる。例: >
set foldexpr=s:MyFoldExpr()
Expand All @@ -144,6 +141,37 @@ NOTE: 各行について式評価が実行されるので、この折り畳み
折り畳みが適切に更新されない場合がある。その場合は |zx||zX| を使って強制的
に更新すること。

☆計算コストの最小化 *fold-expr-slow*

この折り畳み方式は計算コストが高いため、特にすべての行の折り畳みレベルを最初に
計算する必要がある場合、Vim が応答しなくなる可能性がある。
その後、各変更の後に Vim は折り畳みレベルの計算を折り畳みレベルが影響を受けた
行に制限する (他のすべての行の既知の折り畳みレベルを再利用する)。

したがって、折り畳み式は特定の行の計算に必要な依存行の数を最小限に抑えるように
努める必要がある。例えば、独立した折り畳みレベルが見つかるまで前の行の折り畳み
レベルの評価が必要になるため、"="、"a" および "s" の戻り値を避けるようにするこ
と。

これが難しい場合は、次善策として |b:changedtick| でのみ更新されるバッファロー
カル変数 (b:foldlevels) にすべての折り畳みレベルをキャッシュすることが考えられ
る:
>vim
vim9script
def MyFoldFunc(): number
if b:lasttick == b:changedtick
return b:foldlevels[v:lnum - 1]
endif
b:lasttick = b:changedtick
b:foldlevels = []
# compute foldlevels ...
return b:foldlevels[v:lnum - 1]
enddef
set foldexpr=s:MyFoldFunc()
<
上記の例では、プリコンパイルされた引数なしの Vim9 script 関数を使用することで、
さらに高速化された (それでも v:lnum を使用する必要がある)。
|expr-option-function| を参照。

☆構文 *fold-syntax*

Expand Down Expand Up @@ -446,7 +474,7 @@ zk カーソルより上方の折り畳みへ移動する。閉じられた折

折り畳みに対してコマンドを実行する ~

:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
閉じた折り畳みの中以外の全ての行に対して{cmd}を実行する。
[range]が与えられた時は、その範囲だけが対象となる。
コマンドが各行に対して実行される時にはカーソルはその対象となる
Expand Down
58 changes: 45 additions & 13 deletions en/fold.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*fold.txt* For Vim version 9.1. Last change: 2023 Mar 24
*fold.txt* For Vim version 9.1. Last change: 2024 Dec 17


VIM REFERENCE MANUAL by Bram Moolenaar
Expand Down Expand Up @@ -87,9 +87,11 @@ The most efficient is to call a compiled function without arguments: >
The function must use v:lnum. See |expr-option-function|.

These are the conditions with which the expression is evaluated:

- The current buffer and window are set for the line.
- 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 ~
0 the line is not in a fold
1, 2, .. the line is in a fold with this level
Expand All @@ -104,6 +106,9 @@ 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 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
will also start (end) when the fold level is higher (lower) than the fold
level of the previous line.
Expand All @@ -117,14 +122,8 @@ 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
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
with the script ID (|local-function|). Examples: >
with the script ID (|local-function|). Examples: >
set foldexpr=s:MyFoldExpr()
set foldexpr=<SID>SomeFoldExpr()
<
Expand All @@ -148,6 +147,39 @@ end in that line.
It may happen that folds are not updated properly. You can use |zx| or |zX|
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
vim9script
def MyFoldFunc(): number
if b:lasttick == b:changedtick
return b:foldlevels[v:lnum - 1]
endif
b:lasttick = b:changedtick
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 precompiled Vim9 script
function without arguments (that must still use v:lnum). See
|expr-option-function|.

SYNTAX *fold-syntax*

Expand Down Expand Up @@ -384,8 +416,8 @@ zX Undo manually opened and closed folds: re-apply 'foldlevel'.
Also forces recomputing folds, like |zx|.

*zm*
zm Fold more: Subtract |v:count1| from 'foldlevel'. If 'foldlevel' was
already zero nothing happens.
zm Fold more: Subtract |v:count1| from 'foldlevel'. If
'foldlevel' was already zero nothing happens.
'foldenable' will be set.

*zM*
Expand Down Expand Up @@ -449,7 +481,7 @@ zk Move upwards to the end of the previous fold. A closed fold

EXECUTING COMMANDS ON FOLDS ~

:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
Execute {cmd} on all lines that are not in a closed fold.
When [range] is given, only these lines are used.
Each time {cmd} is executed the cursor is positioned on the
Expand Down Expand Up @@ -539,7 +571,7 @@ When there is room after the text, it is filled with the character specified
by 'fillchars'.

If the 'foldtext' 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 foldtext=s:MyFoldText()
set foldtext=<SID>SomeFoldText()
<
Expand Down

0 comments on commit 9054565

Please sign in to comment.