Partially synced with the branch.
[MacVim.git] / runtime / autoload / tar.vim
blobfc168e8013217f6bc73c51240efed5ad2a5b609d
1 " tar.vim: Handles browsing tarfiles
2 "            AUTOLOAD PORTION
3 " Date:                 Jul 30, 2008
4 " Version:              20
5 " Maintainer:   Charles E Campbell, Jr <NdrOchip@ScampbellPfamily.AbizM-NOSPAM>
6 " License:              Vim License  (see vim's :help license)
8 "       Contains many ideas from Michael Toren's <tar.vim>
10 " Copyright:    Copyright (C) 2005-2008 Charles E. Campbell, Jr. {{{1
11 "               Permission is hereby granted to use and distribute this code,
12 "               with or without modifications, provided that this copyright
13 "               notice is copied with it. Like anything else that's free,
14 "               tar.vim and tarPlugin.vim are provided *as is* and comes
15 "               with no warranty of any kind, either expressed or implied.
16 "               By using this plugin, you agree that in no event will the
17 "               copyright holder be liable for any damages resulting from
18 "               the use of this software.
20 " ---------------------------------------------------------------------
21 " Load Once: {{{1
22 let s:keepcpo= &cpo
23 set cpo&vim
24 if &cp || exists("g:loaded_tar") || v:version < 700
25  finish
26 endif
27 let g:loaded_tar= "v20"
28 "call Decho("loading autoload/tar.vim")
29 if v:version < 701 || (v:version == 701 && !has("patch299"))
30  echoerr "(autoload/tar.vim) need vim v7.1 with patchlevel 299"
31 endif
33 " ---------------------------------------------------------------------
34 "  Default Settings: {{{1
35 if !exists("g:tar_browseoptions")
36  let g:tar_browseoptions= "Ptf"
37 endif
38 if !exists("g:tar_readoptions")
39  let g:tar_readoptions= "OPxf"
40 endif
41 if !exists("g:tar_cmd")
42  let g:tar_cmd= "tar"
43 endif
44 if !exists("g:tar_writeoptions")
45  let g:tar_writeoptions= "uf"
46 endif
48 if !exists("g:netrw_cygwin")
49  if has("win32") || has("win95") || has("win64") || has("win16")
50   if &shell =~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$'
51    let g:netrw_cygwin= 1
52   else
53    let g:netrw_cygwin= 0
54   endif
55  else
56   let g:netrw_cygwin= 0
57  endif
58 endif
60 " set up shell quoting character
61 if !exists("g:tar_shq")
62  if exists("&shq") && &shq != ""
63   let g:tar_shq= &shq
64  elseif has("win32") || has("win95") || has("win64") || has("win16")
65   if exists("g:netrw_cygwin") && g:netrw_cygwin
66    let g:tar_shq= "'"
67   else
68    let g:tar_shq= '"'
69   endif
70  else
71   let g:tar_shq= "'"
72  endif
73 " call Decho("g:tar_shq<".g:tar_shq.">")
74 endif
76 " ----------------
77 "  Functions: {{{1
78 " ----------------
80 " ---------------------------------------------------------------------
81 " tar#Browse: {{{2
82 fun! tar#Browse(tarfile)
83 "  call Dfunc("tar#Browse(tarfile<".a:tarfile.">)")
84   let repkeep= &report
85   set report=10
87   " sanity checks
88   if !executable(g:tar_cmd)
89    redraw!
90    echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
91 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
92    let &report= repkeep
93 "   call Dret("tar#Browse")
94    return
95   endif
96   if !filereadable(a:tarfile)
97 "   call Decho('a:tarfile<'.a:tarfile.'> not filereadable')
98    if a:tarfile !~# '^\a\+://'
99     " if its an url, don't complain, let url-handlers such as vim do its thing
100     redraw!
101     echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None
102 "    call inputsave()|call input("Press <cr> to continue")|call inputrestore()
103    endif
104    let &report= repkeep
105 "   call Dret("tar#Browse : file<".a:tarfile."> not readable")
106    return
107   endif
108   if &ma != 1
109    set ma
110   endif
111   let w:tarfile= a:tarfile
113   setlocal noswapfile
114   setlocal buftype=nofile
115   setlocal bufhidden=hide
116   setlocal nobuflisted
117   setlocal nowrap
118   set ft=tar
120   " give header
121 "  call Decho("printing header")
122   let lastline= line("$")
123   call setline(lastline+1,'" tar.vim version '.g:loaded_tar)
124   call setline(lastline+2,'" Browsing tarfile '.a:tarfile)
125   call setline(lastline+3,'" Select a file with cursor and press ENTER')
126   $put =''
127   0d
128   $
130   let tarfile= a:tarfile
131   if has("win32") && executable("cygpath")
132    " assuming cygwin
133    let tarfile=substitute(system("cygpath -u ".s:Escape(tarfile,0)),'\n$','','e')
134   endif
135   let curlast= line("$")
136   if tarfile =~# '\.\(gz\|tgz\)$'
137 "   call Decho("1: exe silent r! gzip -d -c ".s:Escape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
138    exe "silent r! gzip -d -c -- ".s:Escape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
139   elseif tarfile =~# '\.lrp'
140 "   call Decho("2: exe silent r! cat -- ".s:Escape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - ")
141    exe "silent r! cat -- ".s:Escape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - "
142   elseif tarfile =~# '\.bz2$'
143 "   call Decho("3: exe silent r! bzip2 -d -c ".s:Escape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
144    exe "silent r! bzip2 -d -c -- ".s:Escape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
145   else
146 "   call Decho("4: exe silent r! ".g:tar_cmd." -".g:tar_browseoptions." ".s:Escape(tarfile,0))
147    exe "silent r! ".g:tar_cmd." -".g:tar_browseoptions." ".s:Escape(tarfile,1)
148   endif
149   if v:shell_error != 0
150    redraw!
151    echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">"
152 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
153 "   call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
154    return
155   endif
156   if line("$") == curlast || ( line("$") == (curlast + 1) && getline("$") =~ '\c\%(warning\|error\|inappropriate\|unrecognized\)')
157    redraw!
158    echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None
159 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
160    silent %d
161    let eikeep= &ei
162    set ei=BufReadCmd,FileReadCmd
163    exe "r ".fnameescape(a:tarfile)
164    let &ei= eikeep
165    1d
166 "   call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
167    return
168   endif
170   setlocal noma nomod ro
171   noremap <silent> <buffer> <cr> :call <SID>TarBrowseSelect()<cr>
173   let &report= repkeep
174 "  call Dret("tar#Browse : w:tarfile<".w:tarfile.">")
175 endfun
177 " ---------------------------------------------------------------------
178 " TarBrowseSelect: {{{2
179 fun! s:TarBrowseSelect()
180 "  call Dfunc("TarBrowseSelect() w:tarfile<".w:tarfile."> curfile<".expand("%").">")
181   let repkeep= &report
182   set report=10
183   let fname= getline(".")
184 "  call Decho("fname<".fname.">")
186   " sanity check
187   if fname =~ '^"'
188    let &report= repkeep
189 "   call Dret("TarBrowseSelect")
190    return
191   endif
193   " about to make a new window, need to use w:tarfile
194   let tarfile= w:tarfile
195   let curfile= expand("%")
196   if has("win32") && executable("cygpath")
197    " assuming cygwin
198    let tarfile=substitute(system("cygpath -u ".s:Escape(tarfile,0)),'\n$','','e')
199   endif
201   new
202   if !exists("g:tar_nomax") || g:tar_nomax == 0
203    wincmd _
204   endif
205   let s:tblfile_{winnr()}= curfile
206   call tar#Read("tarfile:".tarfile.'::'.fname,1)
207   filetype detect
209   let &report= repkeep
210 "  call Dret("TarBrowseSelect : s:tblfile_".winnr()."<".s:tblfile_{winnr()}.">")
211 endfun
213 " ---------------------------------------------------------------------
214 " tar#Read: {{{2
215 fun! tar#Read(fname,mode)
216 "  call Dfunc("tar#Read(fname<".a:fname.">,mode=".a:mode.")")
217   let repkeep= &report
218   set report=10
219   let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
220   let fname   = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
221   if has("win32") && executable("cygpath")
222    " assuming cygwin
223    let tarfile=substitute(system("cygpath -u ".s:Escape(tarfile,0)),'\n$','','e')
224   endif
225 "  call Decho("tarfile<".tarfile.">")
226 "  call Decho("fname<".fname.">")
228   if      fname =~ '\.gz$'  && executable("zcat")
229    let decmp= "|zcat"
230    let doro = 1
231   elseif  fname =~ '\.bz2$' && executable("bzcat")
232    let decmp= "|bzcat"
233    let doro = 1
234   else
235    let decmp=""
236    let doro = 0
237    if fname =~ '\.gz$\|\.bz2$\|\.Z$\|\.zip$'
238     setlocal bin
239    endif
240   endif
242   if tarfile =~# '\.\(gz\|tgz\)$'
243 "   call Decho("5: exe silent r! gzip -d -c -- ".s:Escape(tarfile,1)."| ".g:tar_cmd.' -'.g:tar_readoptions.' - '.s:Escape(fname,1))
244    exe "silent r! gzip -d -c -- ".s:Escape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".s:Escape(fname,1).decmp
245   elseif tarfile =~# '\.lrp$'
246 "   call Decho("6: exe silent r! cat ".s:Escape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".s:Escape(fname,1).decmp)
247    exe "silent r! cat -- ".s:Escape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".s:Escape(fname,1).decmp
248   elseif tarfile =~# '\.bz2$'
249 "   call Decho("7: exe silent r! bzip2 -d -c ".s:Escape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".s:Escape(fname,1).decmp)
250    exe "silent r! bzip2 -d -c -- ".s:Escape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".s:Escape(fname,1).decmp
251   else
252 "   call Decho("8: exe silent r! ".g:tar_cmd." -".g:tar_readoptions." -- ".s:Escape(tarfile,1)." ".s:Escape(fname,1))
253    exe "silent r! ".g:tar_cmd." -".g:tar_readoptions." ".s:Escape(tarfile,1)." -- ".s:Escape(fname,1).decmp
254   endif
256   if doro
257    " because the reverse process of compressing changed files back into the tarball is not currently supported
258    setlocal ro
259   endif
261   let w:tarfile= a:fname
262   exe "file tarfile::".fnameescape(fname)
264   " cleanup
265   0d
266   set nomod
268   let &report= repkeep
269 "  call Dret("tar#Read : w:tarfile<".w:tarfile.">")
270 endfun
272 " ---------------------------------------------------------------------
273 " tar#Write: {{{2
274 fun! tar#Write(fname)
275 "  call Dfunc("tar#Write(fname<".a:fname.">) w:tarfile<".w:tarfile."> tblfile_".winnr()."<".s:tblfile_{winnr()}.">")
276   let repkeep= &report
277   set report=10
279   " sanity checks
280   if !executable(g:tar_cmd)
281    redraw!
282    echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
283 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
284    let &report= repkeep
285 "   call Dret("tar#Write")
286    return
287   endif
288   if !exists("*mkdir")
289    redraw!
290    echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
291 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
292    let &report= repkeep
293 "   call Dret("tar#Write")
294    return
295   endif
297   let curdir= getcwd()
298   let tmpdir= tempname()
299 "  call Decho("orig tempname<".tmpdir.">")
300   if tmpdir =~ '\.'
301    let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
302   endif
303 "  call Decho("tmpdir<".tmpdir.">")
304   call mkdir(tmpdir,"p")
306   " attempt to change to the indicated directory
307   try
308    exe "cd ".fnameescape(tmpdir)
309   catch /^Vim\%((\a\+)\)\=:E344/
310    redraw!
311    echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
312 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
313    let &report= repkeep
314 "   call Dret("tar#Write")
315    return
316   endtry
317 "  call Decho("current directory now: ".getcwd())
319   " place temporary files under .../_ZIPVIM_/
320   if isdirectory("_ZIPVIM_")
321    call s:Rmdir("_ZIPVIM_")
322   endif
323   call mkdir("_ZIPVIM_")
324   cd _ZIPVIM_
325 "  call Decho("current directory now: ".getcwd())
327   let tarfile = substitute(w:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
328   let fname   = substitute(w:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
330   " handle compressed archives
331   if tarfile =~# '\.gz'
332    call system("gzip -d -- ".s:Escape(tarfile,0))
333    let tarfile = substitute(tarfile,'\.gz','','e')
334    let compress= "gzip ".s:Escape(tarfile,0)
335   elseif tarfile =~# '\.tgz'
336    call system("gzip -d -- ".s:Escape(tarfile,0))
337    let tarfile = substitute(tarfile,'\.tgz','.tar','e')
338    let compress= "gzip -- ".s:Escape(tarfile,0)
339    let tgz     = 1
340   elseif tarfile =~# '\.bz2'
341    call system("bzip2 -d -- ".s:Escape(tarfile,0))
342    let tarfile = substitute(tarfile,'\.bz2','','e')
343    let compress= "bzip2 -- ".s:Escape(tarfile,0)
344   endif
345 "  call Decho("tarfile<".tarfile.">")
346 "  call Decho("compress<".compress.">")
348   if v:shell_error != 0
349    redraw!
350    echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None
351 "   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
352   else
354 "   call Decho("tarfile<".tarfile."> fname<".fname.">")
356    if fname =~ '/'
357     let dirpath = substitute(fname,'/[^/]\+$','','e')
358     if executable("cygpath")
359      let dirpath = substitute(system("cygpath ".s:Escape(dirpath, 0)),'\n','','e')
360     endif
361     call mkdir(dirpath,"p")
362    endif
363    if tarfile !~ '/'
364     let tarfile= curdir.'/'.tarfile
365    endif
366 "   call Decho("tarfile<".tarfile."> fname<".fname.">")
368    exe "w! ".fnameescape(fname)
369    if executable("cygpath")
370     let tarfile = substitute(system("cygpath ".s:Escape(tarfile,0)),'\n','','e')
371    endif
373    " delete old file from tarfile
374 "   call Decho("system(tar --delete -f ".s:Escape(tarfile,0)." -- ".s:Escape(fname,0).")")
375    call system("tar --delete -f ".s:Escape(tarfile,0)." -- ".s:Escape(fname,0))
376    if v:shell_error != 0
377     redraw!
378     echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
379 "    call inputsave()|call input("Press <cr> to continue")|call inputrestore()
380    else
382     " update tarfile with new file 
383 "    call Decho("tar -".g:tar_writeoptions." ".s:Escape(tarfile,0)." -- ".s:Escape(fname,0))
384     call system("tar -".g:tar_writeoptions." ".s:Escape(tarfile,0)." -- ".s:Escape(fname,0))
385     if v:shell_error != 0
386      redraw!
387      echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
388 "     call inputsave()|call input("Press <cr> to continue")|call inputrestore()
389     elseif exists("compress")
390 "     call Decho("call system(".compress.")")
391      call system(compress)
392      if exists("tgz")
393 "      call Decho("rename(".tarfile.".gz,".substitute(tarfile,'\.tar$','.tgz','e').")")
394       call rename(tarfile.".gz",substitute(tarfile,'\.tar$','.tgz','e'))
395      endif
396     endif
397    endif
399    " support writing tarfiles across a network
400    if s:tblfile_{winnr()} =~ '^\a\+://'
401 "    call Decho("handle writing <".tarfile."> across network to <".s:tblfile_{winnr()}.">")
402     let tblfile= s:tblfile_{winnr()}
403     1split|enew
404     let binkeep= &binary
405     let eikeep = &ei
406     set binary ei=all
407     exe "e! ".fnameescape(tarfile)
408     call netrw#NetWrite(tblfile)
409     let &ei     = eikeep
410     let &binary = binkeep
411     q!
412     unlet s:tblfile_{winnr()}
413    endif
414   endif
415   
416   " cleanup and restore current directory
417   cd ..
418   call s:Rmdir("_ZIPVIM_")
419   exe "cd ".fnameescape(curdir)
420   setlocal nomod
422   let &report= repkeep
423 "  call Dret("tar#Write")
424 endfun
426 " ---------------------------------------------------------------------
427 " Rmdir: {{{2
428 fun! s:Rmdir(fname)
429 "  call Dfunc("Rmdir(fname<".a:fname.">)")
430   if has("unix")
431    call system("/bin/rm -rf -- ".s:Escape(a:fname,0))
432   elseif has("win32") || has("win95") || has("win64") || has("win16")
433    if &shell =~? "sh$"
434     call system("/bin/rm -rf -- ".s:Escape(a:fname,0))
435    else
436     call system("del /S ".s:Escape(a:fname,0))
437    endif
438   endif
439 "  call Dret("Rmdir")
440 endfun
442 " ---------------------------------------------------------------------
443 " s:Escape: {{{2
444 fun s:Escape(name,isfilt)
445   " shellescape() was added by patch 7.0.111
446   if exists("*shellescape")
447    if a:isfilt
448     let qnameq= shellescape(a:name,1)
449    else
450     let qnameq= shellescape(a:name)
451    endif
452   else
453    let qnameq= g:tar_shq . a:name . g:tar_shq
454   endif
455   return qnameq
456 endfun
458 " ---------------------------------------------------------------------
459 " Modelines And Restoration: {{{1
460 let &cpo= s:keepcpo
461 unlet s:keepcpo
462 " vim:ts=8 fdm=marker