Customize text for closed folds
Talk0this wiki
created March 4, 2008 · complexity basic · author Edouard · version 7.0
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 (such as C++, Java and pov).
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
See also
- Folding presents an overview of how to use folding
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. For example, 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
Another suggestion (less elaborated than above, tested for 7.2/7.3):
set foldtext=MyFoldText()
function MyFoldText()
let nucolwidth = &fdc + &number*&numberwidth
let winwd = winwidth(0) - nucolwidth - 5
let foldlinecount = foldclosedend(v:foldstart) - foldclosed(v:foldstart) + 1
let prefix = " _______>>> "
let fdnfo = prefix . string(v:foldlevel) . "," . string(foldlinecount)
let line = strpart(getline(v:foldstart), 0 , winwd - len(fdnfo))
let fillcharcount = winwd - len(line) - len(fdnfo)
return line . repeat(" ",fillcharcount) . fdnfo
endfunction