Vi and Vim Asked by statox on December 20, 2020
I recently realized that my vimrc
is now more than 400 lines long (which IMO is too much I’ll try to reduce that) and to make it easier to navigate, read and edit it I decided to investigate the concept of folding in vim (which I wasn’t familiar with).
indent
but I didn’t like the result (It was too messy mostly because a great part of my vimrc
isn’t really indented). foldmethod
to expr
and syntax
but I wasn’t able to fold anything properly.diff
as folding method doesn’t seem relevant. (Or if it is I didn’t understand how to use it)marker
method which doesn’t totally satisfy me because of the "{{{
and "}}}
markers which I found “noisy” in the file.So I’d like to know if there are best practices or common guidelines about properly folding a vimrc
.
Note 1: As we all know SO isn’t a forum and isn’t made to collect personal opinions and that’s not what I’m looking for: of course I guess some people has their preferences but I’d like to know why using markers (for example) improves the readability more than using indent.
Note 2: Also my main goal is to make my vimrc
as clear as possible so if other best practices exists to create a nice vimrc
I’m curious about it.
Edit 1: I should have precised that my vimrc
is already subdivided in sections (and sometimes subsection) the main ones being
And it’s this structure which made me thought of folding: I feel that being able to output only the section I’m interested in at a certain point is something pretty convenient.
Edit 2: Answer mentioning subdivisions of the vimrc
in several files are valid, but as a personal preference I’d rather use folding because I think it is easier to maintain only one file in the git repo containing my dotfiles. That is only a personal preference and I’m aware that is it possible to also use this approach but I’d prefer to use folding.
Expanding the idea of @Peter Rincker and @go2null. If you do not want to set the folding options in Vim modeline. You can use the following autocmd to set the folding method and folding expression.
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
I made small modifications to make the original answer to make it work as regular vim command (no need to escape colon, but double quote needs to be escaped).
If you do not like the long foldexpr
string, we can define a function for that:
function! VimFolds(lnum)
let s:cur_line = getline(a:lnum)
if s:cur_line =~ '^"#'
return '>' . (matchend(s:cur_line, '"#*')-1)
else
return '='
endif
endfunction
Then replace the autocmd line about foldexpr
to
autocmd FileType vim set foldexpr=VimFolds(v:lnum)
Answered by jdhao on December 20, 2020
Inspired by @PeterRincker's answer, I crafted the following to use ATX style headers. Add it to the end of your .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):'='
Answered by go2null on December 20, 2020
It is a good idea to first define your own categories in your .vimrc
(like a list with sublists and subsublists) and add all your plugins/settings/functions to the respective categories. Combined with customized folding this can work great:
The example above shows possible categories that I find helpful to structure my .vimrc
. It uses the following customized fold settings:
""""""""""""""""""""""""
" 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
To define your own categories and subcategories use the following syntax:
""""""""""""""
" Category "
""""""""""""""
"" Subcategory
""" Subsubcategory
" Just a comment, gets ignored no matter where
The top level category can be created really easy if you use vim-snippets (e.g. with UltiSnips): Just expand the box
or bbox
snippet provided by vim-snippets (write box
or bbox
and press the expand trigger).
To toggle folds open and closed even faster by pressing space twice:
let mapleader = "<space>"
" Toggle folds
nnoremap <silent> <leader><Space> @=(foldlevel('.')?'za':"<Space>")<CR>
vnoremap <leader><space> zf
That way you have an well structured .vimrc
which can be navigated easily.
Answered by cbaumhardt on December 20, 2020
If you have large functions like me, you can use this to fold your functions:
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
And add this modeline to your vimrc:
" vim:fde=MyFoldLevel(v:lnum):fdm=expr:
Answered by MichalH on December 20, 2020
I have the following modelines at the bottom of my vimrc
which I copied from godlygeek, the author of tabular:
"" vim:fdm=expr:fdl=0
"" vim:fde=getline(v:lnum)=~'^""'?'>'.(matchend(getline(v:lnum),'""*')-2):'='
This will make any line starting with 2+ "
's a fold. The more "
's the deeper the fold. This allows you to sub divide sections if you need.
Update: As noted in a comment below the second modeline now causes an error in Vim. Here's a note from the patch that introduced the change:
Patch 8.1.1366
Problem: Using expressions in a modeline is unsafe.
Solution: Disallow using expressions in a modeline, unless the 'modelineexpr' option is set.
And, no, you can't set 'modelineexpr'
from the modeline! You could try setting 'fde'
as above in an autocmd (e.g. autocmd Filetype vim ...
). I (B Layer) didn't test this but I did test it manually. You need to escape the "
s.
set fde=getline(v:lnum)=~'^""'?'>'.(matchend(getline(v:lnum),'""*')-2):'='
Answered by Peter Rincker on December 20, 2020
You could say that "best practice" is preeminently a matter of opinion, :) but there are two approaches that (1) make obvious sense, and (2) can be applied to all config files, not only Vim's: folding by logical sections and subsections (or even deeper, if you feel brave), and splitting your config into several smaller files and :source
-ing them.
I personally prefer folding because it makes things easier to access, while still giving me some hierarchy to pick up from. Folding functions and autocmd
s at innermost levels is also a good idea, since these make "natural" logical units. marker
folding makes most sense for all this, because logical hierarchies are not necessarily reflected into indent levels, or into syntax highlighting. I also increase foldcolumn
, which gives me a visual hint of where I am:
# vim: filetype=vim foldmethod=marker foldlevel=0 foldcolumn=3
On a side note, this foldtext
function (a modification of a similar function by Drew Neil, IIRC) makes more sense to me than the default:
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()
With the other approach, split files, the main problems are finding things, and switching from one file to another. A very nice way to address both is to use a plugin such as CtrlSF, CtrlP, or similar. But you're probably already using one of those anyway.
Answered by lcd047 on December 20, 2020
I use my primary vimrc
as a link to several other categorized files, sourcing each as it goes along, e.g. Vim options in one file, plugin settings in another.
"--- 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
As a more direct answer to OP question, I do use the marker method, but off to the right side with spacing, and around more categories than individual, for the most part. I do each plugin separately though.
Answered by Cometsong on December 20, 2020
Basic best practises:
Divide into sections:
Comment each section/rebind
(backup your .vimrc
or _vimrc
on Github)
Just my personal preference. Maybe not so much help though.
Answered by Gustav Blomqvist on December 20, 2020
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP