Proposed tip Please edit this page to improve it, or add your comments below (do not use the discussion page).
I wanted to improve the standard Vim foldtext both to look better in GUI versions of Vim, and to make the folding work better with C-like languages (C, C++, Java, pov, and many others).
The foldtext function below does three things:
- Is less intrusive when displaying code, and right-aligns the number of lines in the fold.
- Collapses folds that start and end on braces with everything between the braces replaced with {...}.
- Tries to collapse multiline comments with the first non-blank line in the comment.
Outstanding issues:
- Right alignment may not work with signs turned on.
- Tabs mess up the in-place display of the initial '{'.
" Set a nicer foldtext function set foldtext=MyFoldText() function! MyFoldText() let line = getline(v:foldstart) if match( line, '^[ \t]*\(\/\*\|\/\/\)[*/\\]*[ \t]*$' ) == 0 let initial = substitute( line, '^\([ \t]\)*\(\/\*\|\/\/\)\(.*\)', '\1\2', '' ) let linenum = v:foldstart + 1 while linenum < v:foldend let line = getline( linenum ) let comment_content = substitute( line, '^\([ \t\/\*]*\)\(.*\)$', '\2', 'g' ) if comment_content != '' break endif let linenum = linenum + 1 endwhile let sub = initial . ' ' . comment_content else let sub = line let startbrace = substitute( line, '^.*{[ \t]*$', '{', 'g') if startbrace == '{' let line = getline(v:foldend) let endbrace = substitute( line, '^[ \t]*}\(.*\)$', '}', 'g') if endbrace == '}' let sub = sub.substitute( line, '^[ \t]*}\(.*\)$', '...}\1', 'g') endif endif endif let n = v:foldend - v:foldstart + 1 let info = " " . n . " lines" let sub = sub . " " let num_w = getwinvar( 0, '&number' ) * getwinvar( 0, '&numberwidth' ) let fold_w = getwinvar( 0, '&foldcolumn' ) let sub = strpart( sub, 0, winwidth(0) - strlen( info ) - num_w - fold_w - 1 ) return sub . info endfunction
I also use the following highlights with white backgrounded source to visually set the folds apart from non-folded lines, while trying to keep a nice aesthetic.
highlight FoldColumn gui=bold guifg=grey65 guibg=Grey90 highlight Folded gui=italic guifg=Black guibg=Grey90 highlight LineNr gui=NONE guifg=grey60 guibg=Grey90
References
Comments
Here's what I use. I think that some of it might be good to merge in (especially the 'diff' folding section) but I'm not up do doing it right now. My goal was to have a very similar fold pattern for things like C code, but provide a good fallback for all other folds, and define something special for diff folding. I really like the way the author of this tip treats comments in a special way...I might need to use that idea.
In my $HOME/vimfiles/ftplugin directory, I set up different file-types to use my different fold patterns. E.g. in c.vim, I have "let b:foldpat=1"
if has("folding") set foldtext=MyFoldText() function! MyFoldText() " for now, just don't try if version isn't 7 or higher if v:version < 701 return foldtext() endif " clear fold from fillchars to set it up the way we want later let &l:fillchars = substitute(&l:fillchars,',\?fold:.','','gi') let l:numwidth = (v:version < 701 ? 8 : &numberwidth) if &fdm=='diff' let l:linetext='' let l:foldtext='---------- '.(v:foldend-v:foldstart+1).' lines the same ----------' let l:align = winwidth(0)-&foldcolumn-(&nu ? Max(strlen(line('$'))+1, l:numwidth) : 0) let l:align = (l:align / 2) + (strlen(l:foldtext)/2) " note trailing space on next line setlocal fillchars+=fold:\ elseif !exists('b:foldpat') || b:foldpat==0 let l:foldtext = ' '.(v:foldend-v:foldstart).' lines folded'.v:folddashes.'|' let l:endofline = (&textwidth>0 ? &textwidth : 80) let l:linetext = strpart(getline(v:foldstart),0,l:endofline-strlen(l:foldtext)) let l:align = l:endofline-strlen(l:linetext) setlocal fillchars+=fold:- elseif b:foldpat==1 let l:align = winwidth(0)-&foldcolumn-(&nu ? Max(strlen(line('$'))+1, l:numwidth) : 0) let l:foldtext = ' '.v:folddashes let l:linetext = substitute(getline(v:foldstart),'\s\+$','','') let l:linetext .= ' ---'.(v:foldend-v:foldstart-1).' lines--- ' let l:linetext .= substitute(getline(v:foldend),'^\s\+','','') let l:linetext = strpart(l:linetext,0,l:align-strlen(l:foldtext)) let l:align -= strlen(l:linetext) setlocal fillchars+=fold:- endif return printf('%s%*s', l:linetext, l:align, l:foldtext) endfunction endif