是否有折叠vimrc文件的最佳实践


21

我最近意识到我vimrc现在已经超过400行(IMO太多了,我会尽量减少它),并且为了使其更易于浏览,阅读和编​​辑,我决定研究一下vim中的可折叠概念(我不熟悉)

  • 我尝试将folding方法设置为,indent但是我不喜欢结果(这太混乱了,主要是因为我的很大一部分vimrc都没有真正缩进)。
  • 我也尝试设置foldmethodexprsyntax但无法正确折叠任何东西。
  • 在这里,diff用作折叠方法似乎无关紧要。(或者如果我不明白如何使用它)
  • 因此,marker由于我在文件中发现了“ "{{{和” "}}}标记,因此目前我使用的方法并不完全令我满意。

因此,我想知道是否存在有关正确折叠的最佳实践或通用准则vimrc

注意1:众所周知,SO不是论坛,也不是收集个人意见,这也不是我想要的:当然,我猜有些人有他们的偏好,但我想知道为什么使用例如,标记比使用缩进可提高可读性。

注2:我的主要目标也是使自己vimrc尽可能清晰,因此,如果存在其他最佳做法来创造一个好的,vimrc我对此很好奇。

编辑1:我应该明确指出,我的vimrc内容已经细分为(主要是

  • 常规选项
  • 插件(每个插件及其配置包含一个小节)
  • 映射
  • 导航(也包含小节)
  • 颜色
  • 等等...

正是这种结构让我想到了折叠:我觉得能够只在特定点上输出我感兴趣的部分非常方便。

编辑2:vimrc在几个文件中提及细分的答案是有效的,但出于个人喜好,我宁愿使用折叠,因为我认为在包含我的dotfile的git repo中仅维护一个文件会更容易。那只是个人喜好,我知道也可以使用这种方法,但是我更喜欢使用折叠。


我认为使用"{{{是最“类似于vim”的处理方式,solarized插件使用了这种方式,尽管它可能很嘈杂,但它为您提供了设置手动折叠的最标准方式
icc97

Answers:


22

我在表格的底部有以下vimrc模式行,这些行是从表格的作者Godlygeek复制而来的:

"" vim:fdm=expr:fdl=0
"" vim:fde=getline(v\:lnum)=~'^""'?'>'.(matchend(getline(v\:lnum),'""*')-2)\:'='

这将使任何以2+ "' 开头的行都折叠。越多",折痕越深。这使您可以根据需要细分部分。


我现在无法测试,但这似乎是我的理想解决方案!感谢分享!
statox

一些解释:getline(v:lnum)返回由行号(v:lnum)给出的行的字符串;=〜表示正则表达式匹配;'^“”'表示所有行均以两个“ s”开头; matchend(getline(v:lnum),'“” *')-2计数额外的“”,这意味着“”“将折叠为1级,” “”“将以第2级折叠,依此类推; getline(v:lnum)=〜'^”“'返回true或false,具体取决于以两个”或否“开头的v:lnum行;如果为true,则将fde设置为>extra number of "(起始级别,由该行<后面的数字所坐)或'='(使用上一行的级别),其含义可以在fold-expr
van abel

最近VIM更新1517年8月1日)之后,我得到“此配置”,而处理模式行检测错误。”
阿波罗

9

最好先在自己的类别中定义自己的类别.vimrc(例如带有子列表和子子列表的列表),然后将所有插件/设置/功能添加到相应的类别中。结合定制折叠功能,可以很好地发挥作用:

例

上面的示例显示了可能对我的结构有所帮助的类别.vimrc。它使用以下定制的折叠设置:

""""""""""""""""""""""""
"  THIS IS A CATEGORY  "
""""""""""""""""""""""""
"" Autofolding .vimrc
" see http://vimcasts.org/episodes/writing-a-custom-fold-expression/
""" defines a foldlevel for each line of code
function! VimFolds(lnum)
  let s:thisline = getline(a:lnum)
  if match(s:thisline, '^"" ') >= 0
    return '>2'
  endif
  if match(s:thisline, '^""" ') >= 0
    return '>3'
  endif
  let s:two_following_lines = 0
  if line(a:lnum) + 2 <= line('$')
    let s:line_1_after = getline(a:lnum+1)
    let s:line_2_after = getline(a:lnum+2)
    let s:two_following_lines = 1
  endif
  if !s:two_following_lines
      return '='
    endif
  else
    if (match(s:thisline, '^"""""') >= 0) &&
       \ (match(s:line_1_after, '^"  ') >= 0) &&
       \ (match(s:line_2_after, '^""""') >= 0)
      return '>1'
    else
      return '='
    endif
  endif
