Skip to content

Instantly share code, notes, and snippets.

@vim-voom
Created December 27, 2012 17:23
Show Gist options
  • Save vim-voom/4390083 to your computer and use it in GitHub Desktop.
Save vim-voom/4390083 to your computer and use it in GitHub Desktop.
Vim folding expression with counters
" vim: fdc=5
" http://groups.google.com/group/vim_use/browse_thread/thread/fedd5c8e45162d3f
" THE GOAL: Write Vim folding expression that
" - starts fold on lines matching 'start'
" - ends fold on lines matching 'stop'
" - DOES NOT USE "a", "s", "="
" (this should be same as :set fdm=marker fmr=start,stop)
" stop
" SAMPLE TEXT, INDENT SIGNIFIES FOLD LEVEL:
" start
" stop
"
" start XXX fold remains after dd, WHY?
" alpha
" start
" beta
" stop
" stop
" start
" gamma
" start
" delta
" stop
" stop
" SPECIAL CASES:
" 1) Fold update picks up exactly where previous update left. That is, fold
" update starts on the line next after the line where previous update ended.
" s:lnum==a:lnum
" s:lev set on the previous line during the last update will be used, which
" should be always correct.
"
" 2) Fold update starts after a line matching 'stop'. Previous fold is not closed.
" The solution is to check for that and decrement level by one.
set foldtext=getline(v:foldstart).'\ \ \ /'.v:foldlevel.'...'.(v:foldend-v:foldstart)
setlocal foldmethod=expr
setlocal foldexpr=MyFolds(v:lnum)
let [s:lnum, s:lev] = [1, 0]
function! MyFolds(lnum)
if s:lnum != a:lnum
let s:lev = foldlevel(a:lnum-1)
if getline(a:lnum-1) =~# '\<stop\>' && s:lev>0
let s:lev -= 1
endif
endif
let s:lnum = a:lnum+1
let thisline = getline(a:lnum)
if thisline =~# '\<start\>'
let s:lev += 1
return '>'.s:lev
elseif thisline =~# '\<stop\>' && s:lev>0
let lev = s:lev
let s:lev -= 1
return '<'.lev
else
return s:lev
endif
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment