使用fold-expr时,vim会变慢

时间:2014-12-09 17:33:00

标签: vim folding code-folding

我试图为大型降价文件创建一个简单,快速的折叠方法。我在vim中使用fold-expr方法。例如,如果我想在H1H2降价条目上开始折叠,我的vimscript代码为:

function! MarkdownLevel() 
    if getline(v:lnum) =~ '^# '
        " begin a fold of level one here 
        return ">1" 
    elseif getline(v:lnum) =~ '^## ' 
        " begin a fold of level two 
        return ">2" 
    else
        return "=" 
    endif 
endfunction 

这很有效,我得到了嵌套的折叠。但是,当我有一个大的降价文件时,vim会大大减慢。这并不奇怪,事实上,在vim的fold-expr帮助中表明了这一点。这是因为=符号告诉vim在文件中向后扫描,直到找到带有明确定义的 foldlevel的第一行;这可能是数千行。

我尝试用

替换最后一行
   else
      " set foldlevel to foldlevel of previous line
      return foldlevel(v:lnum-1)
   endif

但这并不像预期的那样奏效。有谁知道如何解决这一问题?很清楚我不理解foldlevel函数是如何工作的,或者是如何实现vim中的折叠算法。

3 个答案:

答案 0 :(得分:1)

您是否考虑过使用Drew Nelstrom的vim-markdown-folding插件?

您可能还想查看Vimcast剧集:Profiling Vimscript performance。这一集实际上是关于折叠降价的。

警示性想法

我无法肯定,因为我没有对您的代码进行分析(并且您应该真正地分析您的代码),但是每当重新绘制内容时,每行都会调用fold表达式,这对Vim来说非常沉重。一些猜测:

  • 使用像=这样的相对折叠表达式意味着我们需要计算前一行,以便您可以想象这可能会成为问题。如果可以的话,尝试使用精确的深度而不计算其他线条。
  • 您在函数中不必要地使用getline()两次
  • 某些文件只会导致问题接受此事实并通过zi
  • 禁用折叠

答案 1 :(得分:1)

我想出了如何解决减速问题,并了解了fold-expr在vim中的工作原理。我在3000行md文件上测试了性能问题。

我依赖于fold-expr应该具有的以下自动折叠功能:如果当前行的foldlevel小于下一个的foldlevel,它将开始折叠。如果当前行的foldlevel大于下一行的foldlevel,它结束折叠。事实证明,据我所知,这不符合预期。

使用return ">1"明确告诉vim折叠开始此处,其中1被相应的数字替换。

在学习了如何从@PeterRinker中分析vim脚本之后,我发现return "="语句在我编辑行(例如)3000时被评估了很多次。

这是我的修复:如果当前行的foldlevel没有落入任何标题类型中,前一行的foldlevel已经定义,那么当前行应该只继承上一行的折叠级别。这是一个显而易见的解决方案,但如果我使用上面的return "1"代替return ">1",那么无效。它需要第一遍的return "="语句才能找出foldlevel。

所以我的启动时间对于3000行文件来说有点大(大约1秒),但现在编辑非常流畅。以下是完成的,简单的代码。其他更精细的降价项目没有这种有用的简化。

function! MarkdownLevel()
    let theline = getline(v:lnum)
    let nextline = getline(v:lnum+1)
    if theline =~ '^# ' 
        " begin a fold of level one here
            return ">1"
    elseif theline =~ '^## ' 
        " begin a fold of level two here
            return ">2"
    elseif theline =~ '^### ' 
        " begin a fold of level three here
            return ">3"
    elseif nextline =~ '^===*'
        " elseif the next line starts with at least two ==
        return ">1"
    elseif nextline =~ '^---*'
        " elseif the line ends with at least two --
        return ">2"
    elseif foldlevel(v:lnum-1) != "-1" 
        return foldlevel(v:lnum-1)
    else
        return "="
    endif
end

答案 2 :(得分:0)

这是可以预料到的,因为Vim必须为每一行计算你的表达。在:h fold-expr

下方的帮助中也提到了这一点
Note: Since the expression has to be evaluated for every line,
this fold method can be very slow!

Try to avoid the "=", "a" and "s" return values, since Vim often
has to search backwards for a line for which the fold level is
defined.  This can be slow.