fold

fold.txt 适用于 Vim 9.2 版本。 最近更新: 2025年10月 VIM 参考手册 by Bram Moolenaar 译者: Zimin<cranecai@users.sf.net>、tocer 折叠 Folding folding folds 折叠功能的介绍请参考用户手册第 28 章 usr_28.txt 。 1. 折叠方法 fold-methods 2. 折叠命令 fold-commands 3. 折叠选项 fold-options 4. 折叠行为 fold-behavior {仅当编译时加入 +folding 特性才有效}

1. 折叠方法 fold-methods

折叠方法可通过 'foldmethod' 选项设置。 将 'foldmethod' 切换为非 "manual" 值时,先删除所有已存在的折叠,然后依据指定方 法创建新折叠。切换为 "manual" 时,则不会删除现有折叠。此设计方便先通过自动方式 定义折叠,然后进行手动微调。 有 6 种方法来选定折叠: manual 手动定义/调整折叠 indent 通过缩进量定义折叠级别 expr 通过表达式定义折叠 syntax 通过语法高亮定义折叠 diff 基于比较结果,对未更改文本进行折叠 marker 通过文本标志定义折叠 手 动 fold-manual 使用命令手动定义折叠区域。脚本中也可用此法,自行解析文本并定义折叠。 折叠级别仅由嵌套层数定义。要提升指定行范围的折叠级别,可在当前折叠内部,定义包 含此范围的新折叠。 放弃文件后,手工折叠会丢失。要保存折叠,可用 :mkview 命令。之后可使用 :loadview 恢复。 缩 进 fold-indent 通过行缩进量自动定义折叠。 折叠级别的计算方法是用行缩进量除以 'shiftwidth',向下取整。一段拥有相同或更高 级别的连续行构成一个折叠。级别更高的连续行构成嵌套折叠。 最大嵌套层数由 'foldnestmax' 选项控制。 计算折叠级别时,部分行会被忽略,并继承其前后相邻行的折叠级别的较小值。这包括空 行或空白行,也包括以 'foldignore' 中字符开头的行。'foldignore' 检查前会跳过前 导空白。缺省值适用于 C 语言,用 "#" 忽略预处理行 (在老式 C 风格中不缩进)。 如果需要更复杂的忽略规则,请使用 "expr" 方法。可在 'foldexpr' 中使用 indent() 函数获取行缩进量。 表 达 式 fold-expr 与 "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 已被设为当前行号 foldexpr 的计算结果按以下规则决定缩进级别: 值 含义 0 本行不折叠 1, 2, .. 指定本行折叠级别 -1 折叠级别未定义,使用前后相邻行的折叠级别的较小值。 "=" 折叠级别继承上行的计算结果 (译者注: 不能简单理解为沿用 上行级别,如上行使用 "<2",则上行级别为 2,而本行会据 上行要求,级别推断为 1)。 "a1", "a2", .. 上行折叠级别加上 (add) 指定数值作为本行折叠级别 "s1", "s2", .. 上行折叠级别减去 (subtract) 指定数值作为下行折叠级别 "<1", "<2", .. 指示指定级别的折叠在本行结束 ">1", ">2", .. 指示指定级别的折叠从本行开始 "="、"s" 和 "a" 诸值计算开销更大,请见 fold-expr-slow 。 并非必须用 ">1" ("<1") 标志折叠的始止。本行折叠级别高于 (低于) 上行时,折叠会 自动开始 (结束) (译者注: 反之不真。即使两行折叠级别相同,本行也可以开始新的同 级别的折叠)。 表达式不能产生副作用。包括不能修改缓冲区文本,光标位置,搜索模式,选项等。如过 程中必须临时修改,必须谨慎保存原值并事后恢复。 表达式中出错或计算结果无法识别时,Vim 不会报错,但会将折叠级别自动设为 0。需要 调试时,可将 'debug' 选项设为 "msg" 来查看错误消息。 表达式以 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() 根据上一折叠级别来计算当前折叠级别。但要注意, 如果指定行的级别未知,该函数返回 -1。另外,返回的是行开头所处级别,但折叠可能 在行内结束。 如果折叠未及时更新,可用 zxzX 强制刷新。 尽 量 减 少 计 算 开 销 fold-expr-slow 本方法因为计算开销较高,尤其在初次计算所有行的折叠级别时,会让系统变卡。在此之 后的每次改动,Vim 只会重新计算受影响的行 (其他行则重用已知折叠级别)。 因而,折叠表达式应尽量减少一行的计算所依赖的行数: 例如,最好避免使用 "=","a" 和 "s" 作为返回值,因为它们需要 Vim 向后回溯,计算之前行的折叠级别,直到找到独 立的折叠级别为止。 如果这很难,次优解是在缓冲区局部变量里缓存折叠级别 ( b:foldlevels ),仅在文本 修改 ( b:changedtick 变化) 时,重新计算: 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() 上例通过预编译不带参数 (仍然必须使用 v:lnum ) 的 Vim9 脚本函数获取额外加速。 见 expr-option-function 。 语 法 fold-syntax 通过带有 "fold" 参数的语法项定义折叠。 :syn-fold 折叠级别仅由嵌套层数定义。最大嵌套层数由 'foldnestmax' 控制。 务必正确配置语法同步。否则折叠效果可能与显示高亮不一致。使用跨行匹配模式时尤需 谨慎。如有疑问,可使用强制同步: :syn sync fromstart 比 较 fold-diff 根据比较结果,自动折叠未改动 (更准确说法是不靠近改动区域) 的文本。 仅适用于开启 'diff' 选项且显示差异文本的窗口。不然,会将整个缓冲区视作一个大折 叠。 可通过 'diffopt' 设置指定上下文行数。即折叠与变更行之间,不被折叠的行数。例如 要设定 8 行上下文: :set diffopt=filler,context:8 默认上下文为 6 行。 同时打开 'scrollbind' 选项时,Vim 会尽量在其他比较窗口中保持相同的折叠状态,确 保显示内容同步。 标 志 fold-marker 通过文本中的特定标志,定义折叠开始和结束位置。可精确定义折叠范围。这种方法可安 心删除和复制折叠,无需担心错误包含无关行。'foldtext' 选项的缺省设置会显示已折 叠行在折叠标志前的文本。方便为折叠命名 (见 foldtext() )。 标志可直接指定折叠级别,也可通过开始/结束标志配对来间接指定。直接指定级别更简 单,无须添加结束标志,也不会出现标志不配对的问题。如: /* 全局变量 {{{1 */ int varA, varB; /* 函数 {{{1 */ /* funcA() {{{2 */ void funcA() {} /* funcB() {{{2 */ void funcB() {} {{{ }}} 折叠从 "{{{" 标志开始。其后数值表示折叠级别。实际行为依当前级别和标志指定级别 的大小关系而定: 1. 级别相同时,结束上一个折叠,开始同级别的新折叠。 2. 标志指定级别更高时,开始新的嵌套折叠。 3. 标志指定级别更低时,结束所有高于或等于当前级别的折叠,开始指定级别新折叠。 数值指定折叠级别。0 值无效 (会被忽略)。可用 "}}}" 加数值表示结束对应级别的折 叠。下行的折叠级别会自动减一。注意 Vim 不会回溯实际开始标志以决定结束后的折叠 级别 (因为开销太大)。例如: {{{1 当前折叠级别为 1 {{{3 当前折叠级别为 3 }}}3 当前折叠级别为 2 也可用配对的 "{{{" 和 "}}}" 标志定义折叠。每次使用 "{{{" 会使折叠级别加 1,而 每次使用 "}}}" 会使折叠级别减 1。注意保持标志配对!如: {{{ 当前折叠级别为 1 {{{ 当前折叠级别为 2 }}} 当前折叠级别为 1 可混合使用带数值和无数值标志。一种实用的方式是,用带数值的标志定义大区域折叠, 而在函数内部用无数值标志。例如,可用 1 级折叠划分文件中的大章节 ("结构定义"、 "局部变量" 和 "函数")。用 2 级折叠包围每个结构定义和函数体。而在函数内部使用无 数值标志。在函数中修改拆分折叠时,无须重新编号标志。 标志可通过 'foldmarker' 选项设置。建议保留缺省值 "{{{,}}}"。这样文件可在不同 Vim 用户间通用。仅当文件有特殊需求时 (如包含来自其他编辑器的折叠标志,或缺省折 叠标志与当前文件语法有冲突等) 才需要修改。 fold-create-marker 可通过 zf 命令创建标志折叠。Vim 会在行范围的首行和末行的行尾自动插入由 'foldmarker' 指定的开始和结束标志。'commentstring' 非空时,会用注释标记包围折 叠标志。 以下情况下无法正常工作: - 该行 (首行或末行) 已包含带级别的标志。Vim 无法判断如何进行。 - 附近折叠使用了带级别的标志,会因此产生冲突。 - 该行位于注释中,'commentstring' 非空,且嵌套注释非法。例如,在 C 语言的注释 内部加入 /* {{{ */ 会破坏现有注释。解决方法是在该注释外部 (之前或之后) 添加 标志,或手工添加标志。 通用建议是,已使用带级别标志时,不建议再使用 Vim 命令创建标志。 fold-delete-marker 可通过 zd 命令删除标志折叠。Vim 会自动在折叠的开始和结束处根据 'foldmarker' 搜索并删除开始和结束标志。如果标志周围文本匹配 'commentstring', 也自动删除这些 注释标记。 以下情况下无法正常工作: - 该行包含多个标志,其中一个带级别编号。Vim 只会删除首个标志,无法保存结果是否 能真正删除折叠。 - 标志包含级别编号,且同时开始或结束多个折叠。

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 删除 (delete) 光标所在的单层折叠。光标位于已折叠行时,则删除该 折叠。删除折叠内部的嵌套折叠上移一层。在可视模式下,删除选区覆 盖 (包括部分覆盖) 的所有单层折叠。 小心: 这很容易删除超出预期的折叠,而且手动折叠删除后无法撤销。 仅当 'foldmethod' 为 "manual" 或 "marker" 时有效。 参考 fold-delete-marker zD zD 递归删除 (Delete) 光标所在折叠,包括嵌套折叠。在可视模式下,删 除选区覆盖 (包括部分覆盖) 的所有折叠,包括嵌套折叠。 仅当 'foldmethod' 为 "manual" 或 "marker" 时有效。 参考 fold-delete-marker zE E352 zE 清空 (Eliminate) 窗口所有折叠。 仅当 'foldmethod' 为 "manual" 或 "marker" 时有效。 参考 fold-delete-marker打 开 和 关 闭 折 叠 行数少于 'foldminlines' 的折叠总是会显示为展开状态。要注意以下命令的描述对小折 叠未必适用。 zo zo 展开 (open) 光标所在折叠一层。给定计数时,展开相应层数; 在可视模式下,展开选区覆盖的所有折叠一层。 zO zO 递归展开 (Open) 光标所在折叠,包括嵌套折叠。不包含光标的折叠不 受影响。在可视模式下,展开选区覆盖 (包括部分覆盖) 的所有折叠, 包括嵌套折叠。 zc zc 关闭 (close) 光标所在折叠一层。给定计数时,关闭相应层数; 在可视模式下,关闭选区覆盖的所有折叠一层。 本命令会自动打开 'foldenable' zC zC 递归关闭 (Close) 光标所在折叠,包括嵌套折叠。不包含光标的折叠 不受影响。在可视模式下,关闭选区覆盖 (包括部分覆盖) 的所有折 叠,包括嵌套折叠。 本命令会自动打开 'foldenable' za za 小结: 切换光标所在折叠状态。 光标位于已关闭折叠时,展开一层。位于嵌套折叠时,可能需要用 "za" 数次才能完全展开。给定计数时,打开相应层数的已关闭折叠。 光标位于展开折叠时,关闭,且自动打开 'foldenable'。仅关闭单层 折叠,再次使用 "za" 会展开折叠。给定计数时,关闭相应层数的折叠 (和重复 "za" 同样多次的效果不同)。 zA zA 位于已关闭折叠时,递归展开折叠。 位于展开折叠时,递归关闭折叠,且自动打开 'foldenable' zv zv 查看 (view) 光标所在行: 仅展开必要折叠,保证光标行完整可见。 zx zx 更新折叠: 撤销对折叠的手动展开和关闭: 重新应用 'foldlevel'。 然后执行 zv : 查看光标所在行。 同时强制重算折叠。适用于 'foldexpr' 未对缓冲区变动及时更新折叠 的异常场景。 zX zX 撤销对折叠的手动展开和关闭: 重新应用 'foldlevel'。 和 zx 类似,也同时强制重算折叠, zm zm 折起更多 (more): 使 'foldlevel' 减少 v:count1 ,但不能低于零。 本命令会自动打开 'foldenable' zM zM 关闭所有折叠: 将 'foldlevel' 设为 0。 本命令会自动打开 'foldenable' zr zr 减少 (reduce) 折叠: 使 'foldlevel' 增加 v:count1 zR zR 展开所有的折叠。将 'foldlevel' 设为当前最高嵌套级别。 :foldo :foldopen :{range}foldo[pen][!] 展开 {range} 范围内的所有折叠。带 [!] 时,递归展开所有折叠,方 便查看 {range} 内的完整文本。省略 [!] 时,打开折叠一层。 :foldc :foldclose :{range}foldc[lose][!] 关闭 {range} 范围内的所有折叠。带 [!] 时,递归关闭所有折叠。方 便隐藏 {range} 内的所有文本。省略 [!] 时,关闭折叠一层。 zn zn 不 (none) 折叠: 复位 'foldenable'。所有折叠全部展开。 zN zN 正常 (normal) 折叠: 打开 'foldenable'。还原原有折叠状态。 zi zi 翻转 (invert) 'foldenable' 值,切换折叠功能启用状态。 在 折 叠 间 移 动 [z [z 跳转到当前打开折叠的起始位置。如果已在起始位置,则跳转到包含当 前折叠的上一层折叠的起始位置。如果没有外层折叠,本命令会失败。 给定计数时,重复执行 [count] 次。 ]z ]z 跳转到当前打开折叠的结束位置。如果已在结束位置,则跳转到包含当 前折叠的上一层折叠结束位置。如果没有外层折叠,本命令会失败。 给定计数时,重复执行 [count] 次。 zj zj 向下跳转到下一个折叠的开始位置。已关闭折叠也算作一个折叠。 给定计数时,重复执行 [count] 次。 本命令可在 operator 后使用。 zk zk 向上跳转到上一个折叠的结束位置。已关闭折叠也算作一个折叠。 给定计数时,重复执行 [count] 次。 本命令可在 operator 后使用。 在 折 叠 上 执 行 命 令 :[range]foldd[oopen] {cmd} :foldd :folddo :folddoopen 对非关闭折叠内的所有行执行 {cmd}。 给定 [range] 时,仅在指定范围内执行。 执行时,光标会先自动定位到待处理行。 和 :global 命令的执行机制类似: 首先标记出不在关闭折叠内的所 有行。然后对所有标记行执行 {cmd}。因此,即使 {cmd} 修改了文本 的折叠状态,也不会影响命令执行范围 (当然,被删除行例外)。 例如: :folddoopen s/end/loop_end/ge 使用标志位 "e" 可在 "end" 不匹配时避免报错。 :[range]folddoc[losed] {cmd} :folddoc :folddoclosed 对已关闭折叠内的所有行执行 {cmd}。 余同 :folddoopen 命令。

