Rainbow
[my-vim-dotfolder.git] / plugin / cecutil.vim
blob0bf34344796a7270f198fa87b3871dfb1f4ee188
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
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
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
21 "  Saving And Restoring User Maps: {{{1
22 "       call SaveUserMaps(mapmode,maplead,mapchx,suffix)
23 "       call RestoreUserMaps(suffix)
25 " GetLatestVimScripts: 1066 1 :AutoInstall: cecutil.vim
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)
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
41 " =======================
42 "  Public Interface: {{{1
43 " =======================
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>
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>)
64 if v:version < 630
65  let s:modifier= "sil "
66 else
67  let s:modifier= "sil keepj "
68 endif
70 " ===============
71 " Functions: {{{1
72 " ===============
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
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>"
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
117   let &l:so = so_keep
118   let &siso = siso_keep
119   let &l:ss = ss_keep
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
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
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
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
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
206   let &l:so   = so_keep
207   let &l:siso = siso_keep
208   let &l:ss   = ss_keep
210 "  call Dret("RestoreWinPosn")
211 endfun
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
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)
244   let lzkeep  = &lz
245   set lz
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
259   let &lz= lzkeep
261 "  call Dret("SaveMark : savemark<".savemark.">")
262   return savemark
263 endfun
265 " ---------------------------------------------------------------------
266 " RestoreMark: {{{2
267 "   call RestoreMark("a")  -or- call RestoreMark(savemark)
268 fun! RestoreMark(markname)
269 "  call Dfunc("RestoreMark(markname<".a:markname.">)")
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))
282   let lzkeep  = &lz
283   set lz
284   let winposn = SaveWinPosn(0)
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
301   call RestoreWinPosn(winposn)
302   let &lz       = lzkeep
304 "  call Dret("RestoreMark")
305 endfun
307 " ---------------------------------------------------------------------
308 " DestroyMark: {{{2
309 "   call DestroyMark("a")  -- destroys mark
310 fun! DestroyMark(markname)
311 "  call Dfunc("DestroyMark(markname<".a:markname.">)")
313   " save options and set to standard values
314   let reportkeep= &report
315   let lzkeep    = &lz
316   set lz report=10000
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)
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)
335   " restore options to user settings
336   let &report = reportkeep
337   let &lz     = lzkeep
339 "  call Dret("DestroyMark")
340 endfun
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
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 
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()
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.">)")
407   if !exists("s:restoremap_{a:suffix}")
408    " initialize restoremap_suffix to null string
409    let s:restoremap_{a:suffix}= ""
410   endif
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.">")
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
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
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
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
501 " ==============
502 "  Restore: {{{1
503 " ==============
504 let &cpo= s:keepcpo
505 unlet s:keepcpo
507 " ================
508 "  Modelines: {{{1
509 " ================
510 " vim: ts=4 fdm=marker