折叠

Nvim 的 :help 页面,生成源代码 使用 tree-sitter-vimdoc 解析器。


折叠 折叠 折叠
您可以在用户手册第 28 章找到有关折叠的介绍。 usr_28.txt

1. 折叠方法 折叠方法

折叠方法可以使用 'foldmethod' 选项设置。
'foldmethod' 设置为除 "manual" 之外的值时,所有折叠都会被删除并创建新的折叠。切换到 "manual" 方法不会删除现有的折叠。这可以用来先自动定义折叠,然后手动更改它们。
有六种方法可以选择折叠:manual 手动定义折叠 indent 更多缩进意味着更高的折叠级别 expr 指定表达式来定义折叠 syntax 由语法高亮定义折叠 diff 用于未更改文本的折叠 marker 由文本中的标记定义的折叠

手动 手动

使用命令手动定义折叠区域。这也可以由解析文本以查找折叠的脚本使用。
折叠的级别仅由其嵌套定义。要增加一系列行的折叠级别,请在其内定义一个具有相同行的折叠。
当您放弃文件时,手动折叠会丢失。要保存折叠,请使用 :mkview 命令。视图可以使用 :loadview 稍后恢复。

缩进 缩进

折叠由行的缩进自动定义。
折叠级别由行的缩进除以 'shiftwidth'(向下取整)计算得出。具有相同或更高折叠级别的行序列构成一个折叠,其中具有更高级别的行构成一个嵌套折叠。
折叠的嵌套使用 'foldnestmax' 限制。
某些行会被忽略,并获得其上方或下方行的折叠级别,取较低者。这些是空行或空白行以及以 'foldignore' 中的字符开头的行。在检查 'foldignore' 中的字符之前,会跳过空白。对于 C,使用 "#" 忽略预处理器行。
如果您想以其他方式忽略行,请使用 "expr" 方法。 indent() 函数可以在 'foldexpr' 中使用来获取行的缩进。

表达式 表达式

折叠由其折叠级别自动定义,类似于 "indent" 方法。 'foldexpr' 选项的值被评估以获取行的折叠级别。示例:这将为所有以制表符开头的连续行创建一个折叠
:set foldexpr=getline(v:lnum)[0]==\"\\t\"
这将使用空白行分隔的段落创建一个折叠
:set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
这做的是同样的事情
:set foldexpr=getline(v:lnum-1)=~'^\\s*$'&&getline(v:lnum)=~'\\S'?'>1':1
请注意,反斜杠必须用于转义 ":set" 以不同方式处理的字符(空格、反斜杠、双引号等,请参阅 option-backslash)。
最有效的方法是调用没有参数的函数
:set foldexpr=MyFoldLevel()
该函数必须使用 v:lnum。请参阅 expr-option-function
这些是评估表达式的条件
当前缓冲区和窗口已针对该行设置。
变量 "v:lnum" 被设置为行号。
结果以这种方式用于折叠级别:value 含义 ~ 0 该行不在折叠中 1、2、.. 该行位于具有此级别的折叠中 -1 折叠级别未定义,使用此行之前或之后的一行的折叠级别,取较低者。 "=" 使用前一行的折叠级别 "a1"、"a2"、.. 在前一行的折叠级别上加一、二、..,将结果用于当前行 "s1"、"s2"、.. 从前一行的折叠级别上减去一、二、..,将结果用于下一行 "<1"、"<2"、.. 具有此级别的折叠在此行结束 ">1"、">2"、.. 具有此级别的折叠在此行开始
不需要使用 ">1" ("<1") 来标记折叠的开始(结束),当折叠级别高于(低于)前一行的折叠级别时,折叠也会开始(结束)。
表达式必须没有副作用。缓冲区中的文本、光标位置、搜索模式、选项等。不得更改。如果您小心,您可以更改和恢复它们。
如果表达式中存在一些错误,或者结果值无法识别,则不会出现错误消息,折叠级别将为零。为了调试,可以将 'debug' 选项设置为 "msg",这样错误消息就会可见。
注意:由于必须对每一行评估表达式,因此这种折叠方法可能非常慢!
尝试避免使用 "=", "a" 和 "s" 返回值,因为 Vim 通常必须向后搜索一行以获取定义了折叠级别的行。这可能很慢。
如果 'foldexpr' 表达式以 s: 或 <SID> 开头,则它将被替换为脚本 ID (local-function)。示例
set foldexpr=s:MyFoldExpr()
set foldexpr=<SID>SomeFoldExpr()
使用 "a1" 和 "s1" 的示例:对于多行 C 注释,包含 "/*" 的行将返回 "a1" 以开始折叠,而包含 "*/" 的行将返回 "s1" 以在该行之后结束折叠
if match(thisline, '/\*') >= 0
  return 'a1'