3. 折叠选项 fold-options

颜 色 fold-colors 已关闭折叠的颜色由 Folded 高亮组 hl-Folded 决定。折叠栏的颜色的设 定由 FolderColumn 高亮组 hl-FoldColumn 决定。 :highlight Folded guibg=grey guifg=blue :highlight FoldColumn guibg=darkgrey guifg=white 折 叠 级 别 fold-foldlevel 'foldlevel' 为数值选项,代表折叠级别: 级别越大则展开的折叠更多。 'foldlevel' 为 0 时,所有折叠都被关闭。 'foldlevel' 为正数时,关闭部分折叠。 'foldlevel' 很大时,展开所有折叠。 'foldlevel' 被修改后效果立即生效。之后仍可以手动展开和关闭折叠。 增加时,高于新级别 (译者注: 应为旧级别) 的折叠会展开。不会关闭手工展开的折叠。 减小时,高于新级别的折叠被关闭。不会展开手工关闭的折叠。 折 叠 文 本 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 使用不带参数的函数调用更有效率,见 expr-option-function 。 模式行中设置时会在沙盘 sandbox 里计算 'foldtext'。当前窗口是显示该行的窗口。 在上次设置本选项的脚本上下文下执行表达式。 表达式中出错时不会报错,需要调试时,可将 'debug' 选项设为 "throw"。 选项缺省值是 foldtext() 。能为大多数类型的折叠生成合适的文本。如果不满意缺省 效果,可自定义 'foldtext' 表达式。其中可使用以下 Vim 变量: v:foldstart 折叠首行的行号 v:foldend 折叠末行的行号 v:folddashes 表示折叠级别的连字符序列 v:foldlevel 折叠级别 返回结果里的制表符会被替换为空格,而不可显示字符会被替换为可显示形式 <xx>。 超长结果文本会被截短以适配窗口而不会回绕。而多余空间会用 'fillchars' 里的 "fold" 字符来填充。 表达式以 s: 或 <SID> 开始时,会用脚本 ID ( local-function ) 替代这些前缀。例 如: set foldtext=s:MyFoldText() set foldtext=<SID>SomeFoldText() 注意 必须用反斜杠转义 ":set" 命令中的特殊字符 (包括空格,反斜杠,双引号等,参 见 option-backslash )。 折 叠 栏 fold-foldcolumn 'foldcolumn' 是数值选项,设置窗口左侧折叠指示列的宽度。为 0 时关闭折叠栏。常用 值为 4 或 5。最小可用值为 2,不过设为 1 仍可提供少量信息 (译者注: 为美观起见, 折叠栏最右侧缺省会显示一列空白,但设为 1 时关闭空白列)。最大值为 12。 打开折叠在折叠栏里会占用一列,在顶行显示 '-',后续行显示 '|' 延伸。折叠结束时 该列也会结束。嵌套折叠会占用外层折叠列的右侧列。 已关闭折叠会显示 '+'。 可用 'fillchars' 选项调整上述字符 ("foldopen", "foldsep", "foldclose")。 窄折叠栏容不下所有嵌套折叠时,会显示数位 (超过 9 会显示 '>') 代表嵌套级别,替 代 '|'。可用 'fillchars' 选项的 "foldinner" 字符替代级别显示 (译者注: 窄折叠栏 也会根据 'foldcolumn' 智能选择最左列对应的起始折叠级别)。 在折叠栏点击鼠标,可展开和关闭折叠: - 点击 '+' 会展开该行所在已关闭折叠。 - 在其他非空字符上点击,会关闭该行所在打开折叠。 其 他 选 项 '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 会在整个折叠里用 "bar" 替代 "foo"。 :folddoopen:folddoclosed 不受此规则影响。 注意 :source 等部分 Ex 命令,仅在使用双行限定符 [range] 时才会进行范围调整。 重新打开过往编辑的缓冲区时,会沿用上次的折叠设置。恢复手动创建的折叠,也复原在 所有方法下创建折叠的手动展开或关闭状态。优先读取当前窗口中该缓冲区的历史配置 (如有),否则,调取该缓冲区最近一次编辑窗口的配置。

vim:tw=78:ts=8:noet:ft=help:norl: