2011-09-29 52 views
12

有没有办法让我可以设置vim来自动折叠ruby源文件,但只在方法级别折叠,而不管它们被定义的级别如何?vim中的自动ruby折叠

所以,当我把它必倍:

class MyClass 
    def method 
    ... 
    end 
end 

而且,当我有:

module FirstModule 
    module SecondModule 
    class MyClass 
     def method 
     ... 
     end 
    end 
    end 
end 

我已经使用foldmethod =语法和各种倍的水平,但尝试它并不需要考虑方法定义的深度。

此外,我不想在方法内部没有折叠(如果块,每个块等)。

我认为foldmethod = expr会是我最好的选择,但我还没弄清楚fold表达式是如何工作的,而vim的帮助并不是很有启发性。

回答

11

您好,我相信使用expr的方法是正确的!

您可以使用该文件的语法结构来评估您自己的syntax样式折叠。在我.vimrc产生预期的行为如下:

function! RubyMethodFold(line) 
    let line_is_method_or_end = synIDattr(synID(a:line,1,0), 'name') == 'rubyMethodBlock' 
    let line_is_def = getline(a:line) =~ '\s*def ' 
    return line_is_method_or_end || line_is_def 
endfunction 

set foldexpr=RubyMethodFold(v:lnum) 

一些注意事项:

我不知道,如果最后一个参数synID应该01。这是决定您是否在所提供的位置获得最上面的透明非透明元素的语法信息的参数。当没有透明元素时,参数不起作用。在我试过的简单例子中,它没有引起任何问题,但它可能。

值得一提的是,line_is_def正则表达式可能太宽大了。在这种情况下返回-1可能会更好,因此与正则表达式匹配的行仅在折叠方法块旁边折叠。更严格的正则表达式也可以工作。

如果您感到很沮丧,您可以扩展此功能,并返回rubyClassrubyModule元素的单独foldlevel。

如果您决定沿着这条路线走下去,有一些useful custom functions in my .vimrc用于内省语法元素和hilighting。当他们被映射到一个快速使用的键排序时,他们是最方便的:

nnoremap g<C-h> :echo GetSynInfo()<CR> 

请让我知道这是否适合您!弄清楚是很有趣的。此外,对于它的价值,:help 'foldexpr'对细节很重要,:help 'fold-expr'更有帮助,甚至在顶部有一些例子。

+2

这是一个很好的答案。这看起来是一个正确的解决方案,或者至少是一个很好的起点,可以让我得到我想要的东西。我会测试一下今天晚些时候的工作方式,并接受你的答案。你的vimrc看起来也是一个很好的学习资源,特别是你定义的所有功能。谢谢。 – adivasile

+0

非常欢迎您!快乐vimming! –

+0

顺便说一下,我很想知道这是怎么解决的! –

1

通过使用zO命令,您也许能够摆脱方法内部折叠的解决方案。 zO递归地打开折叠,所以如果你使用它而不是zo,就好像这个方法里面没有东西被折叠一样。如果你感到很沮丧,你也可以重映射zozO

+0

确实会有帮助,但主要问题仍然存在:使方法自动折叠。 – adivasile

3

您可能有这个更好的运气,特别是如果你已经有了语法高亮:

这会进入你的〜/ .vimrc

 
"" Enable folding based on syntax rules 
set foldmethod=syntax 

"" Adjust the highlighting 
highlight Folded guibg=grey guifg=blue 

"" Map folding to Spacebar 
nnoremap za 

这也是在折叠很大VIMcast:http://vimcasts.org/episodes/how-to-fold/

4

对Max Cantor的解决方案做出了改变,我的作品完美无缺,它将折叠def方法(包括end关键字)和documentations(= begin = end)块,而不管它在哪里(在一个类中或缩进)

function! RubyMethodFold(line) 
    let stack = synstack(a:line, (match(getline(a:line), '^\s*\zs'))+1) 

    for synid in stack 
    if GetSynString(GetSynDict(synid)) ==? "rubyMethodBlock" || GetSynString(GetSynDict(synid)) ==? "rubyDefine" || GetSynString(GetSynDict(synid)) ==? "rubyDocumentation" 
     return 1 
    endif 
    endfor 

    return 0 
endfunction 

set foldexpr=RubyMethodFold(v:lnum) 

set foldmethod=expr 

感谢Max Cantor为他的帮助方法打印出语法信息。

让我解释一下线这条线:

最重要的线将是第二行那里得到语法元素的verious水平的堆在一条线上。 所以如果你有一条像def methodname这样的行,在它之前有空格或制表符,它总是会在第一个非空白字符处得到堆栈。 Max Cantor的解决方案存在的问题是,他的代码只会打印出该行第一列中找到的最低语法元素,因此它总是会返回一些随机的元素,比如我们不关心的“rubyContant”。

所以通过使用match(getline(a:line), '^\s*\zs')我们可以将光标移动到第一个非空白字符的列,这样我们就可以获得更准确的堆栈图。 +1,因为匹配是零索引的。

然后剩下的就和GetSynInfo方法类似,我们通过堆栈循环并匹配我们想要的元素,然后返回1,所以它们都在同一个折叠级别上,其余的都是0。

就是这样,工作折叠expr的功能只会折红宝石定义方法:)

享受和有一个愉快的一天!

+1

您的答案看起来很有希望,但不幸的是,当我尝试它时,什么都没有发生。看起来解决方案错过了这些函数的定义:'GetSynString'和'GetSynDict'。你能不能照顾他们?谢谢 –

1

我制作了vim-ruby-fold插件,用于简单的红宝石折叠方法。我希望它可以帮助人们。