]> git.r.bdr.sh - rbdr/dotfiles/blob - vim/plugin/cecutil.vim
0bf34344796a7270f198fa87b3871dfb1f4ee188
[rbdr/dotfiles] / vim / plugin / cecutil.vim
1 " cecutil.vim : save/restore window position
2 " save/restore mark position
3 " save/restore selected user maps
4 " Author: Charles E. Campbell, Jr.
5 " Version: 18b ASTRO-ONLY
6 " Date: Aug 27, 2008
7 "
8 " Saving Restoring Destroying Marks: {{{1
9 " call SaveMark(markname) let savemark= SaveMark(markname)
10 " call RestoreMark(markname) call RestoreMark(savemark)
11 " call DestroyMark(markname)
12 " commands: SM RM DM
13 "
14 " Saving Restoring Destroying Window Position: {{{1
15 " call SaveWinPosn() let winposn= SaveWinPosn()
16 " call RestoreWinPosn() call RestoreWinPosn(winposn)
17 " \swp : save current window/buffer's position
18 " \rwp : restore current window/buffer's previous position
19 " commands: SWP RWP
20 "
21 " Saving And Restoring User Maps: {{{1
22 " call SaveUserMaps(mapmode,maplead,mapchx,suffix)
23 " call RestoreUserMaps(suffix)
24 "
25 " GetLatestVimScripts: 1066 1 :AutoInstall: cecutil.vim
26 "
27 " You believe that God is one. You do well. The demons also {{{1
28 " believe, and shudder. But do you want to know, vain man, that
29 " faith apart from works is dead? (James 2:19,20 WEB)
30
31 " ---------------------------------------------------------------------
32 " Load Once: {{{1
33 if &cp || exists("g:loaded_cecutil")
34 finish
35 endif
36 let g:loaded_cecutil = "v18b"
37 let s:keepcpo = &cpo
38 set cpo&vim
39 "DechoTabOn
40
41 " =======================
42 " Public Interface: {{{1
43 " =======================
44
45 " ---------------------------------------------------------------------
46 " Map Interface: {{{2
47 if !hasmapto('<Plug>SaveWinPosn')
48 map <unique> <Leader>swp <Plug>SaveWinPosn
49 endif
50 if !hasmapto('<Plug>RestoreWinPosn')
51 map <unique> <Leader>rwp <Plug>RestoreWinPosn
52 endif
53 nmap <silent> <Plug>SaveWinPosn :call SaveWinPosn()<CR>
54 nmap <silent> <Plug>RestoreWinPosn :call RestoreWinPosn()<CR>
55
56 " ---------------------------------------------------------------------
57 " Command Interface: {{{2
58 com! -bar -nargs=0 SWP call SaveWinPosn()
59 com! -bar -nargs=0 RWP call RestoreWinPosn()
60 com! -bar -nargs=1 SM call SaveMark(<q-args>)
61 com! -bar -nargs=1 RM call RestoreMark(<q-args>)
62 com! -bar -nargs=1 DM call DestroyMark(<q-args>)
63
64 if v:version < 630
65 let s:modifier= "sil "
66 else
67 let s:modifier= "sil keepj "
68 endif
69
70 " ===============
71 " Functions: {{{1
72 " ===============
73
74 " ---------------------------------------------------------------------
75 " SaveWinPosn: {{{2
76 " let winposn= SaveWinPosn() will save window position in winposn variable
77 " call SaveWinPosn() will save window position in b:cecutil_winposn{b:cecutil_iwinposn}
78 " let winposn= SaveWinPosn(0) will *only* save window position in winposn variable (no stacking done)
79 fun! SaveWinPosn(...)
80 " call Dfunc("SaveWinPosn() a:0=".a:0)
81 if line(".") == 1 && getline(1) == ""
82 " call Dfunc("SaveWinPosn : empty buffer")
83 return ""
84 endif
85 let so_keep = &l:so
86 let siso_keep = &siso
87 let ss_keep = &l:ss
88 setlocal so=0 siso=0 ss=0
89
90 let swline = line(".")
91 let swcol = col(".")
92 let swwline = winline() - 1
93 let swwcol = virtcol(".") - wincol()
94 let savedposn = "call GoWinbufnr(".winbufnr(0).")|silent ".swline
95 let savedposn = savedposn."|".s:modifier."norm! 0z\<cr>"
96 if swwline > 0
97 let savedposn= savedposn.":".s:modifier."norm! ".swwline."\<c-y>\<cr>"
98 endif
99 if swwcol > 0
100 let savedposn= savedposn.":".s:modifier."norm! 0".swwcol."zl\<cr>"
101 endif
102 let savedposn = savedposn.":".s:modifier."call cursor(".swline.",".swcol.")\<cr>"
103
104 " save window position in
105 " b:cecutil_winposn_{iwinposn} (stack)
106 " only when SaveWinPosn() is used
107 if a:0 == 0
108 if !exists("b:cecutil_iwinposn")
109 let b:cecutil_iwinposn= 1
110 else
111 let b:cecutil_iwinposn= b:cecutil_iwinposn + 1
112 endif
113 " call Decho("saving posn to SWP stack")
114 let b:cecutil_winposn{b:cecutil_iwinposn}= savedposn
115 endif
116
117 let &l:so = so_keep
118 let &siso = siso_keep
119 let &l:ss = ss_keep
120
121 " if exists("b:cecutil_iwinposn") " Decho
122 " call Decho("b:cecutil_winpos{".b:cecutil_iwinposn."}[".b:cecutil_winposn{b:cecutil_iwinposn}."]")
123 " else " Decho
124 " call Decho("b:cecutil_iwinposn doesn't exist")
125 " endif " Decho
126 " call Dret("SaveWinPosn [".savedposn."]")
127 return savedposn
128 endfun
129
130 " ---------------------------------------------------------------------
131 " RestoreWinPosn: {{{2
132 " call RestoreWinPosn()
133 " call RestoreWinPosn(winposn)
134 fun! RestoreWinPosn(...)
135 " call Dfunc("RestoreWinPosn() a:0=".a:0)
136 " call Decho("getline(1)<".getline(1).">")
137 " call Decho("line(.)=".line("."))
138 if line(".") == 1 && getline(1) == ""
139 " call Dfunc("RestoreWinPosn : empty buffer")
140 return ""
141 endif
142 let so_keep = &l:so
143 let siso_keep = &l:siso
144 let ss_keep = &l:ss
145 setlocal so=0 siso=0 ss=0
146
147 if a:0 == 0 || a:1 == ""
148 " use saved window position in b:cecutil_winposn{b:cecutil_iwinposn} if it exists
149 if exists("b:cecutil_iwinposn") && exists("b:cecutil_winposn{b:cecutil_iwinposn}")
150 " call Decho("using stack b:cecutil_winposn{".b:cecutil_iwinposn."}<".b:cecutil_winposn{b:cecutil_iwinposn}.">")
151 try
152 exe "silent! ".b:cecutil_winposn{b:cecutil_iwinposn}
153 catch /^Vim\%((\a\+)\)\=:E749/
154 " ignore empty buffer error messages
155 endtry
156 " normally drop top-of-stack by one
157 " but while new top-of-stack doesn't exist
158 " drop top-of-stack index by one again
159 if b:cecutil_iwinposn >= 1
160 unlet b:cecutil_winposn{b:cecutil_iwinposn}
161 let b:cecutil_iwinposn= b:cecutil_iwinposn - 1
162 while b:cecutil_iwinposn >= 1 && !exists("b:cecutil_winposn{b:cecutil_iwinposn}")
163 let b:cecutil_iwinposn= b:cecutil_iwinposn - 1
164 endwhile
165 if b:cecutil_iwinposn < 1
166 unlet b:cecutil_iwinposn
167 endif
168 endif
169 else
170 echohl WarningMsg
171 echomsg "***warning*** need to SaveWinPosn first!"
172 echohl None
173 endif
174
175 else " handle input argument
176 " call Decho("using input a:1<".a:1.">")
177 " use window position passed to this function
178 exe "silent ".a:1
179 " remove a:1 pattern from b:cecutil_winposn{b:cecutil_iwinposn} stack
180 if exists("b:cecutil_iwinposn")
181 let jwinposn= b:cecutil_iwinposn
182 while jwinposn >= 1 " search for a:1 in iwinposn..1
183 if exists("b:cecutil_winposn{jwinposn}") " if it exists
184 if a:1 == b:cecutil_winposn{jwinposn} " and the pattern matches
185 unlet b:cecutil_winposn{jwinposn} " unlet it
186 if jwinposn == b:cecutil_iwinposn " if at top-of-stack
187 let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " drop stacktop by one
188 endif
189 endif
190 endif
191 let jwinposn= jwinposn - 1
192 endwhile
193 endif
194 endif
195
196 " Seems to be something odd: vertical motions after RWP
197 " cause jump to first column. The following fixes that.
198 " Note: was using wincol()>1, but with signs, a cursor
199 " at column 1 yields wincol()==3. Beeping ensued.
200 if virtcol('.') > 1
201 silent norm! hl
202 elseif virtcol(".") < virtcol("$")
203 silent norm! lh
204 endif
205
206 let &l:so = so_keep
207 let &l:siso = siso_keep
208 let &l:ss = ss_keep
209
210 " call Dret("RestoreWinPosn")
211 endfun
212
213 " ---------------------------------------------------------------------
214 " GoWinbufnr: go to window holding given buffer (by number) {{{2
215 " Prefers current window; if its buffer number doesn't match,
216 " then will try from topleft to bottom right
217 fun! GoWinbufnr(bufnum)
218 " call Dfunc("GoWinbufnr(".a:bufnum.")")
219 if winbufnr(0) == a:bufnum
220 " call Dret("GoWinbufnr : winbufnr(0)==a:bufnum")
221 return
222 endif
223 winc t
224 let first=1
225 while winbufnr(0) != a:bufnum && (first || winnr() != 1)
226 winc w
227 let first= 0
228 endwhile
229 " call Dret("GoWinbufnr")
230 endfun
231
232 " ---------------------------------------------------------------------
233 " SaveMark: sets up a string saving a mark position. {{{2
234 " For example, SaveMark("a")
235 " Also sets up a global variable, g:savemark_{markname}
236 fun! SaveMark(markname)
237 " call Dfunc("SaveMark(markname<".a:markname.">)")
238 let markname= a:markname
239 if strpart(markname,0,1) !~ '\a'
240 let markname= strpart(markname,1,1)
241 endif
242 " call Decho("markname=".markname)
243
244 let lzkeep = &lz
245 set lz
246
247 if 1 <= line("'".markname) && line("'".markname) <= line("$")
248 let winposn = SaveWinPosn(0)
249 exe s:modifier."norm! `".markname
250 let savemark = SaveWinPosn(0)
251 let g:savemark_{markname} = savemark
252 let savemark = markname.savemark
253 call RestoreWinPosn(winposn)
254 else
255 let g:savemark_{markname} = ""
256 let savemark = ""
257 endif
258
259 let &lz= lzkeep
260
261 " call Dret("SaveMark : savemark<".savemark.">")
262 return savemark
263 endfun
264
265 " ---------------------------------------------------------------------
266 " RestoreMark: {{{2
267 " call RestoreMark("a") -or- call RestoreMark(savemark)
268 fun! RestoreMark(markname)
269 " call Dfunc("RestoreMark(markname<".a:markname.">)")
270
271 if strlen(a:markname) <= 0
272 " call Dret("RestoreMark : no such mark")
273 return
274 endif
275 let markname= strpart(a:markname,0,1)
276 if markname !~ '\a'
277 " handles 'a -> a styles
278 let markname= strpart(a:markname,1,1)
279 endif
280 " call Decho("markname=".markname." strlen(a:markname)=".strlen(a:markname))
281
282 let lzkeep = &lz
283 set lz
284 let winposn = SaveWinPosn(0)
285
286 if strlen(a:markname) <= 2
287 if exists("g:savemark_{markname}") && strlen(g:savemark_{markname}) != 0
288 " use global variable g:savemark_{markname}
289 " call Decho("use savemark list")
290 call RestoreWinPosn(g:savemark_{markname})
291 exe "norm! m".markname
292 endif
293 else
294 " markname is a savemark command (string)
295 " call Decho("use savemark command")
296 let markcmd= strpart(a:markname,1)
297 call RestoreWinPosn(markcmd)
298 exe "norm! m".markname
299 endif
300
301 call RestoreWinPosn(winposn)
302 let &lz = lzkeep
303
304 " call Dret("RestoreMark")
305 endfun
306
307 " ---------------------------------------------------------------------
308 " DestroyMark: {{{2
309 " call DestroyMark("a") -- destroys mark
310 fun! DestroyMark(markname)
311 " call Dfunc("DestroyMark(markname<".a:markname.">)")
312
313 " save options and set to standard values
314 let reportkeep= &report
315 let lzkeep = &lz
316 set lz report=10000
317
318 let markname= strpart(a:markname,0,1)
319 if markname !~ '\a'
320 " handles 'a -> a styles
321 let markname= strpart(a:markname,1,1)
322 endif
323 " call Decho("markname=".markname)
324
325 let curmod = &mod
326 let winposn = SaveWinPosn(0)
327 1
328 let lineone = getline(".")
329 exe "k".markname
330 d
331 put! =lineone
332 let &mod = curmod
333 call RestoreWinPosn(winposn)
334
335 " restore options to user settings
336 let &report = reportkeep
337 let &lz = lzkeep
338
339 " call Dret("DestroyMark")
340 endfun
341
342 " ---------------------------------------------------------------------
343 " QArgSplitter: to avoid \ processing by <f-args>, <q-args> is needed. {{{2
344 " However, <q-args> doesn't split at all, so this one returns a list
345 " with splits at all whitespace (only!), plus a leading length-of-list.
346 " The resulting list: qarglist[0] corresponds to a:0
347 " qarglist[i] corresponds to a:{i}
348 fun! QArgSplitter(qarg)
349 " call Dfunc("QArgSplitter(qarg<".a:qarg.">)")
350 let qarglist = split(a:qarg)
351 let qarglistlen = len(qarglist)
352 let qarglist = insert(qarglist,qarglistlen)
353 " call Dret("QArgSplitter ".string(qarglist))
354 return qarglist
355 endfun
356
357 " ---------------------------------------------------------------------
358 " ListWinPosn: {{{2
359 "fun! ListWinPosn() " Decho
360 " if !exists("b:cecutil_iwinposn") || b:cecutil_iwinposn == 0 " Decho
361 " call Decho("nothing on SWP stack") " Decho
362 " else " Decho
363 " let jwinposn= b:cecutil_iwinposn " Decho
364 " while jwinposn >= 1 " Decho
365 " if exists("b:cecutil_winposn{jwinposn}") " Decho
366 " call Decho("winposn{".jwinposn."}<".b:cecutil_winposn{jwinposn}.">") " Decho
367 " else " Decho
368 " call Decho("winposn{".jwinposn."} -- doesn't exist") " Decho
369 " endif " Decho
370 " let jwinposn= jwinposn - 1 " Decho
371 " endwhile " Decho
372 " endif " Decho
373 "endfun " Decho
374 "com! -nargs=0 LWP call ListWinPosn() " Decho
375
376 " ---------------------------------------------------------------------
377 " SaveUserMaps: this function sets up a script-variable (s:restoremap) {{{2
378 " which can be used to restore user maps later with
379 " call RestoreUserMaps()
380 "
381 " mapmode - see :help maparg for details (n v o i c l "")
382 " ex. "n" = Normal
383 " The letters "b" and "u" are optional prefixes;
384 " The "u" means that the map will also be unmapped
385 " The "b" means that the map has a <buffer> qualifier
386 " ex. "un" = Normal + unmapping
387 " ex. "bn" = Normal + <buffer>
388 " ex. "bun" = Normal + <buffer> + unmapping
389 " ex. "ubn" = Normal + <buffer> + unmapping
390 " maplead - see mapchx
391 " mapchx - "<something>" handled as a single map item.
392 " ex. "<left>"
393 " - "string" a string of single letters which are actually
394 " multiple two-letter maps (using the maplead:
395 " maplead . each_character_in_string)
396 " ex. maplead="\" and mapchx="abc" saves user mappings for
397 " \a, \b, and \c
398 " Of course, if maplead is "", then for mapchx="abc",
399 " mappings for a, b, and c are saved.
400 " - :something handled as a single map item, w/o the ":"
401 " ex. mapchx= ":abc" will save a mapping for "abc"
402 " suffix - a string unique to your plugin
403 " ex. suffix= "DrawIt"
404 fun! SaveUserMaps(mapmode,maplead,mapchx,suffix)
405 " call Dfunc("SaveUserMaps(mapmode<".a:mapmode."> maplead<".a:maplead."> mapchx<".a:mapchx."> suffix<".a:suffix.">)")
406
407 if !exists("s:restoremap_{a:suffix}")
408 " initialize restoremap_suffix to null string
409 let s:restoremap_{a:suffix}= ""
410 endif
411
412 " set up dounmap: if 1, then save and unmap (a:mapmode leads with a "u")
413 " if 0, save only
414 let mapmode = a:mapmode
415 let dounmap = 0
416 let dobuffer = ""
417 while mapmode =~ '^[bu]'
418 if mapmode =~ '^u'
419 let dounmap= 1
420 let mapmode= strpart(a:mapmode,1)
421 elseif mapmode =~ '^b'
422 let dobuffer= "<buffer> "
423 let mapmode= strpart(a:mapmode,1)
424 endif
425 endwhile
426 " call Decho("dounmap=".dounmap." dobuffer<".dobuffer.">")
427
428 " save single map :...something...
429 if strpart(a:mapchx,0,1) == ':'
430 " call Decho("save single map :...something...")
431 let amap= strpart(a:mapchx,1)
432 if amap == "|" || amap == "\<c-v>"
433 let amap= "\<c-v>".amap
434 endif
435 let amap = a:maplead.amap
436 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:silent! ".mapmode."unmap ".dobuffer.amap
437 if maparg(amap,mapmode) != ""
438 let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
439 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:".mapmode."map ".dobuffer.amap." ".maprhs
440 endif
441 if dounmap
442 exe "silent! ".mapmode."unmap ".dobuffer.amap
443 endif
444
445 " save single map <something>
446 elseif strpart(a:mapchx,0,1) == '<'
447 " call Decho("save single map <something>")
448 let amap = a:mapchx
449 if amap == "|" || amap == "\<c-v>"
450 let amap= "\<c-v>".amap
451 " call Decho("amap[[".amap."]]")
452 endif
453 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|silent! ".mapmode."unmap ".dobuffer.amap
454 if maparg(a:mapchx,mapmode) != ""
455 let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
456 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".amap." ".dobuffer.maprhs
457 endif
458 if dounmap
459 exe "silent! ".mapmode."unmap ".dobuffer.amap
460 endif
461
462 " save multiple maps
463 else
464 " call Decho("save multiple maps")
465 let i= 1
466 while i <= strlen(a:mapchx)
467 let amap= a:maplead.strpart(a:mapchx,i-1,1)
468 if amap == "|" || amap == "\<c-v>"
469 let amap= "\<c-v>".amap
470 endif
471 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|silent! ".mapmode."unmap ".dobuffer.amap
472 if maparg(amap,mapmode) != ""
473 let maprhs = substitute(maparg(amap,mapmode),'|','<bar>','ge')
474 let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".amap." ".dobuffer.maprhs
475 endif
476 if dounmap
477 exe "silent! ".mapmode."unmap ".dobuffer.amap
478 endif
479 let i= i + 1
480 endwhile
481 endif
482 " call Dret("SaveUserMaps : restoremap_".a:suffix.": ".s:restoremap_{a:suffix})
483 endfun
484
485 " ---------------------------------------------------------------------
486 " RestoreUserMaps: {{{2
487 " Used to restore user maps saved by SaveUserMaps()
488 fun! RestoreUserMaps(suffix)
489 " call Dfunc("RestoreUserMaps(suffix<".a:suffix.">)")
490 if exists("s:restoremap_{a:suffix}")
491 let s:restoremap_{a:suffix}= substitute(s:restoremap_{a:suffix},'|\s*$','','e')
492 if s:restoremap_{a:suffix} != ""
493 " call Decho("exe ".s:restoremap_{a:suffix})
494 exe "silent! ".s:restoremap_{a:suffix}
495 endif
496 unlet s:restoremap_{a:suffix}
497 endif
498 " call Dret("RestoreUserMaps")
499 endfun
500
501 " ==============
502 " Restore: {{{1
503 " ==============
504 let &cpo= s:keepcpo
505 unlet s:keepcpo
506
507 " ================
508 " Modelines: {{{1
509 " ================
510 " vim: ts=4 fdm=marker