endfunction

""" defines a foldtext
function! VimFoldText()
  " handle special case of normal comment first
  let s:info = '('.string(v:foldend-v:foldstart).' l)'
  if v:foldlevel == 1
    let s:line = ' ◇ '.getline(v:foldstart+1)[3:-2]
  elseif v:foldlevel == 2
    let s:line = '   ●  '.getline(v:foldstart)[3:]
  elseif v:foldlevel == 3
    let s:line = '     ▪ '.getline(v:foldstart)[4:]
  endif
  if strwidth(s:line) > 80 - len(s:info) - 3
    return s:line[:79-len(s:info)-3+len(s:line)-strwidth(s:line)].'...'.s:info
  else
    return s:line.repeat(' ', 80 - strwidth(s:line) - len(s:info)).s:info
  endif
endfunction

""" set foldsettings automatically for vim files
augroup fold_vimrc
  autocmd!
  autocmd FileType vim 
                   \ setlocal foldmethod=expr |
                   \ setlocal foldexpr=VimFolds(v:lnum) |
                   \ setlocal foldtext=VimFoldText() |
     "              \ set foldcolumn=2 foldminlines=2
augroup END

要定义自己的类别和子类别,请使用以下语法:

""""""""""""""
"  Category  "
""""""""""""""
"" Subcategory
""" Subsubcategory
" Just a comment, gets ignored no matter where

如果您使用vim片段(例如,使用UltiSnips),则可以非常容易地创建顶级类别:只需展开vim片段提供的boxbbox片段(编写boxbbox按扩展触发器)。

要通过两次按空格来更快地打开和关闭折叠,请执行以下操作:

let mapleader = "\<space>"
" Toggle folds
nnoremap <silent> <leader><Space> @=(foldlevel('.')?'za':"\<Space>")<CR>
vnoremap <leader><space> zf

这样,您.vimrc就可以轻松地导航并具有良好的结构。


+1为精美的动画gif :)很好奇,您用来显示键入的键是什么?
mMontu '16

@mMontu:我使用screenkey来显示按键,并使用gtk-recordmydesktop对其进行记录(均在Debian仓库中)。使用5fps时,45秒的剪辑比MiB少。然后将其在线转换为gif(这是图片质量完美之前失真的来源)。
cbaumhardt '16

7

我将我的主文件vimrc用作指向其他几个分类文件的链接,并按需采购每个文件,例如,一个文件中的Vim选项,另一个文件中的插件设置。

"--- Vim Options
source ~/.vim/config/vim_options.vim

"--- Here Be Functions!
" (need to be sourced before stuff that uses 'em)
runtime! functions/*.vim

"--- Key Mapping
source ~/.vim/config/key_mapping.vim

"--- Folding
source ~/.vim/config/folding.vim

"--- Autocmds
source ~/.vim/config/autocmds.vim

"--- We Are Plugged In!
source ~/.vim/config/plugins.vim

" vim: ft=vim fdm=marker

作为对OP问题的更直接答案,我确实使用了标记方法,但是在大多数情况下,它以右侧隔开间隔,并且类别比单个类别多。我分别做每个插件。


我在我的问题中忘记了这一点:我不喜欢将“分开”到vimrc不同的文件中,因为(IMO)会增加复杂性并使其更难维护。关于折叠,“以一定间隔移到右侧”是什么意思?
statox

我的意思是" {{{那里的空间与您的一样多,textwidth因此标记位于右边缘附近。我在folding.vim文件中也有一个个性化的FoldText函数。我更喜欢单独的文件,以便我的git repo每次提交只能使用一种特定类型的mod。
2015年

7

您可以说“最佳实践”主要是一个见解,:)但是有两种方法(1)显而易见,并且(2)可以应用于所有配置文件,不仅限于Vim:按逻辑部分折叠和小节(或者更深的部分,如果您觉得很勇敢),并将您的配置分成几个较小的文件并对其进行:source-ing操作。

我个人更喜欢折叠,因为它使事情更容易访问,同时仍然给我一些层次。autocmd在最内层折叠功能和s也是一个好主意,因为它们构成了“自然的”逻辑单元。 marker对于所有这一切,折叠是最有意义的,因为逻辑层次结构不一定反映到缩进级别或语法突出显示中。我还增加了foldcolumn,这给了我一个视觉上的提示:

# vim: filetype=vim foldmethod=marker foldlevel=0 foldcolumn=3

附带说明一下,此foldtext功能(IIRC的Drew Neil对类似功能的修改)对我来说比默认值有意义:

function! MyFoldText()
    let line = getline(v:foldstart)

    let nucolwidth = &foldcolumn + &number * &numberwidth
    let windowwidth = winwidth(0) - nucolwidth - 3
    let foldedlinecount = v:foldend - v:foldstart

    " expand tabs into spaces
    let chunks = split(line, "\t", 1)
    let line = join(map(chunks[:-2], 'v:val . repeat(" ", &tabstop - strwidth(v:val) % &tabstop)'), '') . chunks[-1]

    let line = strpart(line, 0, windowwidth - 2 - len(foldedlinecount))
    let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - 1
    return line . '...' . repeat(' ', fillcharcount) . foldedlinecount . ' '
endfunction
set foldtext=MyFoldText()

使用另一种方法(拆分文件),主要问题是查找内容并从一个文件切换到另一个文件。解决这两个问题的一种很好的方法是使用CtrlSFCtrlP或类似的插件。但是无论如何,您可能已经在使用其中之一。


所以你去吧marker。确实,自定义foldcolumn是一件好事,我将看看哪种值最适合我的需求。另外,我也分享了您对拆分文件CtrlSF的看法,但是即使我很满意,我也不知道我会看看它CtrlP
statox

还可以请您说明如何使用自定义折叠方法吗?我尝试设置fdmfoldtextMyFoldText()但这似乎不是使用它的正确方法。
statox

@statox CtrlSF最适合与agack一起使用,而agack实质上是的专用版本grepfoldtext不是自定义折叠方法,而是一种用于更改折叠文本外观的功能。我的代码段的最后一行显示了如何使用:set foldtext=MyFoldText()
lcd047

2

基本最佳实践:

  • 分为几个部分:

    • 外挂程式
    • 设定值
    • 重新绑定
  • 评论每个部分/重新绑定

  • (备份您.vimrc_vimrc在Github上)

只是我个人的喜好。也许没有太多帮助。


我个人不使用折叠功能,而您则不需要。只是组织您的vimrc,一切都应该很好。
古斯塔夫·布洛姆奎斯特

我的vimrc已经按部分进行了组织(常规选项,插件,映射,导航,颜色等)。能够折叠一个部分(或子部分)的事实实际上集中于您正在编辑/寻找的内容。
statox

好的。对不起,不好的回答。
Gustav Blomqvist

这不是一个不好的答案,我也因没有给出足够详细的问题而感到内
,,不必为难;

2

受@PeterRincker的答案启发,我精心设计了以下内容以使用ATX样式标头。将其添加到您的末尾.vimrc

"# Folding

" Fold with ATX style headers - "# is H1, "## is H2, and so on
" vim:fdm=expr:fdl=0
" vim:fde=getline(v\:lnum)=~'^"#'?'>'.(matchend(getline(v\:lnum),'"#*')-1)\:'='

1

如果您拥有像我这样的大型功能,则可以使用此功能折叠功能:

fun! MyFoldLevel(linenum)
    if ! exists('w:nextline')
        let w:nextline = 0
        let w:insideafun = 0
    endif

    if w:nextline == 1
        let w:nextline = 0
        let w:insideafun = 0
    endif

    let l:line = getline(a:linenum)

    if l:line =~# '^[[:space:]]*fun'
        let w:insideafun = 1
        return '>1'
    elseif l:line =~# '^[[:space:]]*endf'
        let w:nextline = 1
        return '<1'
    endif

    if w:insideafun == 1
        return 1
    else
        return 0
    endif
endfun

并将这个modeline添加到您的vimrc中:

" vim:fde=MyFoldLevel(v\:lnum):fdm=expr:

0

扩展了@Peter Rincker和@ go2null的想法。如果不想在Vim modeline中设置折叠选项。您可以使用以下autocmd来设置折叠方法和折叠表达式。

augroup vim_folding
    autocmd!
    autocmd FileType vim set foldmethod=expr foldlevel=0
    " note that double quote in foldexpr has to be escaped with backslash
    autocmd FileType vim set foldexpr=getline(v:lnum)=~'^\"#'?'>'.(matchend(getline(v:lnum),'\"#*')-1):'='
augroup END

我做了一些小的修改,以使原始答案能够像常规的vim命令一样工作(无需转义冒号,但需要转义双引号)。

如果您不喜欢长foldexpr字符串,我们可以为此定义一个函数:

function! VimFolds(lnum)
    let s:cur_line = getline(a:lnum)

    if s:cur_line =~ '^"#'
        return '>' . (matchend(s:cur_line, '"#*')-1)
    else
        return '='
    endif

endfunction

然后将autocmd行替换foldexpr

autocmd FileType vim set foldexpr=VimFolds(v:lnum)
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.