" cecutil.vim : save/restore window position " save/restore mark position " save/restore selected user maps " Author: Charles E. Campbell " Version: 18k ASTRO-ONLY " Date: Nov 22, 2017 " " Saving Restoring Destroying Marks: {{{1 " call SaveMark(markname) let savemark= SaveMark(markname) " call RestoreMark(markname) call RestoreMark(savemark) " call DestroyMark(markname) " commands: SM RM DM " " Saving Restoring Destroying Window Position: {{{1 " call SaveWinPosn() let winposn= SaveWinPosn() " call RestoreWinPosn() call RestoreWinPosn(winposn) " \swp : save current window/buffer's position " \rwp : restore current window/buffer's previous position " commands: SWP RWP " " Saving And Restoring User Maps: {{{1 " call SaveUserMaps(mapmode,maplead,mapchx,suffix) " call RestoreUserMaps(suffix) " " GetLatestVimScripts: 1066 1 :AutoInstall: cecutil.vim " " You believe that God is one. You do well. The demons also {{{1 " believe, and shudder. But do you want to know, vain man, that " faith apart from works is dead? (James 2:19,20 WEB) "redraw!|call inputsave()|call input("Press to continue")|call inputrestore() " --------------------------------------------------------------------- " Load Once: {{{1 if &cp || exists("g:loaded_cecutil") finish endif let g:loaded_cecutil = "v18k" let s:keepcpo = &cpo set cpo&vim "if exists("g:loaded_Decho") " Decho " DechoRemOn "endif " Decho " ======================= " Public Interface: {{{1 " ======================= " --------------------------------------------------------------------- " Map Interface: {{{2 if !hasmapto('SaveWinPosn') map swp SaveWinPosn endif if !hasmapto('RestoreWinPosn') map rwp RestoreWinPosn endif nmap SaveWinPosn :call SaveWinPosn() nmap RestoreWinPosn :call RestoreWinPosn() " --------------------------------------------------------------------- " Command Interface: {{{2 com! -bar -nargs=0 SWP call SaveWinPosn() com! -bar -nargs=? RWP call RestoreWinPosn() com! -bar -nargs=1 SM call SaveMark() com! -bar -nargs=1 RM call RestoreMark() com! -bar -nargs=1 DM call DestroyMark() com! -bar -nargs=1 WLR call s:WinLineRestore() if v:version < 630 let s:modifier= "sil! " else let s:modifier= "sil! keepj " endif " =============== " Functions: {{{1 " =============== " --------------------------------------------------------------------- " SaveWinPosn: {{{2 " let winposn= SaveWinPosn() will save window position in winposn variable " call SaveWinPosn() will save window position in b:cecutil_winposn{b:cecutil_iwinposn} " let winposn= SaveWinPosn(0) will *only* save window position in winposn variable (no stacking done) fun! SaveWinPosn(...) " echomsg "Decho: SaveWinPosn() a:0=".a:0 let savedposn= winsaveview() if a:0 == 0 if !exists("b:cecutil_iwinposn") let b:cecutil_iwinposn= 1 else let b:cecutil_iwinposn= b:cecutil_iwinposn + 1 endif " echomsg "Decho: saving posn to SWP stack" let b:cecutil_winposn{b:cecutil_iwinposn}= savedposn endif return savedposn "" echomsg "Decho: SaveWinPosn() a:0=".a:0 " if line("$") == 1 && getline(1) == "" "" echomsg "Decho: SaveWinPosn : empty buffer" " return "" " endif " let so_keep = &l:so " let siso_keep = &siso " let ss_keep = &l:ss " setlocal so=0 siso=0 ss=0 " let swline = line(".") " save-window line in file " let swcol = col(".") " save-window column in file " if swcol >= col("$") " let swcol= swcol + virtcol(".") - virtcol("$") " adjust for virtual edit (cursor past end-of-line) " endif " let swwline = winline() - 1 " save-window window line " let swwcol = virtcol(".") - wincol() " save-window window column " let savedposn = "" "" echomsg "Decho: sw[".swline.",".swcol."] sww[".swwline.",".swwcol."]" " let savedposn = "call GoWinbufnr(".winbufnr(0).")" " let savedposn = savedposn."|".s:modifier.swline " let savedposn = savedposn."|".s:modifier."norm! 0z\" " if swwline > 0 " let savedposn= savedposn.":".s:modifier."call s:WinLineRestore(".(swwline+1).")\" " endif " if swwcol > 0 " let savedposn= savedposn.":".s:modifier."norm! 0".swwcol."zl\" " endif " let savedposn = savedposn.":".s:modifier."call cursor(".swline.",".swcol.")\" " " save window position in " " b:cecutil_winposn_{iwinposn} (stack) " " only when SaveWinPosn() is used " if a:0 == 0 " if !exists("b:cecutil_iwinposn") " let b:cecutil_iwinposn= 1 " else " let b:cecutil_iwinposn= b:cecutil_iwinposn + 1 " endif "" echomsg "Decho: saving posn to SWP stack" " let b:cecutil_winposn{b:cecutil_iwinposn}= savedposn " endif " let &l:so = so_keep " let &siso = siso_keep " let &l:ss = ss_keep "" if exists("b:cecutil_iwinposn") " Decho "" echomsg "Decho: b:cecutil_winpos{".b:cecutil_iwinposn."}[".b:cecutil_winposn{b:cecutil_iwinposn}."]" "" else " Decho "" echomsg "Decho: b:cecutil_iwinposn doesn't exist" "" endif " Decho "" echomsg "Decho: SaveWinPosn [".savedposn."]" " return savedposn endfun " --------------------------------------------------------------------- " RestoreWinPosn: {{{2 " call RestoreWinPosn() " call RestoreWinPosn(winposn) fun! RestoreWinPosn(...) if line("$") == 1 && getline(1) == "" return "" endif if a:0 == 0 || type(a:1) != 4 " use saved window position in b:cecutil_winposn{b:cecutil_iwinposn} if it exists if exists("b:cecutil_iwinposn") && exists("b:cecutil_winposn{b:cecutil_iwinposn}") try call winrestview(b:cecutil_winposn{b:cecutil_iwinposn}) catch /^Vim\%((\a\+)\)\=:E749/ " ignore empty buffer error messages endtry " normally drop top-of-stack by one " but while new top-of-stack doesn't exist " drop top-of-stack index by one again if b:cecutil_iwinposn >= 1 unlet b:cecutil_winposn{b:cecutil_iwinposn} let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 while b:cecutil_iwinposn >= 1 && !exists("b:cecutil_winposn{b:cecutil_iwinposn}") let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 endwhile if b:cecutil_iwinposn < 1 unlet b:cecutil_iwinposn endif endif else echohl WarningMsg echomsg "***warning*** need to SaveWinPosn first!" echohl None endif else " handle input argument " echomsg "Decho: using input a:1<".a:1.">" " use window position passed to this function call winrestview(a:1) " remove a:1 pattern from b:cecutil_winposn{b:cecutil_iwinposn} stack if exists("b:cecutil_iwinposn") let jwinposn= b:cecutil_iwinposn while jwinposn >= 1 " search for a:1 in iwinposn..1 if exists("b:cecutil_winposn{jwinposn}") " if it exists if a:1 == b:cecutil_winposn{jwinposn} " and the pattern matches unlet b:cecutil_winposn{jwinposn} " unlet it if jwinposn == b:cecutil_iwinposn " if at top-of-stack let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " drop stacktop by one endif endif endif let jwinposn= jwinposn - 1 endwhile endif endif "" echomsg "Decho: RestoreWinPosn() a:0=".a:0 "" echomsg "Decho: getline(1)<".getline(1).">" "" echomsg "Decho: line(.)=".line(".") " if line("$") == 1 && getline(1) == "" "" echomsg "Decho: RestoreWinPosn : empty buffer" " return "" " endif " let so_keep = &l:so " let siso_keep = &l:siso " let ss_keep = &l:ss " setlocal so=0 siso=0 ss=0 " if a:0 == 0 || a:1 == "" " " use saved window position in b:cecutil_winposn{b:cecutil_iwinposn} if it exists " if exists("b:cecutil_iwinposn") && exists("b:cecutil_winposn{b:cecutil_iwinposn}") "" echomsg "Decho: using stack b:cecutil_winposn{".b:cecutil_iwinposn."}<".b:cecutil_winposn{b:cecutil_iwinposn}.">" " try " exe s:modifier.b:cecutil_winposn{b:cecutil_iwinposn} " catch /^Vim\%((\a\+)\)\=:E749/ " " ignore empty buffer error messages " endtry " " normally drop top-of-stack by one " " but while new top-of-stack doesn't exist " " drop top-of-stack index by one again " if b:cecutil_iwinposn >= 1 " unlet b:cecutil_winposn{b:cecutil_iwinposn} " let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " while b:cecutil_iwinposn >= 1 && !exists("b:cecutil_winposn{b:cecutil_iwinposn}") " let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " endwhile " if b:cecutil_iwinposn < 1 " unlet b:cecutil_iwinposn " endif " endif " else " echohl WarningMsg " echomsg "***warning*** need to SaveWinPosn first!" " echohl None " endif " else " handle input argument "" echomsg "Decho: using input a:1<".a:1.">" " " use window position passed to this function " exe a:1 " " remove a:1 pattern from b:cecutil_winposn{b:cecutil_iwinposn} stack " if exists("b:cecutil_iwinposn") " let jwinposn= b:cecutil_iwinposn " while jwinposn >= 1 " search for a:1 in iwinposn..1 " if exists("b:cecutil_winposn{jwinposn}") " if it exists " if a:1 == b:cecutil_winposn{jwinposn} " and the pattern matches " unlet b:cecutil_winposn{jwinposn} " unlet it " if jwinposn == b:cecutil_iwinposn " if at top-of-stack " let b:cecutil_iwinposn= b:cecutil_iwinposn - 1 " drop stacktop by one " endif " endif " endif " let jwinposn= jwinposn - 1 " endwhile " endif " endif " " Seems to be something odd: vertical motions after RWP " " cause jump to first column. The following fixes that. " " Note: was using wincol()>1, but with signs, a cursor " " at column 1 yields wincol()==3. Beeping ensued. " let vekeep= &ve " set ve=all " if virtcol('.') > 1 " exe s:modifier."norm! hl" " elseif virtcol(".") < virtcol("$") " exe s:modifier."norm! lh" " endif " let &ve= vekeep " let &l:so = so_keep " let &l:siso = siso_keep " let &l:ss = ss_keep "" echomsg "Decho: RestoreWinPosn" endfun " --------------------------------------------------------------------- " s:WinLineRestore: {{{2 fun! s:WinLineRestore(swwline) " echomsg "Decho: s:WinLineRestore(swwline=".a:swwline.")" while winline() < a:swwline let curwinline= winline() exe s:modifier."norm! \" if curwinline == winline() break endif endwhile " echomsg "Decho: s:WinLineRestore" endfun " --------------------------------------------------------------------- " GoWinbufnr: go to window holding given buffer (by number) {{{2 " Prefers current window; if its buffer number doesn't match, " then will try from topleft to bottom right fun! GoWinbufnr(bufnum) " call Dfunc("GoWinbufnr(".a:bufnum.")") if winbufnr(0) == a:bufnum " call Dret("GoWinbufnr : winbufnr(0)==a:bufnum") return endif winc t let first=1 while winbufnr(0) != a:bufnum && (first || winnr() != 1) winc w let first= 0 endwhile " call Dret("GoWinbufnr") endfun " --------------------------------------------------------------------- " SaveMark: sets up a string saving a mark position. {{{2 " For example, SaveMark("a") " Also sets up a global variable, g:savemark_{markname} fun! SaveMark(markname) " call Dfunc("SaveMark(markname<".string(a:markname).">)") let markname= a:markname if strpart(markname,0,1) !~ '\a' let markname= strpart(markname,1,1) endif " call Decho("markname=".string(markname)) let lzkeep = &lz set lz if 1 <= line("'".markname) && line("'".markname) <= line("$") let winposn = SaveWinPosn(0) exe s:modifier."norm! `".markname let savemark = SaveWinPosn(0) let g:savemark_{markname} = savemark let savemark = markname.string(savemark) call RestoreWinPosn(winposn) else let g:savemark_{markname} = "" let savemark = "" endif let &lz= lzkeep " call Dret("SaveMark : savemark<".savemark.">") return savemark endfun " --------------------------------------------------------------------- " RestoreMark: {{{2 " call RestoreMark("a") -or- call RestoreMark(savemark) fun! RestoreMark(markname) " call Dfunc("RestoreMark(markname<".a:markname.">)") if strlen(a:markname) <= 0 " call Dret("RestoreMark : no such mark") return endif let markname= strpart(a:markname,0,1) if markname !~ '\a' " handles 'a -> a styles let markname= strpart(a:markname,1,1) endif " call Decho("markname=".markname." strlen(a:markname)=".strlen(a:markname)) let lzkeep = &lz set lz let winposn = SaveWinPosn(0) if strlen(a:markname) <= 2 if exists("g:savemark_{markname}") " use global variable g:savemark_{markname} " call Decho("use savemark list") call RestoreWinPosn(g:savemark_{markname}) exe "norm! m".markname endif else " markname is a savemark command (string) " call Decho("use savemark command") let markcmd= strpart(a:markname,1) call RestoreWinPosn(winposn) exe "norm! m".markname endif call RestoreWinPosn(winposn) let &lz = lzkeep " call Dret("RestoreMark") endfun " --------------------------------------------------------------------- " DestroyMark: {{{2 " call DestroyMark("a") -- destroys mark fun! DestroyMark(markname) " call Dfunc("DestroyMark(markname<".a:markname.">)") " save options and set to standard values let reportkeep= &report let lzkeep = &lz set lz report=10000 let markname= strpart(a:markname,0,1) if markname !~ '\a' " handles 'a -> a styles let markname= strpart(a:markname,1,1) endif " call Decho("markname=".markname) let curmod = &mod let winposn = SaveWinPosn(0) 1 let lineone = getline(".") exe "k".markname d put! =lineone let &mod = curmod call RestoreWinPosn(winposn) " restore options to user settings let &report = reportkeep let &lz = lzkeep " call Dret("DestroyMark") endfun " --------------------------------------------------------------------- " QArgSplitter: to avoid \ processing by , is needed. {{{2 " However, doesn't split at all, so this one returns a list " with splits at all whitespace (only!), plus a leading length-of-list. " The resulting list: qarglist[0] corresponds to a:0 " qarglist[i] corresponds to a:{i} fun! QArgSplitter(qarg) " call Dfunc("QArgSplitter(qarg<".a:qarg.">)") let qarglist = split(a:qarg) let qarglistlen = len(qarglist) let qarglist = insert(qarglist,qarglistlen) " call Dret("QArgSplitter ".string(qarglist)) return qarglist endfun " --------------------------------------------------------------------- " ListWinPosn: {{{2 "fun! ListWinPosn() " Decho " if !exists("b:cecutil_iwinposn") || b:cecutil_iwinposn == 0 " Decho " call Decho("nothing on SWP stack") " Decho " else " Decho " let jwinposn= b:cecutil_iwinposn " Decho " while jwinposn >= 1 " Decho " if exists("b:cecutil_winposn{jwinposn}") " Decho " call Decho("winposn{".jwinposn."}<".b:cecutil_winposn{jwinposn}.">") " Decho " else " Decho " call Decho("winposn{".jwinposn."} -- doesn't exist") " Decho " endif " Decho " let jwinposn= jwinposn - 1 " Decho " endwhile " Decho " endif " Decho "endfun " Decho "com! -nargs=0 LWP call ListWinPosn() " Decho " --------------------------------------------------------------------- " SaveUserMaps: this function sets up a script-variable (s:restoremap) {{{2 " which can be used to restore user maps later with " call RestoreUserMaps() " " mapmode - see :help maparg for details (n v o i c l "") " ex. "n" = Normal " The letters "b" and "u" are optional prefixes; " The "u" means that the map will also be unmapped " The "b" means that the map has a qualifier " ex. "un" = Normal + unmapping " ex. "bn" = Normal + " ex. "bun" = Normal + + unmapping " ex. "ubn" = Normal + + unmapping " maplead - see mapchx " mapchx - "" handled as a single map item. " ex. "" " - "string" a string of single letters which are actually " multiple two-letter maps (using the maplead: " maplead . each_character_in_string) " ex. maplead="\" and mapchx="abc" saves user mappings for " \a, \b, and \c " Of course, if maplead is "", then for mapchx="abc", " mappings for a, b, and c are saved. " - :something handled as a single map item, w/o the ":" " ex. mapchx= ":abc" will save a mapping for "abc" " suffix - a string unique to your plugin " ex. suffix= "DrawIt" fun! SaveUserMaps(mapmode,maplead,mapchx,suffix) " call Dfunc("SaveUserMaps(mapmode<".a:mapmode."> maplead<".a:maplead."> mapchx<".a:mapchx."> suffix<".a:suffix.">)") if !exists("s:restoremap_{a:suffix}") " initialize restoremap_suffix to null string let s:restoremap_{a:suffix}= "" endif " set up dounmap: if 1, then save and unmap (a:mapmode leads with a "u") " if 0, save only let mapmode = a:mapmode let dounmap = 0 let dobuffer = "" while mapmode =~# '^[bu]' if mapmode =~# '^u' let dounmap = 1 let mapmode = strpart(a:mapmode,1) elseif mapmode =~# '^b' let dobuffer = " " let mapmode = strpart(a:mapmode,1) endif endwhile " call Decho("dounmap=".dounmap." dobuffer<".dobuffer.">") " save single map :...something... if strpart(a:mapchx,0,1) == ':' " call Decho("save single map :...something...") let amap= strpart(a:mapchx,1) if amap == "|" || amap == "\" let amap= "\".amap endif let amap = a:maplead.amap let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:sil! ".mapmode."unmap ".dobuffer.amap if maparg(amap,mapmode) != "" let maprhs = substitute(maparg(amap,mapmode),'|','','ge') let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|:".mapmode."map ".dobuffer.amap." ".maprhs endif if dounmap exe "sil! ".mapmode."unmap ".dobuffer.amap endif " save single map elseif strpart(a:mapchx,0,1) == '<' " call Decho("save single map ") let amap = a:mapchx if amap == "|" || amap == "\" let amap= "\".amap " call Decho("amap[[".amap."]]") endif let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|sil! ".mapmode."unmap ".dobuffer.amap if maparg(a:mapchx,mapmode) != "" let maprhs = substitute(maparg(amap,mapmode),'|','','ge') let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".dobuffer.amap." ".maprhs endif if dounmap exe "sil! ".mapmode."unmap ".dobuffer.amap endif " save multiple maps else " call Decho("save multiple maps") let i= 1 while i <= strlen(a:mapchx) let amap= a:maplead.strpart(a:mapchx,i-1,1) if amap == "|" || amap == "\" let amap= "\".amap endif let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|sil! ".mapmode."unmap ".dobuffer.amap if maparg(amap,mapmode) != "" let maprhs = substitute(maparg(amap,mapmode),'|','','ge') let s:restoremap_{a:suffix} = s:restoremap_{a:suffix}."|".mapmode."map ".dobuffer.amap." ".maprhs endif if dounmap exe "sil! ".mapmode."unmap ".dobuffer.amap endif let i= i + 1 endwhile endif " call Dret("SaveUserMaps : s:restoremap_".a:suffix.": ".s:restoremap_{a:suffix}) endfun " --------------------------------------------------------------------- " RestoreUserMaps: {{{2 " Used to restore user maps saved by SaveUserMaps() fun! RestoreUserMaps(suffix) " call Dfunc("RestoreUserMaps(suffix<".a:suffix.">)") if exists("s:restoremap_{a:suffix}") let s:restoremap_{a:suffix}= substitute(s:restoremap_{a:suffix},'|\s*$','','e') if s:restoremap_{a:suffix} != "" " call Decho("exe ".s:restoremap_{a:suffix}) exe "sil! ".s:restoremap_{a:suffix} endif unlet s:restoremap_{a:suffix} endif " call Dret("RestoreUserMaps") endfun " ============== " Restore: {{{1 " ============== let &cpo= s:keepcpo unlet s:keepcpo " ================ " Modelines: {{{1 " ================ " vim: ts=4 fdm=marker