【问题标题】:Two fold methods at the same time两种折叠方式同时进行
【发布时间】:2011-08-23 14:49:04
【问题描述】:

我想设置两种折叠方法

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

    :set foldmethod=marker

    :set foldmarker=/*,*/

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

【问题讨论】:

    标签: vim folding


    【解决方案1】:

    我和你有同样的要求,这是我的不完美的解决方案

    我的 maker 对是 #(或 pycharm 中的 #region 和 #endregion)

    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
    

    现在,我可以在使用缩进折叠方法时保留所有功能, 我可以折叠每个 # 标记块, 此外,行的缩进折叠关系仍然保留在每个块中。

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

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

    https://github.com/Fmajor/configs查看更多信息

    【讨论】:

      【解决方案2】:

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

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

      这里有一个提示,展示了如何折叠 c 样式的 cmets(不是实际代码) http://vim.wikia.com/wiki/Fold_C-style_comments

      【讨论】:

        【解决方案3】:

        在同一个缓冲区中不可能有不同的折叠方法类型。 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
        

        我不希望我编写的 foldmethod 函数会完全按照编写的那样工作。但他们确实指出了可行的方法。

        请注意,对 cme​​ts 使用 '20' 级别只是允许它们被折叠的任意级别,而所有(可能是较低级别的)缩进代码都是可见的。注释部分最后一行的 '21' 只是为了将其与前几行级别为 20 的 cmets 区分开来,以了解下一行应视为常规代码行。

        此外,像“zc”和“zo”这样的关键操作在设置为比周围代码高得多的级别时,在 cmets 上将无法正常工作。希望使用像:set foldlevel=21 这样的直接命令来显示所有注释行。

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

        实际上,仔细考虑一下,我认为您希望任何注释块的第一行与非注释行处于同一级别,只有同一块中的后续注释行需要更高级别让它们“折叠”到起始注释行中。在我给出的代码中,如果它可以工作或几乎可以工作,我认为 vim 会将 all 前面的非注释行后面的注释行折叠起来,这不是你想要的,但是不幸的是,我没有更多的时间专注于这个小谜题。 . .我已经做了很多次这种自定义折叠,并且通常总是要经过一些试验和错误才能得到我想要的。

        【讨论】:

        • 是否可以将 'zo' 命令映射到 'zo' 命令按下 21 次?我注意到 zo 按更多次没有副作用。它会减慢 vim 的速度吗?
        • @xralf,也许zO 会对您有所帮助 - 它递归地打开光标下的所有折叠(同样,zC 关闭所有折叠)。
        猜你喜欢
        • 2021-05-26
        • 2012-12-11
        • 2017-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多