xref: /vim-8.2.3635/runtime/autoload/zip.vim (revision d0bce504)
1" zip.vim: Handles browsing zipfiles
2"            AUTOLOAD PORTION
3" Date:		Jan 07, 2020
4" Version:	31
5" Maintainer:	Charles E Campbell <[email protected]>
6" License:	Vim License  (see vim's :help license)
7" Copyright:    Copyright (C) 2005-2019 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= "v31"
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: insure 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 "noswapfile noautocmd noswapfile 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  if &mouse != ""
147   noremap <silent> <buffer>	<leftmouse>	<leftmouse>:call <SID>ZipBrowseSelect()<cr>
148  endif
149
150  let &report= repkeep
151"  call Dret("zip#Browse")
152endfun
153
154" ---------------------------------------------------------------------
155" ZipBrowseSelect: {{{2
156fun! s:ZipBrowseSelect()
157"  call Dfunc("ZipBrowseSelect() zipfile<".b:zipfile."> curfile<".expand("%").">")
158  let repkeep= &report
159  set report=10
160  let fname= getline(".")
161
162  " sanity check
163  if fname =~ '^"'
164   let &report= repkeep
165"   call Dret("ZipBrowseSelect")
166   return
167  endif
168  if fname =~ '/$'
169   redraw!
170   echohl Error | echo "***error*** (zip#Browse) Please specify a file, not a directory" | echohl None
171"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
172   let &report= repkeep
173"   call Dret("ZipBrowseSelect")
174   return
175  endif
176
177"  call Decho("fname<".fname.">")
178
179  " get zipfile to the new-window
180  let zipfile = b:zipfile
181  let curfile = expand("%")
182"  call Decho("zipfile<".zipfile.">")
183"  call Decho("curfile<".curfile.">")
184
185  noswapfile new
186  if !exists("g:zip_nomax") || g:zip_nomax == 0
187   wincmd _
188  endif
189  let s:zipfile_{winnr()}= curfile
190"  call Decho("exe e ".fnameescape("zipfile:".zipfile.'::'.fname))
191  exe "noswapfile e ".fnameescape("zipfile:".zipfile.'::'.fname)
192  filetype detect
193
194  let &report= repkeep
195"  call Dret("ZipBrowseSelect : s:zipfile_".winnr()."<".s:zipfile_{winnr()}.">")
196endfun
197
198" ---------------------------------------------------------------------
199" zip#Read: {{{2
200fun! zip#Read(fname,mode)
201"  call Dfunc("zip#Read(fname<".a:fname.">,mode=".a:mode.")")
202  let repkeep= &report
203  set report=10
204
205  if has("unix")
206   let zipfile = substitute(a:fname,'zipfile:\(.\{-}\)::[^\\].*$','\1','')
207   let fname   = substitute(a:fname,'zipfile:.\{-}::\([^\\].*\)$','\1','')
208  else
209   let zipfile = substitute(a:fname,'^.\{-}zipfile:\(.\{-}\)::[^\\].*$','\1','')
210   let fname   = substitute(a:fname,'^.\{-}zipfile:.\{-}::\([^\\].*\)$','\1','')
211   let fname   = substitute(fname, '[', '[[]', 'g')
212  endif
213"  call Decho("zipfile<".zipfile.">")
214"  call Decho("fname  <".fname.">")
215  " sanity check
216  if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','',''))
217   redraw!
218   echohl Error | echo "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program" | echohl None
219"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
220   let &report= repkeep
221"   call Dret("zip#Write")
222   return
223  endif
224
225  " the following code does much the same thing as
226  "   exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1)
227  " but allows zipfile:... entries in quickfix lists
228  let temp = tempname()
229"  call Decho("using temp file<".temp.">")
230  let fn   = expand('%:p')
231  exe "sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp
232"  call Decho("exe sil! !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fnameescape(fname),1).' > '.temp)
233  sil exe 'keepalt file '.temp
234  sil keepj e!
235  sil exe 'keepalt file '.fnameescape(fn)
236  call delete(temp)
237
238  filetype detect
239
240  " cleanup
241  "  keepj 0d   " used to be needed for the ...r! ... method
242  set nomod
243
244  let &report= repkeep
245"  call Dret("zip#Read")
246endfun
247
248" ---------------------------------------------------------------------
249" zip#Write: {{{2
250fun! zip#Write(fname)
251"  call Dfunc("zip#Write(fname<".a:fname.">) zipfile_".winnr()."<".s:zipfile_{winnr()}.">")
252  let repkeep= &report
253  set report=10
254
255  " sanity checks
256  if !executable(substitute(g:zip_zipcmd,'\s\+.*$','',''))
257   redraw!
258   echohl Error | echo "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program" | echohl None
259"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
260   let &report= repkeep
261"   call Dret("zip#Write")
262   return
263  endif
264  if !exists("*mkdir")
265   redraw!
266   echohl Error | echo "***error*** (zip#Write) sorry, mkdir() doesn't work on your system" | echohl None
267"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
268   let &report= repkeep
269"   call Dret("zip#Write")
270   return
271  endif
272
273  let curdir= getcwd()
274  let tmpdir= tempname()
275"  call Decho("orig tempname<".tmpdir.">")
276  if tmpdir =~ '\.'
277   let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
278  endif
279"  call Decho("tmpdir<".tmpdir.">")
280  call mkdir(tmpdir,"p")
281
282  " attempt to change to the indicated directory
283  if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory")
284   let &report= repkeep
285"   call Dret("zip#Write")
286   return
287  endif
288"  call Decho("current directory now: ".getcwd())
289
290  " place temporary files under .../_ZIPVIM_/
291  if isdirectory("_ZIPVIM_")
292   call s:Rmdir("_ZIPVIM_")
293  endif
294  call mkdir("_ZIPVIM_")
295  cd _ZIPVIM_
296"  call Decho("current directory now: ".getcwd())
297
298  if has("unix")
299   let zipfile = substitute(a:fname,'zipfile:\(.\{-}\)::[^\\].*$','\1','')
300   let fname   = substitute(a:fname,'zipfile:.\{-}::\([^\\].*\)$','\1','')
301  else
302   let zipfile = substitute(a:fname,'^.\{-}zipfile:\(.\{-}\)::[^\\].*$','\1','')
303   let fname   = substitute(a:fname,'^.\{-}zipfile:.\{-}::\([^\\].*\)$','\1','')
304  endif
305"  call Decho("zipfile<".zipfile.">")
306"  call Decho("fname  <".fname.">")
307
308  if fname =~ '/'
309   let dirpath = substitute(fname,'/[^/]\+$','','e')
310   if has("win32unix") && executable("cygpath")
311    let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
312   endif
313"   call Decho("mkdir(dirpath<".dirpath.">,p)")
314   call mkdir(dirpath,"p")
315  endif
316  if zipfile !~ '/'
317   let zipfile= curdir.'/'.zipfile
318  endif
319"  call Decho("zipfile<".zipfile."> fname<".fname.">")
320
321  exe "w! ".fnameescape(fname)
322  if has("win32unix") && executable("cygpath")
323   let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
324  endif
325
326  if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
327    let fname = substitute(fname, '[', '[[]', 'g')
328  endif
329
330"  call Decho(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
331  call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
332  if v:shell_error != 0
333   redraw!
334   echohl Error | echo "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname | echohl None
335"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
336
337  elseif s:zipfile_{winnr()} =~ '^\a\+://'
338   " support writing zipfiles across a network
339   let netzipfile= s:zipfile_{winnr()}
340"   call Decho("handle writing <".zipfile."> across network as <".netzipfile.">")
341   1split|enew
342   let binkeep= &binary
343   let eikeep = &ei
344   set binary ei=all
345   exe "noswapfile e! ".fnameescape(zipfile)
346   call netrw#NetWrite(netzipfile)
347   let &ei     = eikeep
348   let &binary = binkeep
349   q!
350   unlet s:zipfile_{winnr()}
351  endif
352
353  " cleanup and restore current directory
354  cd ..
355  call s:Rmdir("_ZIPVIM_")
356  call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
357  call s:Rmdir(tmpdir)
358  setlocal nomod
359
360  let &report= repkeep
361"  call Dret("zip#Write")
362endfun
363
364" ---------------------------------------------------------------------
365" zip#Extract: extract a file from a zip archive {{{2
366fun! zip#Extract()
367"  call Dfunc("zip#Extract()")
368
369  let repkeep= &report
370  set report=10
371  let fname= getline(".")
372"  call Decho("fname<".fname.">")
373
374  " sanity check
375  if fname =~ '^"'
376   let &report= repkeep
377"   call Dret("zip#Extract")
378   return
379  endif
380  if fname =~ '/$'
381   redraw!
382   echohl Error | echo "***error*** (zip#Extract) Please specify a file, not a directory" | echohl None
383   let &report= repkeep
384"   call Dret("zip#Extract")
385   return
386  endif
387
388  " extract the file mentioned under the cursor
389"  call Decho("system(".g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell).")")
390  call system(g:zip_extractcmd." ".shellescape(b:zipfile)." ".shellescape(shell))
391"  call Decho("zipfile<".b:zipfile.">")
392  if v:shell_error != 0
393   echohl Error | echo "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!" | echohl NONE
394  elseif !filereadable(fname)
395   echohl Error | echo "***error*** attempted to extract ".fname." but it doesn't appear to be present!"
396  else
397   echo "***note*** successfully extracted ".fname
398  endif
399
400  " restore option
401  let &report= repkeep
402
403"  call Dret("zip#Extract")
404endfun
405
406" ---------------------------------------------------------------------
407" s:Escape: {{{2
408fun! s:Escape(fname,isfilt)
409"  call Dfunc("QuoteFileDir(fname<".a:fname."> isfilt=".a:isfilt.")")
410  if exists("*shellescape")
411   if a:isfilt
412    let qnameq= shellescape(a:fname,1)
413   else
414    let qnameq= shellescape(a:fname)
415   endif
416  else
417   let qnameq= g:zip_shq.escape(a:fname,g:zip_shq).g:zip_shq
418  endif
419"  call Dret("QuoteFileDir <".qnameq.">")
420  return qnameq
421endfun
422
423" ---------------------------------------------------------------------
424" ChgDir: {{{2
425fun! s:ChgDir(newdir,errlvl,errmsg)
426"  call Dfunc("ChgDir(newdir<".a:newdir."> errlvl=".a:errlvl."  errmsg<".a:errmsg.">)")
427
428  try
429   exe "cd ".fnameescape(a:newdir)
430  catch /^Vim\%((\a\+)\)\=:E344/
431   redraw!
432   if a:errlvl == s:NOTE
433    echo "***note*** ".a:errmsg
434   elseif a:errlvl == s:WARNING
435    echohl WarningMsg | echo "***warning*** ".a:errmsg | echohl NONE
436   elseif a:errlvl == s:ERROR
437    echohl Error | echo "***error*** ".a:errmsg | echohl NONE
438   endif
439"   call inputsave()|call input("Press <cr> to continue")|call inputrestore()
440"   call Dret("ChgDir 1")
441   return 1
442  endtry
443
444"  call Dret("ChgDir 0")
445  return 0
446endfun
447
448" ---------------------------------------------------------------------
449" s:Rmdir: {{{2
450fun! s:Rmdir(fname)
451"  call Dfunc("Rmdir(fname<".a:fname.">)")
452  if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
453   call system("rmdir /S/Q ".s:Escape(a:fname,0))
454  else
455   call system("/bin/rm -rf ".s:Escape(a:fname,0))
456  endif
457"  call Dret("Rmdir")
458endfun
459
460" ------------------------------------------------------------------------
461" Modelines And Restoration: {{{1
462let &cpo= s:keepcpo
463unlet s:keepcpo
464" vim:ts=8 fdm=marker
465