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

Vimscript 高级折叠

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

你经常会发现有几种行你可以容易地设置好它们的foldlevel。 然后你就可以使用'-1'(或我们等会会看到的其他特殊foldlevel)来"瀑布般地"设置好剩余的行的foldlevel。如果你重新加载了factorial.pn的折叠代码,Vim_依然_不会折叠任何行。 这是因为所有的行的foldlevel要不是为0,就是为"undefined"。 等级为0的行将影响undefined的行,最终导致所有的行的foldlevel都是0。缩进等级辅助函数为了处理非空行,我们需要知道它们的缩进等级,所以让我们来创建一个辅助函数替我们计算它。 在GetPotionFold之上加上下面的函数:function! IndentLevel(lnum) return indent(a:lnum) / &shiftwidthendfunction重新加载折叠代码。在factorial.pn缓冲区执行下面的命令来测试你的函数::echom IndentLevel(1)Vim显示0,因为第一行没有缩进。现在在第二行试试看::echom IndentLevel(2)这次Vim显示1。第二行开头有四个空格,而shiftwidth设置为4,所以4除以4得1。我们用它除以缓冲区的shiftwidth来得到缩进等级。为什么我们使用&shiftwidth而不是直接除以4? 如果有人偏好使用2个空格缩进他们的Potion代码,除以4将导致不正确的结果。 使用shiftwidth可以允许任何缩进的空格数。再来一个辅助函数下一步的方向尚未明朗。让我们停下来想想为了确定折叠非空行,还需要什么信息。我们需要知道每一行的缩进等级。我们已经通过IndentLevel函数得到了,所以这个条件已经满足了。我们也需要知道_下一个非空行_的缩进等级,因为我们希望折叠段头行到对应的缩进段中去。让我们写一个辅助函数来得到给定行的下一个非空行的foldlevel。在IndentLevel上面加入下面的函数:function! NextNonBlankLine(lnum) let numlines = line('$') let current = a:lnum + 1 while current <= numlines if getline(current) =~? '\v\S' return current endif let current += 1 endwhile return -2endfunction这个函数有点长,不过很简单。让我们逐个部分分析它。首先我们用line('$')得到文件的总行数。查查文档来了解line()。接着我们设变量current为下一行的行号。然后我们开始一个会遍历文件中每一行的循环。如果某一行匹配正则表达式\v\S,表示匹配"有一个_非_空白字符",它就是非空行,所以返回它的行号。如果某一行不匹配,我们就循环到下一行。如果循环到达文件尾行而没有任何返回,这就说明当前行之后_没有_非空行! 我们返回-2来指明这种情况。-2不是一个有效的行号,所以用来简单地表示"抱歉,没有有效的结果"。我们可以返回-1,因为它也是一个无效的行号。 我甚至可以选择0,因为Vim中的行号从1开始! 所以为何我选择-2这个看上去奇怪的选项?我选择-2是因为我们正处理着折叠代码,而'-1'(和'0')是特殊的Vim foldlevel字符串。当眼睛正扫过代码时,看到-1,脑子里会立刻浮现起"undefined foldlevel"。 这对于0也差不多。 我在这里选择-2,就是为了突出它_不是_foldlevel,而是表示一个"错误"。如果你觉得这不可理喻,你可以安心地替换-2为-1或0。 这只是代码风格问题。完成折叠函数本章已经显得比较冗长了,所以现在把折叠函数包装起来(wrap up)吧。把GetPotionFold修改成这样:function! GetPotionFold(lnum) if getline(a:lnum) =~? '\v^\s*$' return '-1' endif let this_indent = IndentLevel(a:lnum) let next_indent = IndentLevel(NextNonBlankLine(a:lnum)) if next_indent == this_indent return this_indent elseif next_indent < this_indent return this_indent elseif next_indent > this_indent return '>' . next_indent endifendfunction这里的新代码真多!让我们分开一步步来看。空行首先我们检查空行。这里没有改动。如果不是空行,我们就准备好处理非空行的情况了。获取缩进等级接下来我们使用两个辅助函数来获取当前行和下一个非空行的折叠等级。你可能会疑惑万一NextNonBlankLine返回错误码-2该怎么办。 如果这发生了,indent(-2)还会继续工作。对一个不存在的行号执行indent()将返回-1。 你可以试试:echom indent(-2)看看。-1除以任意大于1的shiftwidth将返回0。 这好像有问题,不过它实际上不会有。现在暂时不用纠结于此。同级缩进既然我们已经得到了当前行和下一非空行的缩进等级,我们可以比较它们并决定如何折叠当前行。这里又是一个if语句:if next_indent == this_indent return this_indentelseif next_indent < this_indent return this_indentelseif next_indent > this_indent return '>' . next_indentendif首先我们检查这两行是否有同样的缩进等级。如果相等,我们就直接把缩进等级当作foldlevel返回!举个例子:ab c de假设我们正处理包含c的那一行,它的缩进等级为1。 下一个非空行("d")的缩进等级也是一样的,所以返回1作为foldlevel。假设我们正处理"a",它的缩进等级为0。这跟下一非空行("b")的等级是一样的,所以返回0作为foldlevel。在这个简单的示例中,可以分出两个foldlevel。a 0b ? c 1 d ?e ?纯粹出于运气,这种情况也处理了在最后一行对特殊的"error"情况。 记得我们说过,如果我们的辅助函数返回-2,next_indent将会是0。在这个例子中,行"e"的缩进等级为0,而next_indent也被设为0,所以匹配这种情况并返回0。 现在foldlevels是这样:a 0b ? c 1 d ?e 0更低的缩进等级我们再来看看那个if语句:if next_indent == this_indent return this_indentelseif next_indent < this_indent return this_indentelseif next_indent > this_indent return '>' . next_indentendifif的第二部分检查下一行的缩进等级是否比当前行小。就像是例子中行"d"的情况。如果符合,将再一次返回当前行的缩进等级。现在我们的例子看起来像这样:a 0b ? c 1 d 1e 0当然,你可以用||把两种情况连接起来,但是我偏好分开来写以显得更清晰。 你的想法可能不同。这只是风格问题。又一次,纯粹出于运气,这种情况处理了其他来自辅助函数的"error"状态。设想我们有一个文件像这样:a

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


Vimscript 高级折叠