我已经阅读了有关fold-expr(:h fold-expr)的帮助页面,但没有解释表达式中使用的语法。
有四个示例:

:set foldexpr=getline(v:lnum)[0]==\"\t\"
:set foldexpr=MyFoldLevel(v:lnum)
: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

我知道v:lnum是需要缩进级别的行,表达式2是对函数的调用。 1,3和4?有人可以给我解释一下吗?

评论

我的理解是该表达式应返回一个数字,并且该数字将用于确定给定行将在哪一级折叠。 0不折叠,1是最外面的折叠,2是嵌套在1级折叠内部的折叠,依此类推

#1 楼

:help 'foldexpr'开始:


对每条线进行评估以获得折叠水平


foldexpr进行评估,因此它需要是VimL代码;没有提及“特殊语法”等。此评估的结果控制着Vim认为是折叠还是不折叠。

可能的值是

  0                     the line is not in a fold
  1, 2, ..              the line is in a fold with this level
  "<1", "<2", ..        a fold with this level ends at this line
  ">1", ">2", ..        a fold with this level starts at this line


只是问题示例中使用的那些。有关完整列表,请参见:help foldexpr


第一个

第一个非常简单,一旦我们添加了一些空格并删除了反斜杠,我们就可以开始工作了。一个:set命令:

getline(v:lnum)[0] == "\t"




getline(v:lnum)获得整行。

[0]获得该行的第一个字符
== "\t"检查这是否是制表符。
VimL没有“ true”或“ false”,它只将“ 0”表示为false,将“ 1”表示为true。因此,如果此行以制表符开头,则以foldlevel 1折叠。如果不是,则它不在fold(0)中。

如果要扩展它以计算制表符的数量将具有基于缩进的折叠(至少在未启用expandtab时)。


第三

第三个实际上并没有那么复杂第一个;与第一个示例一样,我们首先要使其更具可读性:

getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1



我们用getline(v:lnum)整行得到

我们将其作为正则表达式与=~匹配到'^\s*$'; ^锚定到开头,\s表示任何空格字符,*表示重复前一个零或更多次,$锚定到结尾。因此,此正则表达式匹配(返回true)空白行或仅包含空格的行。

getline(v:lnum + 1)获取下一行。这条线。
如果这两个条件为真,则求值为\S,否则为<1。这是通过C和其他一些语言已知的“三元” 1完成的:if。因此,如果我们在一行是空白而下一行不是空白的情况下结束折叠。否则,我们将处于折叠级别1。或者,正如condition ? return_if_true : return_if_false所说的那样: />
第四次

第四次与第三次的行为相同,但是方式略有不同。展开后,它是:

getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1


如果前一行是空白行,而当前行是非空白行,则在该行上开始折叠(<1 ),如果没有,我们将折叠级别设置为1。


后缀

因此,所有3个示例的逻辑都非常简单。大多数困难在于缺少空格和一些反斜杠使用。 。我不知道现代机器上的差别有多大,除非您有性能问题,否则建议您使用一个函数(如第二个示例中所示)。请记住The Knuth:“过早的优化是万恶之源”。

这个问题也在StackOverflow上,答案略有不同。但是我的当然更好;-)

#2 楼

您本质上是在问这些表达式中的其他元素是什么,可以依次调用:help来找到它们:

v:lnum: the line being evaluated
getline(): get the line of text for a line number
==: equals
=~: matches
<cond>?<if-true>:<if-false>: evaluates to <if-true> if <cond> is true, else to <if-false>


我已经分解了以下这些表达式的各个部分有助于说明其含义:

1将以制表符开头的所有行返回1,其他行返回0:

v:lnum                      the current line number
getline(v:lnum)             the text of the current line
getline(v:lnum)[0]          the first character of the current line
getline(v:lnum)[0]==\"\t\" the first char of the current line is 'tab'


3在以下段落之后的空白行上结束折页:

 getline(v:lnum)=~'^\s*$'                                       current line is only spaces
                              getline(v:lnum+1)=~'\S'           next line has non-space
(getline(v:lnum)=~'^\s*$' && getline(v:lnum+1)=~'\S') ? '<1'   if both of these: <1
                                                              :1 otherwise: 1
(getline(v:lnum)=~'^\s*$' && getline(v:lnum+1)=~'\S') ? '<1':1


4在以下段落开始的空白行上进行折行:

(getline(v:lnum-1)=~'^\s*$'                                     previous line only spaces
                                getline(v:lnum)=~'\S'           this line has non-space
(getline(v:lnum-1)=~'^\s*$' && getline(v:lnum)=~'\S') ? '>1'   if both of these: >1
                                                              :1 otherwise: 1
(getline(v:lnum-1)=~'^\s*$' && getline(v:lnum)=~'\S') ? '>1':1 


<1>1等的含义就在:help fold-expr中这些表达式的正下方

#3 楼

不小心将我的答案发表为评论,并提早提交。 Darn mobile。

我的理解是表达式应返回一个数字,该数字将用于确定给定行将在哪一级折叠。 0不折叠,1是最外面的折叠,2是嵌套在1级折叠内部的折叠,依此类推。

示例中的表达式看起来像它们的值为true或false。 VimScript没有正确的布尔类型,因此它实际上是1或0,这是有效的折叠级别。

您可以使用VimScript编写自己的表达式,就像返回1或0一样简单,或更复杂,允许嵌套折叠。

评论


仅使用数字即可工作,但值得注意的是foldexpr可以求值其他特殊值,例如=,a1,s1,> 1,<1,-1

–马特·博姆(Matt Boehm)
15年2月24日在19:03