5280a50f |
" Vim global plugin for folding text around search results
" Last change: Wed Aug 10 10:06:31 BST 2011
" Maintainer: Damian Conway
" License: This file is placed in the public domain.
" If already loaded, we're done...
if exists("loaded_foldsearch")
finish
endif
let loaded_foldsearch = 1
" Preserve external compatibility options, then enable full vim compatibility...
let s:save_cpo = &cpo
set cpo&vim
" Remember default behaviours...
let s:DEFFOLDMETHOD = &foldmethod
let s:DEFFOLDEXPR = &foldexpr
let s:DEFFOLDTEXT = &foldtext
let s:DEFFOLDLEVEL = 1000
" This is what the options are changed to...
let s:FOLDEXPR = 'FS_FoldSearchLevel()'
let s:FOLDTEXT = {
\ 'visible' : "'___/ line ' . (v:foldend+1) . ' \\' . repeat('_',200) ",
\ 'invisible' : "repeat(' ',200)",
\}
" Turn the mechanism on and off...
function! FS_ToggleFoldAroundSearch (opts)
" How much context to show...
let b:FOLDCONTEXT = get(a:opts, 'context', 1)
let &foldminlines = b:FOLDCONTEXT
" Show folds???
let folds_visible = get(a:opts, 'folds', 'visible')
" Make sure we can remember the previous setup...
if !exists('b:foldsearch')
let b:foldsearch = { 'active' : 0 }
endif
" Turn off, if it's on...
if b:foldsearch.active
let &foldmethod = get(b:foldsearch, 'prevfoldmethod', s:DEFFOLDMETHOD)
let &foldtext = get(b:foldsearch, 'prevfoldtext', s:DEFFOLDTEXT)
let &foldlevel = get(b:foldsearch, 'prevfoldlevel', s:DEFFOLDLEVEL)
let &foldexpr = get(b:foldsearch, 'prevfoldexpr', s:DEFFOLDEXPR)
" Remove autocommands for refolding for each new search...
augroup FoldSearch
autocmd!
augroup END
" Remember that it's off...
let b:foldsearch.active = 0
" Disable special <CR> behaviour...
nunmap <buffer> <CR>
return 'zE'
" Turn on, if it's off...
else
" Save old settings...
let b:foldsearch.prevfoldmethod = &foldmethod
let b:foldsearch.prevfoldexpr = &foldexpr
let b:foldsearch.prevfoldtext = &foldtext
let b:foldsearch.prevfoldlevel = &foldlevel
" Set up new behaviour...
let &foldtext = s:FOLDTEXT[folds_visible]
let &foldexpr = s:FOLDEXPR
let &foldmethod = 'expr'
let &foldlevel = 0
" Recalculate folding for each new search...
augroup FoldSearch
autocmd!
autocmd CursorMoved * let b:inopenfold = foldlevel('.') && foldclosed('.') == -1
autocmd CursorMoved * let &foldexpr = &foldexpr
autocmd CursorMoved * let &foldlevel = 0
autocmd CursorMoved * call ReopenFold()
function! ReopenFold ()
if b:inopenfold
normal zo
endif
endfunction
augroup END
" Enable special <CR> behaviour...
nnoremap <buffer> <expr> <CR> foldlevel('.') ? 'zA' : ''
" Remember that it's on...
let b:foldsearch.active = 1
return ":redraw!\<CR>"
endif
endfunction
" Search for a particular target and turn search folding on (if not already on)...
function! FS_FoldAroundTarget (target, opts)
let context = get(a:opts, 'context', 1 )
let folds_visible = get(a:opts, 'folds', 'visible')
" If already in a foldsearch...
if exists('b:foldsearch')
if b:foldsearch.active
" If already folding this pattern...
if @/ == a:target
" Toggle off...
return ":nohlsearch\<CR>:exec 'normal ' . FS_ToggleFoldAroundSearch({'context':1})\<CR>"
" Otherwise stay in foldsearch and switch to target...
else
let b:FOLDCONTEXT = get(a:opts, 'context', 1)
let &foldtext = s:FOLDTEXT[folds_visible]
let &foldminlines = 1
return '/' . a:target . "\<CR>"
endif
endif
endif
" If not already in a foldsearch, search for target then toggle on...
return '/' . a:target . "\<CR>:exec 'normal ' . FS_ToggleFoldAroundSearch(".string(a:opts).")\<CR>"
endfunction
" Utility function implements folding expression...
function! FS_FoldSearchLevel ()
" Allow one line of context before and after...
let startline = v:lnum > 1 ? v:lnum - b:FOLDCONTEXT : v:lnum
let endline = v:lnum < line('$') ? v:lnum + b:FOLDCONTEXT : v:lnum
let context = getline(startline, endline)
" Simulate smartcase matching...
let matchpattern = @/
if &smartcase && matchpattern =~ '\u'
let matchpattern = '\C'.matchpattern
endif
" Line is folded if surrounding context doesn't match last search pattern...
return match(context, matchpattern) == -1
endfunction
" Restore previous external compatibility options
let &cpo = s:save_cpo
|