折叠(Fold)
折叠就是将缓冲区中某一个范围内的文本行折叠为一行,就像一张纸被折叠缩短些而突出其他更重要的区域:
Text Only
+------------------------+
| 行 1 |
| 行 2 |
| 行 3 |
|_______________________ |
\ \
\________________________\
/ 被折叠的行 /
/________________________/
| 行 12 |
| 行 13 |
| 行 14 |
+------------------------+
被折叠的文本仍然在缓冲区内没有改变,受到折叠影响的只是文本行显示的方式。他的好处是能够更方便的类似大纲试图展示文章而专注与某一个区域。
foldmethod
折叠方法由 foldmethod
来设定,其中包含六种折叠方式:
- manual: 手工定义折叠
- indent: 使用缩进来进行折叠
- expr: 用表达式来定义折叠
- syntax: 使用语法高亮来定义折叠
- diff: 对没有更改的文本进行折叠
- marker: 对文中的标志折叠
其中默认就是 manual,插件则会提供 expr 配合 foldexpr 来实现高级的折叠。
手动折叠(manual)
通过 zf{motion}
或 {Visual}zf
来创建折叠,这是使用手动折叠最常见的方式。
之后我们可以使用 zo zc 来打开和关闭折叠,实际上所有折叠命令都是以 z 开头的:
- zf: F-old create(创建折叠)
- zo: O-pen a fold(打开折叠)
- zc: C-lose a fold(关闭折叠)
Tips
Text Only
还有一个更常用的 `za` 来打开/关闭折叠
Note
Text Only
手动折叠最大的问题就是关闭当前 buffer 时默认会丢弃,当然可以使用 session 相关的命令保存但是这就引入了复杂性。
表达式折叠(expr)
表达式折叠能够通过自定义表达式来控制折叠逻辑,是一种非常灵活的折叠方法,它需要配合 foldexpr 来定义行为:
foldexpr 是一个 vim 表达式,通过表达式的返回值来控制每一行的折叠等级,该表达式的返回值是一个整数:
0
: 当前行没有折叠>0
: 当前行在指定等级上被折叠-1
: 继承上一行的折叠等级(与上一行同级,不会产生新的折叠)
例如假设你先让每一个以 # region
开头的和以 # endregion
结尾的作为一个折叠块,可以使用:
VimL
:set foldexpr=getline(v:lnum) =~? '^# region' ? '1' :
\ getline(v:lnum) =~? '^# endregion' ? '0' : '-1'
他的含义:
v:lnum
表示当前行号,这样getline(v:lnum)
返回当前行内容=~?
是不区分大小写的模式匹配'^# region' ? '1'
即如果以# region
开头返回 1,否则执行后续语句'^# endregion' ? '0'
表示以# endregion
开头结束折叠-1
表示如果没有上面的内容这继承上一行的折叠等级,这样在他们之间的折叠等级都是 1,而后续的就是继承# endregion
的 0 这样就实现了只折叠指定块
一个完整的表达式是比较复杂的,它需要很多分支逻辑,如果先要更加现代化的折叠可以使用nvim-treesitter插件来实现:
折叠等级(foldlevel)
折叠等级控制了哪些折叠会被展开或隐藏,折叠等级是通过嵌套层级来进行划分的,例如基于 foldmethod = indent
的折叠等级划分:
Tips
Text Only
不同的折叠方法划分的方式不太一样,例如 `foldmethod=syntax` 时的 python,类包含方法和属性,方法又包含语句这样形成的嵌套而形成的折叠等级。
通过设置 foldlevel
参数来决定哪些折叠被关闭,所有高于 foldlevel 的折叠会被关闭,实际上有很多命令来设置该选项来控制代码的折叠和关闭:
zm
: M-ore flod,通过foldlevel - 1
来折叠更多zM
: 设置foldlevel = 0
关闭所有折叠zr
: R-educe flod,通过foldlevel + 1
来打开更多折叠zR
: 设置foldlevel = 99
打开所有折叠
还有一个比较极端的 foldnable
设置来开启或关闭折叠功能:
zn
: N-o fold,设定 nofoldenable,所有折叠被打开(即折叠功能被关闭)zN
: 设定 foldenable,重新根据当前的 foldlevel 来应用折叠zi
: 反转 foldenable