elseif match(thisline, '\*/') >= 0
  return 's1'
else
  return '='
endif
但是,这将不适用于单行注释、字符串等。
foldlevel() 可以用于计算相对于先前折叠级别的折叠级别。但请注意,如果级别尚不清楚,foldlevel() 可能会返回 -1。它返回行开头的级别,而折叠可能在该行结束。
折叠可能无法正确更新。您可以使用 zxzX 强制更新折叠。

语法 语法

折叠由具有 "fold" 参数的语法项定义。 :syn-fold
折叠级别由嵌套折叠定义。折叠的嵌套使用 'foldnestmax' 限制。
请务必指定正确的语法同步。如果这没有正确完成,则折叠可能与显示的高亮显示不同。这在使用匹配多行的模式时尤其重要。如有疑问,请尝试使用暴力同步
:syn sync fromstart

差异 差异

对于不属于更改部分或靠近更改部分的文本,折叠将自动定义。
此方法仅在当前窗口设置了 'diff' 选项并且正在显示更改时才能正常工作。否则,整个缓冲区将是一个大的折叠。
'diffopt' 选项可用于指定上下文。即,折叠和未包含在折叠中的更改之间的行数。例如,要使用 8 行的上下文
:set diffopt=filler,context:8
默认上下文为六行。
'scrollbind' 也设置时,Vim 会尝试在其他差异窗口中保持相同的折叠打开,以便显示相同的文本。

标记 标记

