xref: /vim-8.2.3635/runtime/autoload/zip.vim (revision 577fadfc)
1" zip.vim: Handles browsing zipfiles
2"            AUTOLOAD PORTION
3" Date:		Sep 13, 2016
4" Version:	28
5" Maintainer:	Charles E Campbell <[email protected]>
6" License:	Vim License  (see vim's :help license)
7" Copyright:    Copyright (C) 2005-2013 Charles E. Campbell {{{1
8"               Permission is hereby granted to use and distribute this code,
9"               with or without modifications, provided that this copyright
10"               notice is copied with it. Like anything else that's free,
11"               zip.vim and zipPlugin.vim are provided *as is* and comes with
12"               no warranty of any kind, either expressed or implied. By using
13"               this plugin, you agree that in no event will the copyright
14"               holder be liable for any damages resulting from the use
15"               of this software.
16"redraw!|call DechoSep()|call inputsave()|call input("Press <cr> to continue")|call inputrestore()
17
18" ---------------------------------------------------------------------
19" Load Once: {{{1
20if &cp || exists("g:loaded_zip")
21 finish
22endif
23let g:loaded_zip= "v28"
24if v:version < 702
25 echohl WarningMsg
26 echo "***warning*** this version of zip needs vim 7.2 or later"
27 echohl Normal
28 finish
29endif
30let s:keepcpo= &cpo
31set cpo&vim
32"DechoTabOn
33
34let s:zipfile_escape = ' ?&;\'
35let s:ERROR          = 2
36let s:WARNING        = 1
37let s:NOTE           = 0
38
39" ---------------------------------------------------------------------
40"  Global Values: {{{1
41if !exists("g:zip_shq")
42 if &shq != ""
43  let g:zip_shq= &shq
44 elseif has("unix")
45  let g:zip_shq= "'"
46 else
47  let g:zip_shq= '"'
48 endif
49endif
50if !exists("g:zip_zipcmd")
51 let g:zip_zipcmd= "zip"
52endif
53if !exists("g:zip_unzipcmd")
54 let g:zip_unzipcmd= "unzip"
55endif
56if !exists("g:zip_extractcmd")
57 let g:zip_extractcmd= g:zip_unzipcmd
58endif
59
60" ----------------
61"  Functions: {{{1
62" ----------------
63
64" ---------------------------------------------------------------------
65" zip#Browse: {{{2
66fun! zip#Browse(zipfile)
67"  call Dfunc("zip#Browse(zipfile<".a:zipfile.">)")
68  " sanity check: ensure that the zipfile has "PK" as its first two letters
69  "               (zipped files have a leading PK as a "magic cookie")
70  if !filereadable(a:zipfile) || readfile(a:zipfile, "", 1)[0] !~ '^PK'
71   exe "noautocmd e ".fnameescape(a:zipfile)
72"   call Dret("zip#Browse : not a zipfile<".a:zipfile.">")
73   return
74"  else        " Decho
75"   call Decho("zip#Browse: a:zipfile<".a:zipfile."> passed PK test - it's a zip file")
76  endif
77
78  let repkeep= &report
79  set report=10
80
81  " sanity checks
82  if !exists("*fnameescape")
83   if &verbose > 1
84    echoerr "the zip plugin is not available (your vim doens't support fnameescape())"
85   endif
86   return
87  endif
88  if !executable(g:zip_unzipcmd)
89   redraw!
90   echohl Error | echo "***error*** (zip#Browse) unzip not available on your system"
91"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
92   let &report= repkeep
93"   call Dret("zip#Browse")
94   return
95  endif
96  if !filereadable(a:zipfile)
97   if a:zipfile !~# '^\a\+://'
98    " if it's an url, don't complain, let url-handlers such as vim do its thing
99    redraw!
100    echohl Error | echo "***error*** (zip#Browse) File not readable<".a:zipfile.">" | echohl None
101"    call inputsave()|call input("Press <cr> to continue")|call inputrestore()
102   endif
103   let &report= repkeep
104"   call Dret("zip#Browse : file<".a:zipfile."> not readable")
105   return
106  endif
107"  call Decho("passed sanity checks")
108  if &ma != 1
109   set ma
110  endif
111  let b:zipfile= a:zipfile
112
113  setlocal noswapfile
114  setlocal buftype=nofile
115  setlocal bufhidden=hide
116  setlocal nobuflisted
117  setlocal nowrap
118  set ft=tar
119
120  " give header
121  call append(0, ['" zip.vim version '.g:loaded_zip,
122 \                '" Browsing zipfile '.a:zipfile,
123 \                '" Select a file with cursor and press ENTER'])
124  keepj $
125
126"  call Decho("exe silent r! ".g:zip_unzipcmd." -l -- ".s:Escape(a:zipfile,1))
127  exe "keepj sil! r! ".g:zip_unzipcmd." -Z -1 -- ".s:Escape(a:zipfile,1)
128  if v:shell_error != 0
129   redraw!
130   echohl WarningMsg | echo "***warning*** (zip#Browse) ".fnameescape(a:zipfile)." is not a zip file" | echohl None
131"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
132   keepj sil! %d
133   let eikeep= &ei
134   set ei=BufReadCmd,FileReadCmd
135   exe "keepj r ".fnameescape(a:zipfile)
136   let &ei= eikeep
137   keepj 1d
138"   call Dret("zip#Browse")
139   return
140  endif
141
142  " Maps associated with zip plugin
143  setlocal noma nomod ro
144  noremap <silent> <buffer> <cr>	:call <SID>ZipBrowseSelect()<cr>
145  noremap <silent> <buffer> x		:call zip#Extract()<cr>
146
147  let &report= repkeep
148"  call Dret("zip#Browse")
149endfun
150
151" ---------------------------------------------------------------------
152" ZipBrowseSelect: {{{2
153fun! s:ZipBrowseSelect()
154"  call Dfunc("ZipBrowseSelect() zipfile<".b:zipfile."> curfile<".expand("%").">")
155  let repkeep= &report
156  set report=10
157  let fname= getline(".")
158
159  " sanity check
160  if fname =~ '^"'
161   let &report= repkeep
162"   call Dret("ZipBrowseSelect")
163   return
164  endif
165  if fname =~ '/$'
166   redraw!
167   echohl Error | echo "***error*** (zip#Browse) Please specify a file, not a directory" | echohl None
168"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
169   let &report= repkeep
170"   call Dret("ZipBrowseSelect")
171   return
172  endif
173
174"  call Decho("fname<".fname.">")
175
176  " get zipfile to the new-window
177  let zipfile = b:zipfile
178  let curfile= expand("%")
179"  call Decho("zipfile<".zipfile.">")
180"  call Decho("curfile<".curfile.">")
181
182  new
183  if !exists("g:zip_nomax") || g:zip_nomax == 0
184   wincmd _
185  endif
186  let s:zipfile_{winnr()}= curfile
187"  call Decho("exe e ".fnameescape("zipfile:".zipfile.'::'.fname))
188  exe "e ".fnameescape("zipfile:".zipfile.'::'.fname)
189  filetype detect
190
191  let &report= repkeep
192"  call Dret("ZipBrowseSelect : s:zipfile_".winnr()."<".s:zipfile_{winnr()}.">")
193endfun
194
195" ---------------------------------------------------------------------
196" zip#Read: {{{2
197fun! zip#Read(fname,mode)
198"  call Dfunc("zip#Read(fname<".a:fname.">,mode=".a:mode.")")
199  let repkeep= &report
200  set report=10
201
202  if has("unix")
203   let zipfile = substitute(a:fname,'zipfile:\(.\{-}\)::[^\\].*$','\1','')
204   let fname   = substitute(a:fname,'zipfile:.\{-}::\([^\\].*\)$','\1','')
205  else
206   let zipfile = substitute(a:fname,'^.\{-}zipfile:\(.\{-}\)::[^\\].*$','\1','')
207   let fname   = substitute(a:fname,'^.\{-}zipfile:.\{-}::\([^\\].*\)$','\1','')
208   let fname   = substitute(fname, '[', '[[]', 'g')
209  endif
210"  call Decho("zipfile<".zipfile.">")
211"  call Decho("fname  <".fname.">")
212  " sanity check
213  if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','',''))
214   redraw!
215   echohl Error | echo "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program" | echohl None
216"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
217   let &report= repkeep
218"   call Dret("zip#Write")
219   return
220  endif
221
222  " the following code does much the same thing as
223  "   exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1)
224  " but allows zipfile:... entries in quickfix lists
225  let temp = tempname()
226"  call Decho("using temp file<".temp.">")
227  let fn   = expand('%:p')
228  exe "sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp
229"  call Decho("exe sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp)
230  sil exe 'keepalt file '.temp
231  sil keepj e!
232  sil exe 'keepalt file '.fnameescape(fn)
233  call delete(temp)
234
235  filetype detect
236
237  " cleanup
238  "  keepj 0d   " used to be needed for the ...r! ... method
239  set nomod
240
241  let &report= repkeep
242"  call Dret("zip#Read")
243endfun
244
245" ---------------------------------------------------------------------
246" zip#Write: {{{2
247fun! zip#Write(fname)
248"  call Dfunc("zip#Write(fname<".a:fname.">) zipfile_".winnr()."<".s:zipfile_{winnr()}.">")
249  let repkeep= &report
250  set report=10
251
252  " sanity checks
253  if !executable(substitute(g:zip_zipcmd,'\s\+.*$','',''))
254   redraw!
255   echohl Error | echo "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program" | echohl None
256"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
257   let &report= repkeep
258"   call Dret("zip#Write")
259   return
260  endif
261  if !exists("*mkdir")
262   redraw!
263   echohl Error | echo "***error*** (zip#Write) sorry, mkdir() doesn't work on your system" | echohl None
264"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
265   let &report= repkeep
266"   call Dret("zip#Write")
267   return
268  endif
269
270  let curdir= getcwd()
271  let tmpdir= tempname()
272"  call Decho("orig tempname<".tmpdir.">")
273  if tmpdir =~ '\.'
274   let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
275  endif
276"  call Decho("tmpdir<".tmpdir.">")
277  call mkdir(tmpdir,"p")
278
279  " attempt to change to the indicated directory
280  if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory")
281   let &report= repkeep
282"   call Dret("zip#Write")
283   return
284  endif
285"  call Decho("current directory now: ".getcwd())
286
287  " place temporary files under .../_ZIPVIM_/
288  if isdirectory("_ZIPVIM_")
289   call s:Rmdir("_ZIPVIM_")
290  endif
291  call mkdir("_ZIPVIM_")
292  cd _ZIPVIM_
293"  call Decho("current directory now: ".getcwd())
294
295  if has("unix")
296   let zipfile = substitute(a:fname,'zipfile:\(.\{-}\)::[^\\].*$','\1','')
297   let fname   = substitute(a:fname,'zipfile:.\{-}::\([^\\].*\)$','\1','')
298  else
299   let zipfile = substitute(a:fname,'^.\{-}zipfile:\(.\{-}\)::[^\\].*$','\1','')
300   let fname   = substitute(a:fname,'^.\{-}zipfile:.\{-}::\([^\\].*\)$','\1','')
301  endif
302"  call Decho("zipfile<".zipfile.">")
303"  call Decho("fname  <".fname.">")
304
305  if fname =~ '/'
306   let dirpath = substitute(fname,'/[^/]\+$','','e')
307   if has("win32unix") && executable("cygpath")
308    let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
309   endif
310"   call Decho("mkdir(dirpath<".dirpath.">,p)")
311   call mkdir(dirpath,"p")
312  endif
313  if zipfile !~ '/'
314   let zipfile= curdir.'/'.zipfile
315  endif
316"  call Decho("zipfile<".zipfile."> fname<".fname.">")
317
318  exe "w! ".fnameescape(fname)
319  if has("win32unix") && executable("cygpath")
320   let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
321  endif
322
323  if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
324    let fname = substitute(fname, '[', '[[]', 'g')
325  endif
326
327"  call Decho(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
328  call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
329  if v:shell_error != 0
330   redraw!
331   echohl Error | echo "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname | echohl None
332"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
333
334  elseif s:zipfile_{winnr()} =~ '^\a\+://'
335   " support writing zipfiles across a network
336   let netzipfile= s:zipfile_{winnr()}
337"   call Decho("handle writing <".zipfile."> across network as <".netzipfile.">")
338   1split|enew
339   let binkeep= &binary
340   let eikeep = &ei
341   set binary ei=all
342   exe "e! ".fnameescape(zipfile)
343   call netrw#NetWrite(netzipfile)
344   let &ei     = eikeep
345   let &binary = binkeep
346   q!
347   unlet s:zipfile_{winnr()}
348  endif
349
350  " cleanup and restore current directory
351  cd ..
352  call s:Rmdir("_ZIPVIM_")
353  call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
354  call s:Rmdir(tmpdir)
355  setlocal nomod
356
357  let &report= repkeep
358"  call Dret("zip#Write")
359endfun
360
361" ---------------------------------------------------------------------
362" zip#Extract: extract a file from a zip archive {{{2
363fun! zip#Extract()
364"  call Dfunc("zip#Extract()")
365
366  let repkeep= &report
367  set report=10
368  let fname= getline(".")
369"  call Decho("fname<".fname.">")
370
371  " sanity check
372  if fname =~ '^"'
373   let &report= repkeep
374"   call Dret("zip#Extract")
375   return
376  endif
377  if fname =~ '/$'
378   redraw!
379   echohl Error | echo "***error*** (zip#Extract) Please specify a file, not a directory" | echohl None
380   let &report= repkeep
381"   call Dret("zip#Extract")
382   return
383  endif
384
385  " extract the file mentioned under the cursor
386"  call Decho("system(".g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell).")")
387  call system(g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell))
388"  call Decho("zipfile<".b:zipfile.">")
389  if v:shell_error != 0
390   echohl Error | echo "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!" | echohl NONE
391  elseif !filereadable(fname)
392   echohl Error | echo "***error*** attempted to extract ".fname." but it doesn't appear to be present!"
393  else
394   echo "***note*** successfully extracted ".fname
395  endif
396
397  " restore option
398  let &report= repkeep
399
400"  call Dret("zip#Extract")
401endfun
402
403" ---------------------------------------------------------------------
404" s:Escape: {{{2
405fun! s:Escape(fname,isfilt)
406"  call Dfunc("QuoteFileDir(fname<".a:fname."> isfilt=".a:isfilt.")")
407  if exists("*shellescape")
408   if a:isfilt
409    let qnameq= shellescape(a:fname,1)
410   else
411    let qnameq= shellescape(a:fname)
412   endif
413  else
414   let qnameq= g:zip_shq.escape(a:fname,g:zip_shq).g:zip_shq
415  endif
416"  call Dret("QuoteFileDir <".qnameq.">")
417  return qnameq
418endfun
419
420" ---------------------------------------------------------------------
421" ChgDir: {{{2
422fun! s:ChgDir(newdir,errlvl,errmsg)
423"  call Dfunc("ChgDir(newdir<".a:newdir."> errlvl=".a:errlvl."  errmsg<".a:errmsg.">)")
424
425  try
426   exe "cd ".fnameescape(a:newdir)
427  catch /^Vim\%((\a\+)\)\=:E344/
428   redraw!
429   if a:errlvl == s:NOTE
430    echo "***note*** ".a:errmsg
431   elseif a:errlvl == s:WARNING
432    echohl WarningMsg | echo "***warning*** ".a:errmsg | echohl NONE
433   elseif a:errlvl == s:ERROR
434    echohl Error | echo "***error*** ".a:errmsg | echohl NONE
435   endif
436"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
437"   call Dret("ChgDir 1")
438   return 1
439  endtry
440
441"  call Dret("ChgDir 0")
442  return 0
443endfun
444
445" ---------------------------------------------------------------------
446" s:Rmdir: {{{2
447fun! s:Rmdir(fname)
448"  call Dfunc("Rmdir(fname<".a:fname.">)")
449  if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
450   call system("rmdir /S/Q ".s:Escape(a:fname,0))
451  else
452   call system("/bin/rm -rf ".s:Escape(a:fname,0))
453  endif
454"  call Dret("Rmdir")
455endfun
456
457" ------------------------------------------------------------------------
458" Modelines And Restoration: {{{1
459let &cpo= s:keepcpo
460unlet s:keepcpo
461" vim:ts=8 fdm=marker
462