将vim折叠为一行,类似于Atom或Sublime Text


13

我喜欢Atom和Sublime Text处理行折叠的方式,其中每个折叠的第一行都是可见的(语法高亮显示完整),并且在该行的末尾附加了一个标记来指示折叠。

请参阅下面的屏幕快照,比较Vim的缩进折叠(顶部)与Atom的折叠(底部):Vim与Atom代码折叠

Vim为每折指定两行。第一行用作标题,第二行描述有关折页的一些信息(折页内的行数和文本)。

Atom仅使用一行,并在该行的末尾使用一个小标记来指示折叠,并在左侧的行号中添加颜色。Atom的折叠样式使用的屏幕空间更少,但仍可以传达我真正需要的所有信息。

我偏爱Atom折叠样式。我认为,这看起来更干净,更一致,尤其是当连续列出多个方法或属性时(如上图所示)。

有没有办法大致估算Vim中Atom的折叠样式?


1
我认为这是因为您的折叠实际上并不是从包含开括号的行开始的。Vim仅在折叠开始的行上使用折叠文本。例如,请参见C中的括号位置如何影响它:imgur.com/3h70dPf,wfCLPm7
muru

但这是Python,不包含花括号(from __future__ import braces)...您是如何配置折叠的?并且您可以粘贴此代码段(或其他演示问题的代码段)吗?Vim可以折叠成一行,但是正如一位大师所说,您的折叠起步较晚。
马丁·图尔诺伊

@Carpetsmoker括号仅用于说明折叠开始的位置。可以在Haskell上看到相同的效果。
muru

@MikeHearn我以前的回答是完全错误的。我已经对其进行了更新,以包括该问题的解决方案。
丰富

Answers:


12

两行与一行

在Vim中,折痕内的所有行都将折叠为单行,然后该'foldtext'选项确定这些线的提要(通常是破折号,折线的数量以及第一(或全部)行的内容)。

在您的示例中,在Vim中,仅{...}参数块本身被折叠;上面的行(使用参数)不是折叠的一部分。相反,在另一个编辑器中,使用参数的那一行属于该折叠,而其折叠文本(使用Vim术语)是该行的内容以及附加的标记。

适应

在Vim中,可以通过不同的方式生成折叠(请参见参考资料:help fold-methods),并且取决于'filetype'缓冲区的大小。将上述行包含在折叠中的难度取决于此;与确认:setlocal foldmethod?。随着缩进折叠,有什么可以影响; 您必须切换到另一种方法。对于语法折叠,这将意味着修改语法定义,并且可能非常棘手。如果使用表达式,将会带来更多的运气,但这仍然意味着理解和改变逻辑。(文件类型插件作者不太可能提供配置来影响此设置。)

折线的语法高亮显示

不幸的是,这根本不可能。Vim始终Folded对整个折叠线使用高光组。您可以通过中的:highlight命令进行调整~/.vimrc,但是语法的个体差异将丢失。


5

Vim已经将折叠显示为一行。但是,在Vim的indent折叠中,所有具有相同缩进的行都包含在折叠中。因此,在屏幕截图中,您所指的“标题”行(例如,以开头的那一行collection_base_url不在折叠内。

通过使用Vim可以实现类似于Atom的折叠方式foldexpr foldmethod

" Finds the indent of a line. The indent of a blank line is the indent of the
" first non-blank line above it.
function! FindIndent(line_number, indent_width)
    " Regular expression for a "blank" line
    let regexp_blank = "^\s*$"

    let non_blank_line = a:line_number
    while non_blank_line > 0 && getline(non_blank_line) =~ regexp_blank
        let non_blank_line = non_blank_line - 1
    endwhile
    return indent(non_blank_line) / a:indent_width
endfunction

" 'foldexpr' for Atom-style indent folding
function! AtomStyleFolding(line_number)
    let indent_width = &shiftwidth

    " Find current indent
    let indent = FindIndent(a:line_number, indent_width)

    " Now find the indent of the next line
    let indent_below = FindIndent(a:line_number + 1, indent_width)

    " Calculate indent level
    if indent_below > indent
        return indent_below
    elseif indent_below < indent
        return "<" . indent
    else
        return indent
    endif
endfunction

set foldexpr=AtomStyleFolding(v:lnum)
set foldmethod=expr

这定义了一个fold表达式(请参阅参考资料:help fold-expr),如下所示:

  • 对于紧缩行之前的行,它返回紧随其后的块的缩进。
  • 对于缩进的行,它返回缩进。(除以shiftwidth,因此每个缩进级别将返回值增加1)
  • 对于缩进行的末尾的行,它返回一个string "<N",其中N设置为缩进。这告诉Vim 该行完成 N级折叠。

更新资料

@alxndr在评论中询问是否可以扩展它以将Ruby的outdented end包含在折叠中。您可以先" Calculate indent level用以下内容替换该部分:

if indent_below > indent
    return indent_below
elseif getline(a:line_number) =~ '^\s*end\s*$'
    return "<" . (indent + 1)
else
    return indent
endif

实际上,这不是最可靠的解决方案(例如,如果end语句位于分号后的同一行,它将失败。)您可以调整正则表达式和周围的代码以解决此问题,但是由于您现在处在解析文件实际语法的领域内,因此我认为在找到一个好的解决方案之前,事情可能会变得更加复杂。


很棒的方法。可以将这个答案推广到还可以说是Ruby的Ruby end吗?
alxndr

1
@alxndr我已经通过一些讨论来编辑答案。
Rich

@Rich:我还发现Sublime文本折叠...非常有用,并且在行尾仅显示一个标记作为折叠的文本块的符号,与在vim中突出显示整个文本块的第一行相比,分散注意力的程度较小。我尝试使用vim的默认折叠行为在上面折叠,简单不起作用。如何使用python在文本块的第一行结尾处打上一个标记呢?我应该问一个新问题吗?我只是再次测试您的弃牌率,使用缩进线确实可以很好地工作。超级谢谢。
Tuyen Pham

这真太了不起了!我一直在寻找可以进行组织模式(如折叠)的东西,这很有帮助!
priomsrb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.