两种折叠方法同时进行

时间:2011-05-11 20:00:06

标签: vim folding

我想设置两种折叠方法

  1. :set foldmethod=indent并保留其所有功能
  2. 隐藏评论

    :set foldmethod=marker

    :set foldmarker=/*,*/

  3. 我发现这是不可能的。是否有可能实现所需的折叠并在.vimrc中设置或为此使用一些脚本或插件?

3 个答案:

答案 0 :(得分:8)

在同一个缓冲区中不可能有不同的foldmethod类型。 Vim如何知道在同一缩进级别有一些评论与您想要视为具有不同(更高编号)级别的其他文本?

我确信你可以通过将foldmethod设置为'expr'来达到你想要的效果。这是在Vim中进行折叠的最灵活方式,但可能会变得复杂(和/或缓慢),具体取决于您的需求。不过,我认为它对你的用例来说相当容易。

首先,在vimrc或vimscripts中的某个位置,您需要确保为相关文件类型定义了foldexpr。

set foldexpr=MyFoldLevel(v:lnum)
set foldmethod=expr
" and for last code example
let b:previous_level = 0

然后你必须充实你的foldexpr函数,以便它以一种导致你想要的行为的方式分配级别。类似下面的代码可能接近于每个注释行都有前缀符号(即,不是你的情况),但我希望它需要一些调整。 h: fold-expr是寻求帮助的好地方:

function! MyFoldLevel(linenum)
   " assign levels based on spaces indented and tabstop of 4
   let level = indent(a:linenum) / 4
   if getline(a:linenum) =~ [put line-based comment prefix pattern here]
       let level = 20
   endif
endfunction

需要进行修改,以便按照您希望的方式为评论开始和结束标记之间的行分配更高级别:

function! MyFoldLevel(linenum)
   let linetext = getline(a:linenum)
   if linetext =~ [put line-based comment prefix pattern here]
       let level = 20
   elseif linetext =~ '^\s*/\*'
       let level = 20
   elseif linetext =~ '^\s*\*/'
       let level = 21
   else
       if b:previous_level == 20
           let level = 20
       else
           "assuming code is space-indented with tabstop of 4
           let level = indent(a:linenum) / 4
       endif
   endif

   let b:previous_level = level
   return level

endfunction

我不希望我写的折叠方法功能完全按照书面方式工作。但他们确实指出了可行的方法。

请注意,对评论使用“20”级别只是允许折叠的任意级别,而所有(可能是较低级别的)缩进代码都可见。最后一行评论部分的“21”只是为了区别于前面的20级评论,以便知道下一行应该被视为常规代码行。

此外,像'zc'和'zo'这样的关键操作在注释设置为远高于周围代码的水平时将无法正常工作。希望使用:set foldlevel=21之类的直接命令来显示所有注释行。

不漂亮,我希望它可以简化一点,但我认为这就是你想要的东西。

实际上,考虑到这一点,我想你会希望任何评论块的第一行与非评论行处于相同的水平,只需要在同一块中的后续评论行更高级别让他们“折叠”到起始评论行。在我给出的代码中,如果它起作用或接近完成工作,我认为vim会将前面的非注释行后面的注释行折叠 all ,这不是你想要的,但是遗憾的是,我没有更多的时间专注于这个小谜题。 。 。我做过这种自定义折叠很多次,并且在获得我想要的东西时总是会有一些试验和错误。

答案 1 :(得分:1)

基于语法的折叠可能是比我在不同的问题答案中建议的基于expr的方法更好的方法。查看:h fold-syn了解详情。我认为基于c的折叠可能已经有了一些很好的解决方案。不知道它有多好,但这里是一个支持基于语法的折叠的c语法文件: http://www.vim.org/scripts/script.php?script_id=234 另一个: http://www.vim.org/scripts/script.php?script_id=925

上述解决方案完全基于语法,不涉及使用缩进来确定折叠级别。但是如果需要,您可以修改基于语法的折叠以通过缩进区域进行主折叠。如果你基于语法元素缩进,结果可能是相同的。

