Merged from "branches/vim7.1".
[MacVim/jjgod.git] / runtime / autoload / vimball.vim
blob5ed34f22c385513f682064e96cfc526f7b87432d
1 " vimball.vim : construct a file containing both paths and files
2 " Author:       Charles E. Campbell, Jr.
3 " Date:         May 07, 2007
4 " Version:      22
5 " GetLatestVimScripts: 1502 1 :AutoInstall: vimball.vim
6 " Copyright: (c) 2004-2006 by Charles E. Campbell, Jr.
7 "            The VIM LICENSE applies to Vimball.vim, and Vimball.txt
8 "            (see |copyright|) except use "Vimball" instead of "Vim".
9 "            No warranty, express or implied.
10 "  *** ***   Use At-Your-Own-Risk!   *** ***
12 " ---------------------------------------------------------------------
13 "  Load Once: {{{1
14 if &cp || exists("g:loaded_vimball") || v:version < 700
15  finish
16 endif
17 let s:keepcpo        = &cpo
18 let g:loaded_vimball = "v22"
19 set cpo&vim
21 " =====================================================================
22 " Constants: {{{1
23 if !exists("s:USAGE")
24  let s:USAGE   = 0
25  let s:WARNING = 1
26  let s:ERROR   = 2
27 endif
29 " =====================================================================
30 "  Functions: {{{1
32 " ---------------------------------------------------------------------
33 " vimball#MkVimball: creates a vimball given a list of paths to files {{{2
34 " Vimball Format:
35 "     path
36 "     filesize
37 "     [file]
38 "     path
39 "     filesize
40 "     [file]
41 fun! vimball#MkVimball(line1,line2,writelevel,...) range
42 "  call Dfunc("MkVimball(line1=".a:line1." line2=".a:line2." writelevel=".a:writelevel." vimballname<".a:1.">) a:0=".a:0)
43   if a:1 =~ '.vim' || a:1 =~ '.txt'
44    let vbname= substitute(a:1,'\.\a\{3}$','.vba','')
45   else
46    let vbname= a:1
47   endif
48   if vbname !~ '\.vba$'
49    let vbname= vbname.'.vba'
50   endif
51 "  call Decho("vbname<".vbname.">")
52   if a:1 =~ '[\/]'
53    call vimball#ShowMesg(s:ERROR,"(MkVimball) vimball name<".a:1."> should not include slashes")
54 "   call Dret("MkVimball : vimball name<".a:1."> should not include slashes")
55    return
56   endif
57   if !a:writelevel && filereadable(vbname)
58    call vimball#ShowMesg(s:ERROR,"(MkVimball) file<".vbname."> exists; use ! to insist")
59 "   call Dret("MkVimball : file<".vbname."> already exists; use ! to insist")
60    return
61   endif
63   " user option bypass
64   call s:SaveSettings()
66   if a:0 >= 2
67    " allow user to specify where to get the files
68    let home= expand(a:2)
69   else
70    " use first existing directory from rtp
71    let home= s:VimballHome()
72   endif
74   " save current directory
75   let curdir = getcwd()
76   call s:ChgDir(home)
78   " record current tab, initialize while loop index
79   let curtabnr = tabpagenr()
80   let linenr   = a:line1
81 "  call Decho("curtabnr=".curtabnr)
83   while linenr <= a:line2
84    let svfile  = getline(linenr)
85 "   call Decho("svfile<".svfile.">")
87    if !filereadable(svfile)
88     call vimball#ShowMesg(s:ERROR,"unable to read file<".svfile.">")
89         call s:ChgDir(curdir)
90         call s:RestoreSettings()
91 "    call Dret("MkVimball")
92     return
93    endif
95    " create/switch to mkvimball tab
96    if !exists("vbtabnr")
97     tabnew
98     silent! file Vimball
99     let vbtabnr= tabpagenr()
100    else
101     exe "tabn ".vbtabnr
102    endif
104    let lastline= line("$") + 1
105    if lastline == 2 && getline("$") == ""
106         call setline(1,'" Vimball Archiver by Charles E. Campbell, Jr., Ph.D.')
107         call setline(2,'UseVimball')
108         call setline(3,'finish')
109         let lastline= line("$") + 1
110    endif
111    call setline(lastline  ,substitute(svfile,'$','      [[[1',''))
112    call setline(lastline+1,0)
114    " write the file from the tab
115    let svfilepath= s:Path(svfile,'')
116 "   call Decho("exe $r ".svfilepath)
117    exe "$r ".svfilepath
119    call setline(lastline+1,line("$") - lastline - 1)
120 "   call Decho("lastline=".lastline." line$=".line("$"))
122   " restore to normal tab
123    exe "tabn ".curtabnr
124    let linenr= linenr + 1
125   endwhile
127   " write the vimball
128   exe "tabn ".vbtabnr
129   call s:ChgDir(curdir)
130   if a:writelevel
131    let vbnamepath= s:Path(vbname,'')
132 "   call Decho("exe w! ".vbnamepath)
133    exe "w! ".vbnamepath
134   else
135    let vbnamepath= s:Path(vbname,'')
136 "   call Decho("exe w ".vbnamepath)
137    exe "w ".vbnamepath
138   endif
139 "  call Decho("Vimball<".vbname."> created")
140   echo "Vimball<".vbname."> created"
142   " remove the evidence
143   setlocal nomod bh=wipe
144   exe "tabn ".curtabnr
145   exe "tabc ".vbtabnr
147   " restore options
148   call s:RestoreSettings()
150 "  call Dret("MkVimball")
151 endfun
153 " ---------------------------------------------------------------------
154 " vimball#Vimball: extract and distribute contents from a vimball {{{2
155 fun! vimball#Vimball(really,...)
156 "  call Dfunc("vimball#Vimball(really=".a:really.") a:0=".a:0)
158   if getline(1) !~ '^" Vimball Archiver by Charles E. Campbell, Jr., Ph.D.$'
159    echoerr "(Vimball) The current file does not appear to be a Vimball!"
160 "   call Dret("vimball#Vimball")
161    return
162   endif
164   " set up standard settings
165   call s:SaveSettings()
166   let curtabnr = tabpagenr()
168   " set up vimball tab
169 "  call Decho("setting up vimball tab")
170   tabnew
171   silent! file Vimball
172   let vbtabnr= tabpagenr()
173   let didhelp= ""
175   " go to vim plugin home
176   if a:0 > 0
177    let home= expand(a:1)
178   else
179    let home= s:VimballHome()
180   endif
181 "  call Decho("home<".home.">")
183   " save current directory and remove older same-named vimball, if any
184   let curdir = getcwd()
185 "  call Decho("home<".home.">")
186 "  call Decho("curdir<".curdir.">")
188   call s:ChgDir(home)
189   call vimball#RmVimball()
191   let linenr  = 4
192   let filecnt = 0
194   " give title to listing of (extracted) files from Vimball Archive
195   if a:really
196    echohl Title | echomsg "Vimball Archive" | echohl None
197   else
198    echohl Title | echomsg "Vimball Archive Listing" | echohl None
199    echohl Statement | echomsg "files would be placed under: ".home | echohl None
200   endif
202   " apportion vimball contents to various files
203 "  call Decho("exe tabn ".curtabnr)
204   exe "tabn ".curtabnr
205 "  call Decho("linenr=".linenr." line$=".line("$"))
206   while 1 < linenr && linenr < line("$")
207    let fname   = substitute(getline(linenr),'\t\[\[\[1$','','')
208    let fname   = substitute(fname,'\\','/','g')
209    let fsize   = getline(linenr+1)
210    let filecnt = filecnt + 1
211 "   call Decho("fname<".fname."> fsize=".fsize." filecnt=".filecnt)
213    if a:really
214     echomsg "extracted <".fname.">: ".fsize." lines"
215    else
216     echomsg "would extract <".fname.">: ".fsize." lines"
217    endif
218 "   call Decho("using L#".linenr.": will extract file<".fname.">")
219 "   call Decho("using L#".(linenr+1).": fsize=".fsize)
221    " Allow AsNeeded/ directory to take place of plugin/ directory
222    " when AsNeeded/filename is filereadable
223    if fname =~ '\<plugin/'
224         let anfname= substitute(fname,'\<plugin/','AsNeeded/','')
225         if filereadable(anfname)
226 "        call Decho("using anfname<".anfname."> instead of <".fname.">")
227          let fname= anfname
228         endif
229    endif
231    " make directories if they don't exist yet
232    if a:really
233 "    call Decho("making directories if they don't exist yet (fname<".fname.">)")
234     let fnamebuf= substitute(fname,'\\','/','g')
235         let dirpath = substitute(home,'\\','/','g')
236     while fnamebuf =~ '/'
237      let dirname  = dirpath."/".substitute(fnamebuf,'/.*$','','')
238          let dirpath  = dirname
239      let fnamebuf = substitute(fnamebuf,'^.\{-}/\(.*\)$','\1','')
240 "        call Decho("dirname<".dirname.">")
241      if !isdirectory(dirname)
242 "      call Decho("making <".dirname.">")
243       call mkdir(dirname)
244           call s:RecordInVar(home,"rmdir('".dirname."')")
245      endif
246     endwhile
247    endif
248    call s:ChgDir(home)
250    " grab specified qty of lines and place into "a" buffer
251    " (skip over path/filename and qty-lines)
252    let linenr   = linenr + 2
253    let lastline = linenr + fsize - 1
254 "   call Decho("exe ".linenr.",".lastline."yank a")
255    exe "silent ".linenr.",".lastline."yank a"
257    " copy "a" buffer into tab
258 "   call Decho('copy "a buffer into tab#'.vbtabnr)
259    exe "tabn ".vbtabnr
260    silent! %d
261    silent put a
262    1
263    silent d
265    " write tab to file
266    if a:really
267     let fnamepath= s:Path(home."/".fname,'')
268 "    call Decho("exe w! ".fnamepath)
269     exe "silent w! ".fnamepath
270     echo "wrote ".fnamepath
271         call s:RecordInVar(home,"call delete('".fnamepath."')")
272    endif
274    " return to tab with vimball
275 "   call Decho("exe tabn ".curtabnr)
276    exe "tabn ".curtabnr
278    " set up help if its a doc/*.txt file
279 "   call Decho("didhelp<".didhelp."> fname<".fname.">")
280    if a:really && didhelp == "" && fname =~ 'doc/[^/]\+\.txt$'
281         let didhelp= substitute(fname,'^\(.*\<doc\)[/\\][^.]*\.txt$','\1','')
282 "       call Decho("didhelp<".didhelp.">")
283    endif
285    " update for next file
286 "   let oldlinenr = linenr " Decho
287    let linenr    = linenr + fsize
288 "   call Decho("update linenr= [linenr=".oldlinenr."] + [fsize=".fsize."] = ".linenr)
289   endwhile
291   " set up help
292 "  call Decho("about to set up help: didhelp<".didhelp.">")
293   if didhelp != ""
294    let htpath= escape(substitute(s:Path(home."/".didhelp,'"'),'"','','g'),' ')
295 "   call Decho("exe helptags ".htpath)
296    exe "helptags ".htpath
297    echo "did helptags"
298   endif
300   " make sure a "Press ENTER..." prompt appears to keep the messages showing!
301   while filecnt <= &ch
302    echomsg " "
303    let filecnt= filecnt + 1
304   endwhile
306   " record actions in <.VimballRecord>
307   call s:RecordInFile(home)
309   " restore events, delete tab and buffer
310   exe "tabn ".vbtabnr
311   setlocal nomod bh=wipe
312   exe "tabn ".curtabnr
313   exe "tabc ".vbtabnr
314   call s:RestoreSettings()
315   call s:ChgDir(curdir)
317 "  call Dret("vimball#Vimball")
318 endfun
320 " ---------------------------------------------------------------------
321 " vimball#RmVimball: remove any files, remove any directories made by any {{{2
322 "               previous vimball extraction based on a file of the current
323 "               name.
324 "  Usage:  RmVimball  (assume current file is a vimball; remove)
325 "          RmVimball vimballname
326 fun! vimball#RmVimball(...)
327 "  call Dfunc("vimball#RmVimball() a:0=".a:0)
328   if exists("g:vimball_norecord")
329 "   call Dret("vimball#RmVimball : (g:vimball_norecord)")
330    return
331   endif
332   let eikeep= &ei
333   set ei=all
334 "  call Decho("turned off all events")
336   if a:0 == 0
337    let curfile= '^'.expand("%:tr")
338   else
339    if a:1 =~ '[\/]'
340     call vimball#ShowMesg(s:USAGE,"RmVimball vimballname [path]")
341 "    call Dret("vimball#RmVimball : suspect a:1<".a:1.">")
342     return
343    endif
344    let curfile= a:1
345   endif
346   if curfile !~ '.vba$'
347    let curfile= curfile.".vba: "
348   else
349    let curfile= curfile.": "
350   endif
351   if a:0 >= 2
352    let home= expand(a:2)
353   else
354    let home= s:VimballHome()
355   endif
356   let curdir = getcwd()
357 "  call Decho("home   <".home.">")
358 "  call Decho("curfile<".curfile.">")
359 "  call Decho("curdir <".curdir.">")
361   call s:ChgDir(home)
362   if filereadable(".VimballRecord")
363 "   call Decho(".VimballRecord is readable")
364 "   call Decho("curfile<".curfile.">")
365    keepalt keepjumps 1split 
366    silent! keepalt keepjumps e .VimballRecord
367    let keepsrch= @/
368    if search(curfile,'cw')
369         let exestring= substitute(getline("."),curfile,'','')
370 "       call Decho("exe ".exestring)
371         silent! keepalt keepjumps exe exestring
372         silent! keepalt keepjumps d
373    else
374 "       call Decho("unable to find <".curfile."> in .VimballRecord")
375    endif
376    silent! keepalt keepjumps g/^\s*$/d
377    silent! keepalt keepjumps wq!
378    let @/= keepsrch
379   endif
380   call s:ChgDir(curdir)
382   " restoring events
383 "  call Decho("restoring events")
384   let &ei= eikeep
386 "  call Dret("vimball#RmVimball")
387 endfun
389 " ---------------------------------------------------------------------
390 " vimball#Decompress: attempts to automatically decompress vimballs {{{2
391 fun! vimball#Decompress(fname)
392 "  call Dfunc("Decompress(fname<".a:fname.">)")
394   " decompression:
395   if     expand("%") =~ '.*\.gz'  && executable("gunzip")
396    exe "!gunzip ".a:fname
397    let fname= substitute(a:fname,'\.gz$','','')
398    exe "e ".escape(fname,' \')
399    call vimball#ShowMesg(s:USAGE,"Source this file to extract it! (:so %)")
400   elseif expand("%") =~ '.*\.bz2' && executable("bunzip2")
401    exe "!bunzip2 ".a:fname
402    let fname= substitute(a:fname,'\.bz2$','','')
403    exe "e ".escape(fname,' \')
404    call vimball#ShowMesg(s:USAGE,"Source this file to extract it! (:so %)")
405   elseif expand("%") =~ '.*\.zip' && executable("unzip")
406    exe "!unzip ".a:fname
407    let fname= substitute(a:fname,'\.zip$','','')
408    exe "e ".escape(fname,' \')
409    call vimball#ShowMesg(s:USAGE,"Source this file to extract it! (:so %)")
410   endif
411   set noma bt=nofile fmr=[[[,]]] fdm=marker
413 "  call Dret("Decompress")
414 endfun
416 " ---------------------------------------------------------------------
417 " vimball#ShowMesg: {{{2
418 fun! vimball#ShowMesg(level,msg)
419 "  call Dfunc("vimball#ShowMesg(level=".a:level." msg<".a:msg.">)")
420   let rulerkeep   = &ruler
421   let showcmdkeep = &showcmd
422   set noruler noshowcmd
423   redraw!
425   if &fo =~ '[ta]'
426    echomsg "***vimball*** " a:msg
427   else
428    if a:level == s:WARNING || a:level == s:USAGE
429     echohl WarningMsg
430    elseif a:level == s:ERROR
431     echohl Error
432    endif
433    echomsg "***vimball*** " a:msg
434    echohl None
435   endif
437   if a:level != s:USAGE
438    call inputsave()|let ok= input("Press <cr> to continue")|call inputrestore()
439   endif
441   let &ruler   = rulerkeep
442   let &showcmd = showcmdkeep
444 "  call Dret("vimball#ShowMesg")
445 endfun
447 " ---------------------------------------------------------------------
448 let &cpo= s:keepcpo
449 unlet s:keepcpo
450 " =====================================================================
451 " s:ChgDir: change directory (in spite of Windoze) {{{2
452 fun! s:ChgDir(newdir)
453 "  call Dfunc("ChgDir(newdir<".a:newdir.">)")
454   if (has("win32") || has("win95") || has("win64") || has("win16"))
455     exe 'silent cd '.escape(substitute(a:newdir,'/','\\','g'),' ')
456   else
457    exe 'silent cd '.escape(a:newdir,' ')
458   endif
459 "  call Dret("ChgDir")
460 endfun
462 " ---------------------------------------------------------------------
463 " s:Path: prepend and append quotes, do escaping, as necessary {{{2
464 fun! s:Path(cmd,quote)
465 "  call Dfunc("Path(cmd<".a:cmd."> quote<".a:quote.">)")
466   if (has("win32") || has("win95") || has("win64") || has("win16"))
467    let cmdpath= a:quote.substitute(a:cmd,'/','\\','g').a:quote
468   else
469    let cmdpath= a:quote.a:cmd.a:quote
470   endif
471   if a:quote == ""
472    let cmdpath= escape(cmdpath,' ')
473   endif
474 "  call Dret("Path <".cmdpath.">")
475   return cmdpath
476 endfun
478 " ---------------------------------------------------------------------
479 " s:RecordInVar: record a un-vimball command in the .VimballRecord file {{{2
480 fun! s:RecordInVar(home,cmd)
481 "  call Dfunc("RecordInVar(home<".a:home."> cmd<".a:cmd.">)")
482   if a:cmd =~ '^rmdir'
483 "   if !exists("s:recorddir")
484 "    let s:recorddir= substitute(a:cmd,'^rmdir',"call s:Rmdir",'')
485 "   else
486 "    let s:recorddir= s:recorddir."|".substitute(a:cmd,'^rmdir',"call s:Rmdir",'')
487 "   endif
488 "   call Decho("recorddir=".s:recorddir)
489   elseif !exists("s:recordfile")
490    let s:recordfile= a:cmd
491 "   call Decho("recordfile=".s:recordfile)
492   else
493    let s:recordfile= s:recordfile."|".a:cmd
494 "   call Decho("recordfile=".s:recordfile)
495   endif
496 "  call Dret("RecordInVar")
497 endfun
499 " ---------------------------------------------------------------------
500 " s:RecordInFile: {{{2
501 fun! s:RecordInFile(home)
502 "  call Dfunc("RecordInFile()")
503   if exists("g:vimball_norecord")
504 "   call Dret("RecordInFile : (g:vimball_norecord)")
505    return
506   endif
508   if exists("s:recordfile") || exists("s:recorddir")
509    let curdir= getcwd()
510    call s:ChgDir(a:home)
511    keepalt keepjumps 1split 
512    let cmd= expand("%:tr").": "
513    silent! keepalt keepjumps e .VimballRecord
514    $
515    if exists("s:recordfile") && exists("s:recorddir")
516         let cmd= cmd.s:recordfile."|".s:recorddir
517    elseif exists("s:recorddir")
518         let cmd= cmd.s:recorddir
519    elseif exists("s:recordfile")
520         let cmd= cmd.s:recordfile
521    else
522 "    call Dret("RecordInFile")
523         return
524    endif
525    keepalt keepjumps put=cmd
526    silent! keepalt keepjumps g/^\s*$/d
527    silent! keepalt keepjumps wq!
528    call s:ChgDir(curdir)
529    if exists("s:recorddir") |unlet s:recorddir |endif
530    if exists("s:recordfile")|unlet s:recordfile|endif
531   else
532 "   call Decho("s:record[file|dir] doesn't exist")
533   endif
535 "  call Dret("RecordInFile")
536 endfun
538 " ---------------------------------------------------------------------
539 " s:Rmdir: {{{2
540 "fun! s:Rmdir(dirname)
541 ""  call Dfunc("s:Rmdir(dirname<".a:dirname.">)")
542 "  if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
543 "    call system("del ".a:dirname)
544 "  else
545 "   call system("rmdir ".a:dirname)
546 "  endif
547 ""  call Dret("s:Rmdir")
548 "endfun
550 " ---------------------------------------------------------------------
551 " s:VimballHome: determine/get home directory path (usually from rtp) {{{2
552 fun! s:VimballHome()
553 "  call Dfunc("VimballHome()")
554   if exists("g:vimball_home")
555    let home= g:vimball_home
556   else
557    " go to vim plugin home
558    for home in split(&rtp,',') + ['']
559     if isdirectory(home) && filewritable(home) | break | endif
560    endfor
561    if home == ""
562     " just pick the first directory
563     let home= substitute(&rtp,',.*$','','')
564    endif
565    if (has("win32") || has("win95") || has("win64") || has("win16"))
566     let home= substitute(home,'/','\\','g')
567    endif
568   endif
569 "  call Dret("VimballHome <".home.">")
570   return home
571 endfun
573 " ---------------------------------------------------------------------
574 " s:SaveSettings: {{{2
575 fun! s:SaveSettings()
576 "  call Dfunc("SaveSettings()")
577   let s:makeep  = getpos("'a")
578   let s:regakeep= @a
579   if exists("&acd")
580    let s:acdkeep = &acd
581   endif
582   let s:eikeep  = &ei
583   let s:fenkeep = &fen
584   let s:hidkeep = &hidden
585   let s:ickeep  = &ic
586   let s:lzkeep  = &lz
587   let s:pmkeep  = &pm
588   let s:repkeep = &report
589   let s:vekeep  = &ve
590   if exists("&acd")
591    set ei=all ve=all noacd nofen noic report=999 nohid bt= ma lz pm=
592   else
593    set ei=all ve=all nofen noic report=999 nohid bt= ma lz pm=
594   endif
595 "  call Dret("SaveSettings")
596 endfun
598 " ---------------------------------------------------------------------
599 " s:RestoreSettings: {{{2
600 fun! s:RestoreSettings()
601 "  call Dfunc("RestoreSettings()")
602   let @a      = s:regakeep
603   if exists("&acd")
604    let &acd   = s:acdkeep
605   endif
606   let &fen    = s:fenkeep
607   let &hidden = s:hidkeep
608   let &ic     = s:ickeep
609   let &lz     = s:lzkeep
610   let &pm     = s:pmkeep
611   let &report = s:repkeep
612   let &ve     = s:vekeep
613   let &ei     = s:eikeep
614   if s:makeep[0] != 0
615    " restore mark a
616 "   call Decho("restore mark-a: makeep=".string(makeep))
617    call setpos("'a",s:makeep)
618   endif
619   if exists("&acd")
620    unlet s:regakeep s:acdkeep s:eikeep s:fenkeep s:hidkeep s:ickeep s:repkeep s:vekeep s:makeep s:lzkeep s:pmkeep
621   else
622    unlet s:regakeep s:eikeep s:fenkeep s:hidkeep s:ickeep s:repkeep s:vekeep s:makeep s:lzkeep s:pmkeep
623   endif
624   set bt=nofile noma
625 "  call Dret("RestoreSettings")
626 endfun
628 " ---------------------------------------------------------------------
629 " Modelines: {{{1
630 " vim: fdm=marker