文本中的标记指示折叠的开始和结束位置。这使您可以精确地指定折叠。这将允许您删除和放置折叠,而不会冒包含错误行的风险。 'foldtext' 选项通常设置为使标记之前的文本显示在折叠行中。这使您可以为折叠命名。
标记可以包含级别,也可以使用匹配对。包含级别更容易,您不必添加结束标记,并避免非匹配标记对的问题。示例
/* global variables {{{1 */
int varA, varB;
/* functions {{{1 */
/* funcA() {{{2 */
void funcA() {}
/* funcB() {{{2 */
void funcB() {}
{{{ }}} 折叠从 "{{{" 标记开始。后面的数字指定折叠级别。发生的事情取决于当前折叠级别与标记给定的级别之间的差异:1. 如果遇到具有相同折叠级别的标记,则先前折叠结束,另一个具有相同级别的折叠开始。 2. 如果找到具有更高折叠级别的标记,则开始嵌套折叠。 3. 如果找到具有更低折叠级别的标记,则所有折叠(包括此级别)都将结束,并开始一个具有指定级别的折叠。
该数字表示折叠级别。不能使用零(级别为零的标记将被忽略)。您可以使用 "}}}" 和一个数字来指示结束的折叠的级别。下一行的折叠级别将比指示的级别少一。请注意,Vim 不会回溯到匹配标记的级别(这将花费太多时间)。示例
{{{1
fold level here is 1
{{{3
fold level here is 3
}}}3
fold level here is 2
您还可以使用 "{{{" 和 "}}}" 标记的匹配对来定义折叠。每个 "{{{" 将折叠级别增加一,每个 "}}}" 将折叠级别减少一。请务必使标记匹配!示例
{{{
fold level here is 1
{{{
fold level here is 2
}}}
fold level here is 1
您可以混合使用带编号和不带编号的标记。一种有用的方法是使用带编号的标记进行大折叠,并在函数中局部使用不带编号的标记。例如,使用级别 1 折叠来进行文件的各个部分,例如 "结构定义"、"局部变量" 和 "函数"。使用级别 2 标记来进行每个定义和函数,使用不带编号的标记在函数内部。当您在函数中进行更改以拆分折叠时,您不必重新编号标记。
标记可以使用 'foldmarker' 选项设置。建议将其保留为默认值 "{{{,}}}", 这样就可以在 Vim 用户之间交换文件。仅当文件需要时才更改它(例如,它包含来自其他折叠编辑器的标记,或者默认标记对文件的语言造成问题)。
fold-create-marker
"zf" 可用于创建由标记定义的折叠。Vim 将为您插入标记。Vim 将附加开始和结束标记,如 'foldmarker' 指定的那样。标记将附加到行的末尾。 'commentstring' 如果不为空,则使用它。当以下情况发生时,这将无法正常工作
该行已包含具有级别编号的标记。然后,Vim 将不知道该怎么做。
附近的折叠在其标记中使用级别编号,这会妨碍操作。
该行位于注释内部,'commentstring' 不为空,嵌套注释不起作用。例如在 C 中,在注释内部添加 /* {{{ */ 将截断现有注释。将标记放在注释之前或之后,或手动添加标记。通常,当您已经使用级别编号创建了标记时,不建议让 Vim 创建标记。
fold-delete-marker
"zd" 可用于删除由标记定义的折叠。Vim 将为您删除标记。Vim 将根据 'foldmarker' 中指定的设置,在折叠的开头和结尾处搜索开始和结束标记。当标记周围的文本与 'commentstring' 匹配时,该文本也会被删除。当以下情况发生时,此方法无法正常工作
一行包含多个标记,其中一个标记指定了一个级别。仅删除第一个标记,不检查这是否会达到删除折叠的预期效果。
标记包含一个级别编号,用于同时开始或结束多个折叠。

2. 折叠命令 fold-commands E490

所有折叠命令都以 "z" 开头。提示:"z" 看起来像一张折叠的纸,如果你从侧面看它。
创建和删除折叠
zf E350 zf{motion} 或 {Visual}zf 运算符用于创建折叠。这仅在 'foldmethod' 为 "manual" 或 "marker" 时有效。对于 "manual" 方法,新折叠将被关闭。'foldenable' 将被设置。另请参见 fold-create-marker
zF
zF 为 [count] 行创建折叠。与 "zf" 相似。
:{range}fo[ld] :fold :fo{range} 中的线条创建折叠。与 "zf" 相似。
zd E351 zd 删除光标处的单个折叠。当光标位于折叠行上时,将删除该折叠。嵌套的折叠将上移一级。在 Visual 模式下,所选区域中所有折叠(部分)的一级将被删除。注意:这很容易删除超出预期的折叠,并且手动折叠没有撤消功能。这仅在 'foldmethod' 为 "manual" 或 "marker" 时有效。另请参见 fold-delete-marker
zD
zD 递归删除光标处的折叠。在 Visual 模式下,将删除所选区域中所有折叠(部分),以及其中包含的所有嵌套折叠。这仅在 'foldmethod' 为 "manual" 或 "marker" 时有效。另请参见 fold-delete-marker
zE E352 zE 删除窗口中的所有折叠。这仅在 'foldmethod' 为 "manual" 或 "marker" 时有效。另请参见 fold-delete-marker
打开和关闭折叠
小于 'foldminlines' 的折叠将始终像打开一样显示。因此,下面的命令在小折叠上的行为可能有所不同。
zo
zo 打开光标下的单个折叠。当给出计数时,将打开该计数级别的折叠。在 Visual 模式下,将为所选区域中的所有行打开一级折叠。
zO
zO 递归打开光标下的所有折叠。不包含光标行的折叠保持不变。在 Visual 模式下,它会打开所选区域中的所有折叠,包括仅部分选中的折叠。
zc
zc 关闭光标下的单个折叠。当给出计数时,将关闭该计数级别的折叠。在 Visual 模式下,将为所选区域中的所有行关闭一级折叠。'foldenable' 将被设置。
zC
zC 递归关闭光标下的所有折叠。不包含光标行的折叠保持不变。在 Visual 模式下,它会关闭所选区域中的所有折叠,包括仅部分选中的折叠。'foldenable' 将被设置。
za
za 摘要:切换光标下的折叠。当位于关闭的折叠上时:打开它。当折叠嵌套时,您可能需要多次使用 "za"。当给出计数时,将打开该计数个关闭的折叠。当位于打开的折叠上时:关闭它并设置 'foldenable'。这将仅关闭一级,因为再次使用 "za" 将打开折叠。当给出计数时,将关闭该计数个折叠(与重复 "za" 该计数次不同)。
zA
zA 当位于关闭的折叠上时:递归打开它。当位于打开的折叠上时:递归关闭它并设置 'foldenable'
zv
zv 查看光标行:仅打开足够的折叠,使包含光标的行不被折叠。
zx
zx 更新折叠:撤消手动打开和关闭的折叠:重新应用 'foldlevel',然后执行 "zv":查看光标行。还会强制重新计算折叠。当使用 'foldexpr' 并且缓冲区以导致折叠未正确更新的方式更改时,这很有用。
zX
zX 撤消手动打开和关闭的折叠:重新应用 'foldlevel'。还会强制重新计算折叠,就像 zx 一样。
zm
zm 折叠更多:从 'foldlevel' 中减去 v:count1。如果 'foldlevel' 已经是零,则不会发生任何事情。'foldenable' 将被设置。
zM
zM 关闭所有折叠:将 'foldlevel' 设置为 0。'foldenable' 将被设置。
zr
zr 减少折叠:将 v:count1 添加到 'foldlevel'
zR
zR 打开所有折叠。这会将 'foldlevel' 设置为最高折叠级别。
:foldo :foldopen :{range}foldo[pen][!] 打开 {range} 中的折叠。当添加 [!] 时,将打开所有折叠。这对于查看 {range} 中的所有文本很有用。没有 [!] 时,将打开一级折叠。
:foldc :foldclose :{range}foldc[lose][!] 关闭 {range} 中的折叠。当添加 [!] 时,将关闭所有折叠。这对于隐藏 {range} 中的所有文本很有用。没有 [!] 时,将关闭一级折叠。
zn
zn 不折叠:重置 'foldenable'。所有折叠都将打开。
zN
zN 正常折叠:设置 'foldenable'。所有折叠都将恢复到之前的状态。
zi
zi 反转 'foldenable'
跨越折叠移动
[z
[z 移动到当前打开的折叠的开头。如果已经在开头,则移动到包含它的折叠的开头。如果没有包含的折叠,则命令失败。当使用计数时,将重复该命令 [count] 次。
]z
]z 移动到当前打开的折叠的结尾。如果已经在结尾,则移动到包含它的折叠的结尾。如果没有包含的折叠,则命令失败。当使用计数时,将重复该命令 [count] 次。
zj
zj 向下移动到下一个折叠的开头。关闭的折叠被计为一个折叠。当使用计数时,将重复该命令 [count] 次。此命令可以在 运算符 之后使用。
zk
zk 向上移动到上一个折叠的结尾。关闭的折叠被计为一个折叠。当使用计数时,将重复该命令 [count] 次。此命令可以在 运算符 之后使用。
在折叠上执行命令
:[range]foldd[oopen] {cmd} :foldd :folddo :folddoopen 在所有不在关闭的折叠中的行上执行 {cmd}。当给出 [range] 时,仅使用这些行。每次执行 {cmd} 时,光标都会定位在执行该命令的行上。这与 ":global" 命令类似:首先标记所有不在关闭的折叠中的行。然后对所有标记的行执行 {cmd}。因此,当 {cmd} 更改折叠时,这不会影响其执行的位置(当然,除非删除行)。示例
:folddoopen s/end/loop_end/ge
注意 "e" 标志的使用,以避免在 "end" 不匹配时出现错误消息。
:[range]folddoc[losed] {cmd} :folddoc :folddoclosed 在所有位于关闭的折叠中的行上执行 {cmd}。否则与 ":folddoopen" 相似。

3. 折叠选项 fold-options

关闭折叠的颜色由 Folded 组 hl-Folded 设置。折叠列的颜色由 FoldColumn 组 hl-FoldColumn 设置。设置颜色的示例
:highlight Folded guibg=grey guifg=blue
:highlight FoldColumn guibg=darkgrey guifg=white

FOLDLEVEL fold-foldlevel

'foldlevel' 是一个数字选项:数字越高,打开的折叠区域就越多。当 'foldlevel' 为 0 时,所有折叠都关闭。当 'foldlevel' 为正数时,一些折叠被关闭。当 'foldlevel' 非常高时,所有折叠都打开。 'foldlevel' 在更改时应用。之后可以手动打开和关闭折叠。当增加时,高于新级别的折叠将被打开。不会关闭任何手动打开的折叠。当减少时,高于新级别的折叠将被关闭。不会打开任何手动关闭的折叠。

FOLDTEXT fold-foldtext

'foldtext' 是一个字符串选项,用于指定表达式。该表达式将被评估以获得显示在关闭的折叠上的文本。示例
:set foldtext=v:folddashes.substitute(getline(v:foldstart),'/\\*\\\|\\*/\\\|{{{\\d\\=','','g')
这显示了折叠的第一行,其中 "/*", "*/" 和 "{{{" 被删除。注意反斜杠的使用,以避免某些字符被 ":set" 命令解释。定义一个函数并调用它要简单得多
:set foldtext=MyFoldText()
:function MyFoldText()
:  let line = getline(v:foldstart)
:  let sub = substitute(line, '/\*\|\*/\|{{{\d\=', '', 'g')
:  return v:folddashes .. sub
:endfunction
评估 'foldtext'沙盒 中完成。当前窗口将设置为显示该行的窗口。
错误将被忽略。为了调试,将 'debug' 选项设置为 "throw"。
默认值为 foldtext()。这将为大多数类型的折叠返回合理的文本。如果您不喜欢它,可以指定您自己的 'foldtext' 表达式。它可以使用以下特殊的 Vim 变量:v:foldstart 折叠中第一行的行号 v:foldend 折叠中最后一行行号 v:folddashes 包含代表折叠级别的破折号的字符串。v:foldlevel 折叠的折叠级别
如果结果是 List,它将被解析并像 "overlay" 虚拟文本一样绘制(参见 nvim_buf_set_extmark()),否则结果将被转换为字符串,其中 TAB 将被空格替换,不可打印的字符将变为可打印的字符。
结果行将被截断以适合窗口,它永远不会换行。如果文本之后有空间,它将用 'fillchars' 指定的字符填充。
如果 'foldtext' 表达式以 s: 或 <SID> 开头,则它将被脚本 ID (local-function) 替换。示例
set foldtext=s:MyFoldText()
set foldtext=<SID>SomeFoldText()
请注意,对于“:set”命令以不同方式处理的字符,需要使用反斜杠:空格、反斜杠和双引号。 option-backslash

FOLDCOLUMN fold-foldcolumn

'foldcolumn' 是一个数字,它设置窗口侧边一列的宽度,用于指示折叠。当它为零时,没有折叠列。一个正常的值是 auto:9。最大值为 9。
打开的折叠用顶部有“-”、下方有“|”字符的列表示。此列在打开的折叠结束处停止。当折叠嵌套时,嵌套折叠位于其包含折叠的右侧一个字符处。
关闭的折叠用“+”表示。
这些字符可以使用 'fillchars' 选项更改。
当折叠列太窄而无法显示所有嵌套折叠时,将显示数字以指示嵌套级别。
鼠标也可以用于通过点击折叠列来打开和关闭折叠。
点击“+”以打开该行处的关闭折叠。
点击任何其他非空白字符以关闭该行处的打开折叠。

其他选项

'foldenable' 'fen': 未设置时打开所有折叠。 'foldexpr' 'fde': 用于“expr”折叠的表达式。 'foldignore' 'fdi': 用于“indent”折叠的字符。 'foldmarker' 'fmr': 用于“marker”折叠的定义标记。 'foldmethod' 'fdm': 当前折叠方法的名称。 'foldminlines' 'fml': 为了使折叠显示为关闭状态,屏幕上折叠的最小行数。 'foldnestmax' 'fdn': “indent”和“syntax”折叠的最大嵌套级别。 'foldopen' 'fdo': 哪些类型的命令打开关闭的折叠。 'foldclose' 'fcl': 当光标下的折叠关闭时。

4. 折叠的行为 fold-behavior

向上或向下移动光标以及滚动时,光标将移动到折叠行序列的第一行。当光标已位于折叠行上时,它将移动到下一行未折叠的行或下一个关闭的折叠。
当光标位于折叠行上时,光标始终显示在第一列中。标尺确实显示了实际的光标位置,但由于该行已折叠,因此无法在该处显示。
许多移动命令将折叠行序列处理为空行。例如,“w”命令在第一列中停止一次。
当在关闭的折叠中开始搜索时,它将不会在当前折叠中找到匹配项。就像向前搜索总是从关闭的折叠的末尾开始,而向后搜索从关闭的折叠的开头开始一样。
在插入模式下,光标行永远不会折叠。这让你可以查看你键入的内容!
当使用操作符时,关闭的折叠将作为一个整体包含在内。因此,“dl”删除了光标下方的整个关闭的折叠。
对于在缓冲区行上工作的 Ex 命令,范围将调整为始终从关闭的折叠的第一行开始,并在关闭的折叠的最后一行结束。因此,此命令
:s/foo/bar/g
当与光标位于关闭的折叠上一起使用时,将在折叠的所有行中将“foo”替换为“bar”。这不会发生在 :folddoopen:folddoclosed 上。
当编辑以前编辑过的缓冲区时,将再次使用最后使用的折叠设置。对于手动折叠,将恢复已定义的折叠。对于所有折叠方法,将恢复手动打开和关闭的折叠。如果此缓冲区已在此窗口中编辑过,则将使用来自当时的值。否则,将使用来自上次编辑缓冲区的窗口的值。
主要
命令索引
快速参考