10

我想设置两种折叠方法

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

    :set foldmethod=marker

    :set foldmarker=/*,*/

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

4

3 回答 3

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

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

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

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

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

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

于 2011-05-11T21:59:57.383 回答
2

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

我的制造商对是 #<=== 和 #===> (或 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上查看更多信息

于 2016-06-09T15:30:37.503 回答
1

与我在对您的问题的不同答案中建议的基于 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 样式的注释(不是实际的代码) http://vim.wikia.com/wiki/Fold_C-style_comments

于 2011-05-11T23:16:22.203 回答