两种折叠方式同时进行

发布于 2024-11-06 18:51:20 字数 263 浏览 0 评论 0原文

我想设置两种折叠方法

  1. :set Foldmethod=indent 并保留其所有功能
  2. 隐藏注释

    :设置foldmethod=marker

    :setfoldmarker=/*,*/

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

I'd like to set two methods for folding

  1. :set foldmethod=indent and retain all its features
  2. hiding comments with

    :set foldmethod=marker

    :set foldmarker=/*,*/

I found out that this is not possible. Is it possible to achieve the desired folding and set this in .vimrc or to use some script or plugin for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暮年慕年 2024-11-13 18:51:20

同一缓冲区中不可能有不同的折叠方法类型。 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 会将所有注释行折叠到前面的非注释行后面,这不是您想要的,但是不幸的是,我没有更多的时间来解决这个小难题。 。 。我已经做过很多次这种定制折叠了,通常总是要经过一些尝试和错误才能得到我想要的东西。

It's not possible to have different foldmethod types in same buffer. How is Vim to know that there are some comments at same indent level as other text that you want to treat as being of a different (higher numbered) level?

I'm sure you can achieve what you want by setting foldmethod to 'expr'. This is most flexible way of doing folds in Vim but can get complicated (and/or slow) depending on what you want. I think it would work fairly easily for your use case, though.

First, somewhere in your vimrc or vimscripts you need to make sure that foldexpr is getting defined for the filetype in question.

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

and you then have to flesh out your foldexpr function so that it assigns levels in a way that results in behavior you want. Something like the code below might come close to working in cases where each comment line has prefix symbol (i.e., not in your case), but I expect it needs some tweaks. h: fold-expr would be a good place to look for help:

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

Would need to be modified to assign higher level for lines between comment start and end markers the way you want:

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

I don't expect the foldmethod functions I've written would work exactly as written. But they do point the way to something that would work.

Note that use of level of '20' for comments is just arbitrary level that allows them to be folded while all (presumably lower-leveled) indented code could be visible. '21' for last line of comment section is just to differentiate it from the previous lines of comments that have level of 20, to know that next line should be treated as regular line of code.

Also, key ops like 'zc' and 'zo' will not work quite right on comments when they're set to level much higher than surrounding code. Would want to use direct command like :set foldlevel=21 to show all comment lines.

Not pretty, and I expect it could be simplified a little, but something like this is what I think is required for what you want.

Actually, thinking through this a little more, I think you would want the first line of any comment blocks to be at same level as if it were a non-comment line, only subsequent comment lines in same block would need to be of higher level to have them "fold" into the starting comment line. In the code I gave, if it works or comes close to working at all, I think vim would fold all the comment lines behind the preceding non-comment line, which isn't what you want, but I unfortunately don't have more time to devote to this little puzzle. . . I've done this sort of custom-folding quite a few times and generally always have a little bit of trial and error in getting exactly what I want.

临走之时 2024-11-13 18:51:20

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

我的制造商对是 #<=== 和 #===> (或者像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*

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

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

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

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

) 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*

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

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

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

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

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

I have the same requests as yours, here is my not perfect solution

my maker pair is #<=== and #===> (or #region and #endregion as in 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*

now, i can keep all the features when using indent fold method,
and i can fold each #<=, #=> marker block,
also, the lines' indent folding relations are still kept in each block.

In this function, i avoid using "a1", "s1" and "=" level, which will cause iteration for this function and may be slow for large files.
However, when you update lines, the calculation of fold level may be incorrect (because vim may not update all fold level from beginning, and thus have incorrect inBlock value)

you can use zx to update fold levels manually.

see more at https://github.com/Fmajor/configs

) 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*

now, i can keep all the features when using indent fold method,
and i can fold each #<=, #=> marker block,
also, the lines' indent folding relations are still kept in each block.

In this function, i avoid using "a1", "s1" and "=" level, which will cause iteration for this function and may be slow for large files.
However, when you update lines, the calculation of fold level may be incorrect (because vim may not update all fold level from beginning, and thus have incorrect inBlock value)

you can use zx to update fold levels manually.

see more at https://github.com/Fmajor/configs

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

now, i can keep all the features when using indent fold method,
and i can fold each #<=, #=> marker block,
also, the lines' indent folding relations are still kept in each block.

In this function, i avoid using "a1", "s1" and "=" level, which will cause iteration for this function and may be slow for large files.
However, when you update lines, the calculation of fold level may be incorrect (because vim may not update all fold level from beginning, and thus have incorrect inBlock value)

you can use zx to update fold levels manually.

see more at https://github.com/Fmajor/configs

基于语法的折叠可能是比我在问题的不同答案中建议的基于表达式的方法更好的方法。检查 :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

Syntax-based folding may be a better way to get what you want than the expr-based method I suggested in different answer to your question. Check :h fold-syn for more info. I think there may be some good solutions already out there for c-based folding. Don't know how good it is, but here is a c-syntax file with support for syntax-based folding:
http://www.vim.org/scripts/script.php?script_id=234
and another:
http://www.vim.org/scripts/script.php?script_id=925

The solutions above are entirely syntax-based, don't involve using indents to determine fold levels. But you could modify syntax-based folding to do the main folding by indented regions if you wanted. If you indent based on syntactical elements the result might be the same anyway.

Here's a tip that shows how to just fold c-style comments (not the actual code)
http://vim.wikia.com/wiki/Fold_C-style_comments

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文