Vim 同时采用两种方法
我想设置两种折叠方法Vim 同时采用两种方法,vim,folding,Vim,Folding,我想设置两种折叠方法 :设置foldmethod=indent并保留其所有功能 使用隐藏评论 :设置foldmethod=marker :设置foldmarker=/*,*/ 我发现这是不可能的。是否可以实现所需的折叠并在.vimrc中进行设置,或者为此使用一些脚本或插件?在同一缓冲区中不可能有不同的折叠方法类型。Vim如何知道有一些注释与其他文本具有相同的缩进级别,您希望将它们视为不同(编号更高)级别的注释 我相信通过将foldmethod设置为“expr”,您可以实现您想要的。这是在Vim中
:设置foldmethod=indent
并保留其所有功能:设置foldmethod=marker
:设置foldmarker=/*,*/
我发现这是不可能的。是否可以实现所需的折叠并在
.vimrc
中进行设置,或者为此使用一些脚本或插件?在同一缓冲区中不可能有不同的折叠方法类型。Vim如何知道有一些注释与其他文本具有相同的缩进级别,您希望将它们视为不同(编号更高)级别的注释
我相信通过将foldmethod设置为“expr”,您可以实现您想要的。这是在Vim中进行折叠的最灵活的方法,但根据您的需要可能会变得复杂(和/或缓慢)。不过,我认为它对于您的用例来说相当容易
首先,在vimrc或vimscripts中的某个地方,您需要确保为所讨论的文件类型定义了Folderxpr
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”只是一个任意级别,允许它们折叠,而所有(可能级别较低的)缩进代码都可以看到“注释的最后一行”部分只是为了将其与之前级别为20的注释行区分开来,以便知道下一行应被视为常规代码行
另外,当注释的级别设置为比周围代码高得多时,像“zc”和“zo”这样的关键操作将不能很好地处理注释。要使用直接命令,如:set foldlevel=21
,以显示所有注释行
不漂亮,我希望它可以简化一点,但我认为这是你想要的东西所必需的
实际上,再仔细考虑一下,我想你会希望任何注释块的第一行与非注释行处于相同的级别,只有同一块中的后续注释行需要具有更高的级别才能“折叠”到起始注释行中。在我给出的代码中,如果它工作或接近工作,我认为vim会将所有注释行折叠到前面的非注释行后面,这不是您想要的,但不幸的是,我没有更多的时间来解决这个小难题。我已经做过很多次这种自定义折叠,通常在得到我想要的东西时会有一些尝试和错误。基于语法的折叠可能比我在不同的问题答案中建议的基于expr的方法更好。查看
:h fold syn
了解更多信息。我认为基于c的折叠可能已经有了一些很好的解决方案。不知道它有多好,但这里有一个支持基于语法的折叠的c-syntax文件:
还有一个:
上述解决方案完全基于语法,不涉及使用缩进来确定折叠级别。但是,如果需要,可以修改基于语法的折叠,以按缩进区域进行主折叠。如果基于语法元素缩进,结果可能是相同的
这里有一个技巧,展示了如何折叠c风格的注释(而不是实际的代码)
我和你有同样的要求,这是我不完美的解决方案 我的生成器对是#(或pycharm中的#region和#endregion)
设b:inBlock=0
设b:lastLineNum=0
设b:lastLevel=0
设b:lastGoodLine=0
设b:lastGoodBlock=0
设b:startFoldingMark='^\s*\?\\\\\\\\\\\s*\?\\\'endregion'
功能!MyFold(linenum)
让linetext=getline(a:linenum)
let level=缩进(a:linenum)/&shiftwidth
“第一行有0个折叠级别
如果(a:linenum==1)
如果linetext=~b:startFoldingMark
设b:inBlock=1
设b:lastLineNum=a:linenum
设b:lastGoodLine=0
设b:lastGoodBlock=0
设b:lastLevel=level
返回水平
恩迪夫
设b:inBlock=0
设b:lastInBlock=0
设b:lastLineNum=a:linenum
设b:lastGoodLine=0
设b:lastGoodBlock=b:inBlock
设b:lastLevel=level+b:inBlock
返回级别+b:内锁
恩迪夫
“不从文本中间计算
如果((b:lastLineNum+1)!=a:linenum)
let level=缩进(a:linenum)/&shiftwidth
设lastGoodNum=a:linenum-1
而(lastGoodNum>1&&getline(lastGoodNum)=~?'\v^\s*$)
设lastGoodNum-=1
循环结束
if(foldlevel(lastGoodNum)=-1)
设b:inBlock=b:lastGoodBlock
其他的
设lastlevel=indent(lastGoodNum)/&shiftwidth
让lastlinetext=getline(lastGoodNum)
设lastlinelevel=foldlevel(lastGoodNum)
如果lastlinetext=~b:startFoldingMark
设b:inBlock=lastlinelevel-lastlevel+1
elseif lastlinetext=~b:endFoldingMark
设b:inBlock=lastlinelevel-lastlevel-1
其他的
设b:inBlock=lastlinelevel-lastlevel
恩迪夫
恩迪夫
恩迪夫
“空行具有未定义的折叠级别
如果getline(a:linenum)=~?'\v^\s*$'
设b:lastLineNum=a:linenum
设b:lastLevel=-1
返回-1
恩迪夫
“如果下一行是n的开头
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