]> git.r.bdr.sh - rbdr/dotfiles/blame - vim/plugin/searchfold_0.9.vim
Add DS_Store to gitignore
[rbdr/dotfiles] / vim / plugin / searchfold_0.9.vim
CommitLineData
0d23b6e5
BB
1" Vim global plugin -- create folds based on last search pattern
2" General: {{{1
3" File: searchfold.vim
4" Created: 2008 Jan 19
5" Last Change: 2011 May 24
6" Rev Days: 18
7" Author: Andy Wokula <anwoku@yahoo.de>
8" Credits: Antonio Colombo's f.vim (Vimscript #318, 2005 May 10)
9" Vim Version: Vim 7.0
10" Version: 0.9
11
12" Description:
13" Provide mappings to fold away lines not matching the last search pattern
14" and to restore old fold settings afterwards. Uses manual fold method,
15" which allows for nested folds to hide or show more context. Doesn't
16" preserve the user's manual folds.
17
18" Usage:
19" <Leader>z fold away lines not matching the last search pattern.
20"
21" With [count], change the initial foldlevel to ([count] minus
22" one). The setting will be stored in g:searchfold_foldlevel
23" and will be reused when [count] is omitted.
24"
25" <Leader>iz fold away lines that do match the last search pattern
26" (inverse folding), also with [count].
27"
28" <Leader>Z restore the previous fold settings.
29"
30" Minor Extra: If already in restored state, show a dialog to
31" revert all involved local fold options to the global
32" defaults. The "(s)how" just prints info.
33
34" Customization:
35" :let g:searchfold_maxdepth = 7
36" (number)
37" maximum fold depth
38"
39" :let g:searchfold_usestep = 1
40" (boolean)
41" Controls how folds are organized: If 1 (default), each "zr"
42" (after "\z") unfolds the same amount of lines above and
43" below a match. If 0, only one more line is unfolded above a
44" match. This applies for next "\z" or "\iz".
45"
46" :let g:searchfold_postZ_do_zv = 1
47" (boolean)
48" If 1, execute "zv" (view cursor line) after <Leader>Z.
49"
50" :let g:searchfold_foldlevel = 0
51" (number)
52" Initial 'foldlevel' to set for <Leader>z and <Leader>iz.
53"
54" :let g:searchfold_do_maps = 1
55" (boolean)
56" Whether to map the default keys or not.
57"
58" Hint: For boolean options, 1 actually means any non-zero number.
59
60" Related: Vimscript #158 (foldutil.vim) ... still to be checked out
61" http://www.noah.org/wiki/Vim#Folding
62" Vimscript #2302 (foldsearch.vim)
63" Vimscript #578 (allfold.tar.gz)
64"
65" Changes:
66" v0.9 redraw removed, plug map renamed, comments (usestep ...)
67" v0.8 added inverse folding (<Leader>iz), g:searchfold_foldlevel,
68" count for <Leader>z, <Plug> mappings, disabled F(), (fixes)
69" v0.7 b:searchfold fallback, s:foldtext check
70" v0.6 (after v0.4) added customization vars (usestep, maxdepth, Zpost)
71" reverting global fold settings adds to cmd-history
72" v0.4 decreasing fold step always 1
73" maxdepth 7 (before: 6)
74" v0.3 (after v0.1) added a modified F() from f.vim
75" functions now with return values
76" v0.2 (skipped)
77
78" Init Folklore: {{{1
79if exists("loaded_searchfold")
80 finish
81endif
82let loaded_searchfold = 1
83
84if v:version<700
85 echo "Searchfold: you need at least Vim 7.0"
86 finish
87endif
88
89" Customization: {{{1
90if !exists("g:searchfold_maxdepth")
91 let g:searchfold_maxdepth = 7
92endif
93if !exists("g:searchfold_usestep")
94 let g:searchfold_usestep = 1
95endif
96if !exists("g:searchfold_postZ_do_zv")
97 let g:searchfold_postZ_do_zv = 1
98endif
99if !exists("g:searchfold_foldlevel")
100 let g:searchfold_foldlevel = 0
101endif
102if !exists("g:searchfold_do_maps")
103 let g:searchfold_do_maps = 1
104endif
105
106" s:variables {{{1
107let s:foldtext = "(v:folddashes.'').((v:foldend)-(v:foldstart)+(1))"
108" use unique notation of 'foldtext' to identify active searchfold in a
109" window
110
111func! s:FoldNested(from, to) " {{{1
112 " create one fold from line a:from to line a:to, with more nested folds
113 " return 1 if folds were created
114 " return 0 if from > to
115 let nlines = a:to - a:from
116 if nlines < 0
117 return 0
118 elseif nlines < 3
119 " range of 1 line possible
120 exec a:from.",".a:to. "fold"
121 return 1
122 endif
123
124 " calc folds, start with most outer fold
125 " - range of inner folds at least 2 lines (from<to)
126 " - limit nesting (depth)
127 " - snap folds at start and end of file
128 " - at greater "depth" (here depth->0), don't create folds with few
129 " lines only (check to-from>step)
130 if g:searchfold_maxdepth < 1 || g:searchfold_maxdepth > 12
131 let g:searchfold_maxdepth = 7
132 endif
133 let depth = g:searchfold_maxdepth
134 let step = 1 " decstep:''
135 let step1 = 1 " (const) decstep:'1'
136 let from = a:from
137 let to = a:to
138 " let decstep = exists("g:searchfold_usestep") && g:searchfold_usestep ? "" : "1"
139 let decstep = g:searchfold_usestep ? "" : "1"
140 let foldranges = []
141 let lined = line("$")
142 while depth>0 && from<to && to-from>step
143 call insert(foldranges, from.",".to)
144 let from += from>1 ? step : 0
145 " let to -= to<lined ? 1 : 0
146 let to -= to<lined ? step{decstep} : 0
147 let step += step " arbitrary
148 let depth -= 1
149 endwhile
150
151 " create folds, start with most inner fold
152 for range in foldranges
153 exec range. "fold"
154 endfor
155
156 return 1
157endfunc
158
159func! s:CreateFolds(inverse) " {{{1
160 " create search folds for the whole buffer based on last search pattern
161 let sav_cur = getpos(".")
162
163 let matches = [] " list of lnums
164 if !a:inverse
165 global//call add(matches, line("."))
166 else
167 vglobal//call add(matches, line("."))
168 endif
169
170 let nmatches = len(matches)
171 if nmatches > 0
172 call s:FoldNested(1, matches[0]-1)
173 let imax = nmatches - 1
174 let i = 0
175 while i < imax
176 if matches[i]+1 < matches[i+1]
177 call s:FoldNested(matches[i]+1, matches[i+1]-1)
178 endif
179 let i += 1
180 endwhile
181 call s:FoldNested(matches[imax]+1, line("$"))
182 endif
183
184 let &l:foldlevel = g:searchfold_foldlevel
185 call cursor(sav_cur[1:])
186
187 return nmatches
188endfunc
189
190func! <sid>SearchFoldEnable(inverse) "{{{1
191 " return number of matches
192 if !search("", "n")
193 " last search pattern not found, do nothing
194 return 0
195 endif
196 if (!exists("w:searchfold") || w:searchfold.bufnr != bufnr(""))
197 \ && &fdt != s:foldtext
198 " remember settings
199 let w:searchfold = { "bufnr": bufnr(""),
200 \ "fdm": &fdm,
201 \ "fdl": &fdl,
202 \ "fdt": &fdt,
203 \ "fen": &fen,
204 \ "fml": &fml }
205 " else: do not remember settings if already enabled
206 endif
207 setlocal foldmethod=manual
208 setlocal foldlevel=0
209 let &l:foldtext=s:foldtext
210 setlocal foldenable
211 setlocal foldminlines=0
212 normal! zE
213 if exists("w:searchfold")
214 let b:searchfold = w:searchfold
215 endif
216 return s:CreateFolds(a:inverse)
217endfunc
218func! SearchFoldRestore() "{{{1
219 " turn off
220 if exists("w:searchfold") && w:searchfold.bufnr == bufnr("")
221 " restore settings; var has the right settings if exists, but
222 " doesn't survive window split or win close/restore
223 let &l:fdm = w:searchfold.fdm
224 let &l:fdl = w:searchfold.fdl
225 let &l:fdt = w:searchfold.fdt
226 let &l:fen = w:searchfold.fen
227 let &l:fml = w:searchfold.fml
228 if &fdm == "manual"
229 " remove all search folds (old folds are lost anyway):
230 normal! zE
231 endif
232 unlet w:searchfold
233 elseif exists("b:searchfold") && &fdt == s:foldtext
234 " fallback only, may have wrong settings if overwritten
235 let &l:fdm = b:searchfold.fdm
236 let &l:fdl = b:searchfold.fdl
237 let &l:fdt = b:searchfold.fdt
238 let &l:fen = b:searchfold.fen
239 let &l:fml = b:searchfold.fml
240 if &fdm == "manual"
241 normal! zE
242 endif
243 else
244 let choice = input("Revert to global fold settings? (y/[n]/(s)how):")[0]
245 let setargs = 'fdm< fdl< fdt< fen< fml<'
246 if choice == "y"
247 let cmd = 'setlocal '. setargs
248 echo ':'. cmd
249 exec cmd
250 " call histadd(':', cmd)
251 elseif choice == "s"
252 let setargs = tr(setargs, "<","?")
253 let cmd = 'setglobal '. setargs
254 echo ':'. cmd
255 exec cmd
256 let cmd = 'setlocal '. setargs
257 echo ':'. cmd
258 exec cmd
259 endif
260 return
261 endif
262 if g:searchfold_postZ_do_zv
263 normal! zv
264 endif
265endfunc
266
267"" func! F() range "{{{1
268" " commented out 2010 Jun 01
269" " range arg: ignore range given by accident
270" let pat = input("Which regexp? ", @/)
271" if pat == ""
272" if exists("w:searchfold")
273" call SearchFoldRestore()
274" endif
275" return
276" endif
277" let @/ = pat
278" call histadd("search", @/)
279" call SearchFold()
280" endfunc
281
282" :call F() only for backwards compatibility
283
284func! SearchFold(...) "{{{1
285 let inverse = a:0>=1 && a:1
286 if v:count >= 1
287 let g:searchfold_foldlevel = v:count - 1
288 endif
289 let nmatches = <sid>SearchFoldEnable(inverse)
290 " at most one match per line counted
291 if nmatches == 0
292 echohl ErrorMsg
293 echomsg "Searchfold: Pattern not found:" @/
294 echohl none
295 elseif nmatches == line("$")
296 echomsg "Searchfold: Pattern found in every line:" @/
297 elseif nmatches == 1
298 echo "Searchfold: 1 line found"
299 else
300 echo "Searchfold:" nmatches "lines found"
301 endif
302 " 2011 Feb 06 commented out:
303 " let &hls = &hls
304 " redraw
305endfunc
306
307" Mappings: {{{1
308nn <silent> <Plug>SearchFoldNormal :<C-U>call SearchFold(0)<CR>
309nn <silent> <Plug>SearchFoldInverse :<C-U>call SearchFold(1)<CR>
310nn <silent> <Plug>SearchFoldRestore :<C-U>call SearchFoldRestore()<CR>
311
312if g:searchfold_do_maps
313 nmap <Leader>z <Plug>SearchFoldNormal
314 nmap <Leader>iz <Plug>SearchFoldInverse
315 nmap <Leader>Z <Plug>SearchFoldRestore
316endif
317
318" Modeline: {{{1
319" vim:set fdm=marker ts=8 sts=4 sw=4 noet: