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