当前位置:K88软件开发文章中心编程工具Vim → 文章内容

Vimscript 高级折叠

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-24 10:54:14

由 Loen 创建, 最后一次修改 2016-02-24 在上一章里我们用Vim的indent折叠方式,在Potion文件中增加了一些快捷而肮脏的折叠。打开factorial.pn并用zM关闭所有的折叠。文件现在看起来就像这样:factorial = (n):+-- 5 lines: total = 110 times (i):+-- 4 lines: i string print展开第一个折叠,它看上去会是这样:factorial = (n): total = 1 n to 1 (i):+--- 2 lines: # Multiply the running total. total.10 times (i):+-- 4 lines: i string print这真不错,但我个人喜欢依照内容来折叠每个块的第一行。 在本章中我们将写下一些自定义的折叠代码,并在最后实现这样的效果:factorial = (n): total = 1+--- 3 lines: n to 1 (i): total.+-- 5 lines: 10 times (i):这将更为紧凑,而且(对我来说)更容易阅读。 如果你更喜欢indent也不是不行,不过最好学习本章来对Vim中实现折叠的代码的更深入的了解。折叠原理为了写好自定义的折叠,我们需要了解Vim对待("thinks")折叠的方式。简明扼要地讲解下规则:文件中的每行代码都有一个"foldlevel"。它不是为零就是一个正整数。foldlevel为零的行_不会_被折叠。有同等级的相邻行会被折叠到一起。如果一个等级X的折叠被关闭了,任何在里面的、foldlevel不小于X的行都会一起被折叠,直到有一行的等级小于X。通过一个例子,我们可以加深理解。打开一个Vim窗口然后粘贴下面的文本进去。a b c d e fg执行下面的命令来设置indent折叠::setlocal foldmethod=indent花上一分钟玩一下折叠,观察它是怎么工作的。现在执行下面的命令来看看第一行的foldlevel::echom foldlevel(1)Vim显示0。现在看看第二行的::echom foldlevel(2)Vim显示1。试一下第三行::echom foldlevel(3)Vim再次显示1。这意味着第2,3行都属于一个level1的折叠。这是每一行的foldlevel:a 0 b 1 c 1 d 2 e 2 f 1g 0重读这一部分开头的几条规则。打开或关闭每个折叠,观察foldlevel,并确保你理解了为什么会这样折叠。一旦你已经自信地认为你理解了每行的foldlevel是怎么影响折叠结构的,继续看下一部分。首先:做一个规划在我们埋头敲键盘之前,先为我们的折叠功能规划出几条大概的规则。首先,同等缩进的行应该要折叠到一块。我们也希望_上_一行也一并折叠,达到这样的效果:hello = (name): 'Hello, ' print name print.将折叠成这样:+-- 3 lines: hello = (name):空行应该算入_下_一行,因此折叠底部的空行不会包括进去。这意味着类似这样的内容:hello = (name): 'Hello, ' print name print.hello('Steve')将折叠成这样:+-- 3 lines: hello = ():hello('Steve')而_不是_这样:+-- 4 lines: hello = ():hello('Steve')这当然是属于个人偏好的问题,但现在我们就这么定了。开始现在开始写我们的自定义折叠代码吧。 打开Vim,分出两个分割,一个是ftplugin/potion/folding.vim,另一个是示例代码factorial.pn。在上一章我们关闭并重新打开Vim来使得folding.vim生效,但其实还有更简单的方法。不要忘记每当设置一个缓冲区的filetype为potion的时候,在ftplugin/potion/下的所有文件都会被执行。 这意味着仅需在factorial.pn的分割下执行:set ft=potion,Vim将重新加载折叠代码!这比每次都关闭并重新打开文件要快多了。 唯一需要铭记的是,你得保存folding.vim到硬盘上,否则未保存的改变不会起作用。Expr折叠为了获取折叠上的无限自由,我们将使用Vim的expr折叠。我们可以继续并从folding.vim移除foldignore,因为它只在使用indent的时候生效。 我们也打算让Vim使用expr折叠,所以把folding.vim改成这样:setlocal foldmethod=exprsetlocal foldexpr=GetPotionFold(v:lnum)function! GetPotionFold(lnum) return '0'endfunction第一行只是告诉Vim使用expr折叠。第二行定义了Vim用来计算每一行的foldlevel的表达式。 当Vim执行某个表达式,它会设置v:lnum为它需要的对应行的行号。 我们的表达式将把这个数字作为自定义函数的参数。最后我们定义一个对任意行均返回0的占位(dummy)函数。 注意它返回的是一个字符串而不是一个整数。等会我们就知道为什么这么做。继续并重新加载折叠代码(保存folding.vim并对factorial.pn执行:set ft=potion)。 我们的函数对任意行均返回0,所以Vim将不会进行任何折叠。空行让我们先解决空行的特殊情况。修改GetPotionFold函数成这样:function! GetPotionFold(lnum) if getline(a:lnum) =~? '\v^\s*$' return '-1' endif return '0'endfunction我们增加了一个if语句来处理空行。它是怎么起效的?首先,我们使用getline(a:lnum)来以字符串形式获取当前行的内容。我们把结果跟正则表达式\v^\s*$比较。记得\v表示"very magic"(我的意思是,正常的)模式。 这个正则表达式将匹配"行的开头,任何空白字符,行的结尾"。比较是用大小写不敏感比较符=~?完成的。 技术上我们不用担心大小写,毕竟我们只匹配空白,但是我偏好在比较字符串时使用更清晰的方式。 如果你喜欢,可以使用=~代替。如果需要唤起Vim中的正则表达式的回忆,你应该回头重读"基本正则表达式"和"Grep Operator"这两部分。如果当前行包括一些非空白字符,它将不会匹配,我们将如前返回0。如果当前行_匹配_正则表达式(i.e. 比如它是空的或者只有空格),就返回字符串'-1'。之前我说过一行的foldlevel可以为0或者正整数,所以这会发生什么?特殊折叠你自定义的表达式可以直接返回一个foldlevel,或者返回一个"特殊字符串"来告诉Vim如何折叠这一行。'-1'正是其中一种特殊字符串。它告知Vim,这一行的foldlevel为"undefined"。 Vim将把它理解为"该行的foldlevel等于其上一行或下一行的较小的那个foldlevel"。这不是我们计划中的_最终_结果,但我们可以看到,它已经足够接近了,而且必将达到我们的目标。Vim可以把undefined的行串在一起,所以假设你有三个undefined的行和接下来的一个level1的行, 它将设置最后一行为1,接着是倒数第二行为1,然后是第一行为1。在写自定义的折叠代码时,

[1] [2] [3]  下一页


Vimscript 高级折叠