这是一个提示,展示如何折叠c风格的评论(而不是实际的代码)  http://vim.wikia.com/wiki/Fold_C-style_comments

答案 2 :(得分:1)

我和你的请求一样,这是我不完美的解决方案

我的制造商对是#< ===和#===> (或#region和#endregion在pycharm中)

let b:inBlock=0
let b:lastLineNum=0
let b:lastLevel=0
let b:lastGoodLine=0
let b:lastGoodBlock=0
let b:startFoldingMark='^\s*.\?#<==*\|^\s*.\?#region'
let b:endFoldingMark='^\s*.\?#=*=>\|^\s*.\?#endregion'
function! MyFold(linenum)
    let linetext = getline(a:linenum)
    let level     = indent(a:linenum)   / &shiftwidth
    "the first line have 0 fold level
    if (a:linenum == 1)
        if linetext =~ b:startFoldingMark
            let b:inBlock = 1
            let b:lastLineNum=a:linenum
            let b:lastGoodLine=0
            let b:lastGoodBlock=0
            let b:lastLevel=level
            return level
        endif
        let b:inBlock=0
        let b:lastInBlock=0
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=0
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock
        return level + b:inBlock
    endif

    " not calculate from the mid of text
    if ((b:lastLineNum+1) != a:linenum)
        let level     = indent(a:linenum)   / &shiftwidth
        let lastGoodNum = a:linenum-1
        while (lastGoodNum>1 && getline(lastGoodNum) =~? '\v^\s*$' )
            let lastGoodNum -= 1
        endwhile
        if  (foldlevel(lastGoodNum)==-1)
            let b:inBlock=b:lastGoodBlock
        else
            let lastlevel = indent(lastGoodNum)   / &shiftwidth
            let lastlinetext = getline(lastGoodNum)
            let lastlinelevel = foldlevel(lastGoodNum)
            if lastlinetext =~ b:startFoldingMark
                let b:inBlock = lastlinelevel - lastlevel + 1
            elseif lastlinetext =~ b:endFoldingMark
                let b:inBlock = lastlinelevel - lastlevel - 1
            else
                let b:inBlock = lastlinelevel - lastlevel
            endif
        endif
    endif

    "blank lines have undefined fold level
    if getline(a:linenum) =~? '\v^\s*$'
        let b:lastLineNum=a:linenum
        let b:lastLevel=-1
        return -1
    endif

    "if next line is a start of new marker block, inBlock ++
    if linetext =~ b:startFoldingMark
        let b:lastLineNum=a:linenum
        if (b:lastLevel != -1)
            let b:lastGoodLine=a:linenum
            let b:lastGoodBlock=b:inBlock
        endif
        let b:lastLevel=level + b:inBlock - 1
        return level + b:inBlock - 1
    "if next line is an end of new marker block, inBlock -
    elseif linetext =~ b:endFoldingMark
        let b:inBlock = b:inBlock - 1
        let b:lastLineNum=a:linenum
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
        let b:lastLevel=level + b:inBlock + 1
        return level + b:inBlock + 1
    endif

    let b:lastLineNum=a:linenum
    if (b:lastLevel != -1)
        let b:lastGoodLine=a:linenum
        let b:lastGoodBlock=b:inBlock
    endif
    let b:lastLevel=level + b:inBlock
    return level+b:inBlock
endfunction

现在,我可以在使用缩进折叠方法时保留所有功能, 我可以折叠每个#&lt; =,#=&gt;标记块, 而且,线条&#39;每个区块仍保留缩进折叠关系。

在此功能中,我避免使用&#34; a1&#34;,&#34; s1&#34;和&#34; =&#34; level,这将导致此函数的迭代,并且对于大文件可能会很慢。 但是,当您更新行时,折叠级别的计算可能不正确(因为vim可能不会从开头更新所有折叠级别,因此具有不正确的inBlock值)

您可以使用 zx 手动更新折叠级别。

https://github.com/Fmajor/configs

了解详情