2

我正在尝试为大型降价文件创建一种简单、快速的折叠方法。我正在使用fold-exprvim中的方法。例如,如果我想开始折叠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 在文件中向后扫描,直到可以找到具有明确定义的折叠级别的第一行;这可能是数千行之外。

我试图用

   else
      " set foldlevel to foldlevel of previous line
      return foldlevel(v:lnum-1)
   endif

但这并没有按预期工作。有谁知道如何解决这一问题?很明显,我不了解 foldlevel 函数是如何工作的,或者 vim 中的折叠算法是如何实现的。

4

3 回答 3

1

Have you thought about using Drew Nelstrom's vim-markdown-folding plugin?

You may also want to look that the Vimcast episode: Profiling Vimscript performance. This episode actually talks about folding markdown.

Cautionary thoughts

I can not be for certain because I have not profiled your code (and you should really profile your code), but as the fold expression gets called on every line every time things get redrawn it can be very taxing on Vim. Some guesses:

  • Using relative fold expressions like = means we need to compute the previous line so as you can imagine this can become problematic. Try and use exact depths without computing other lines if you can.
  • You are using getline() twice in your function needlessly
  • Some files are just going to cause problems accept this fact and disable folding via zi
于 2014-12-09T18:06:37.797 回答
1

我想出了如何解决减速的问题,并了解了一些关于fold-exprvim 的工作原理。我在一个 3000 行的 md 文件上测试了性能问题。

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

有效的是明确告诉 vim 折叠从这里开始使用return ">1",其中1被适当的数字替换。

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

这是我的解决方法:如果当前行的折叠级别不属于任何标题类型并且上一行的折叠级别已经定义,则当前行应该只继承上一行的折叠级别。这是一个明显的解决方案,但如果我使用而不是上面的,它就不起作用。它需要第一遍的语句来计算折叠级别。return "1"return ">1"return "="

所以对于一个 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
于 2014-12-10T00:25:24.980 回答
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.
于 2014-12-09T19:36:41.597 回答