blob: dae4ddeb9921eeb8582eabb3d4defd0960a66f1a [file] [log] [blame]
Bram Moolenaar60a795a2005-09-16 21:55:43 +00001" zip.vim: Handles browsing zipfiles
Damien2cad9412024-07-24 20:07:00 +02002" AUTOLOAD PORTION
Christian Brabandtbc29ea62024-08-21 08:18:44 +02003" Date: 2024 Aug 21
Christian Brabandta336d8f2024-08-05 21:26:46 +02004" Version: 34
Christian Brabandtf9ca1392024-02-19 20:37:11 +01005" Maintainer: This runtime file is looking for a new maintainer.
6" Former Maintainer: Charles E Campbell
Christian Brabandt1c673422024-06-15 14:49:24 +02007" Last Change:
Damien2cad9412024-07-24 20:07:00 +02008" 2024 Jun 16 by Vim Project: handle whitespace on Windows properly (#14998)
9" 2024 Jul 23 by Vim Project: fix 'x' command
10" 2024 Jul 24 by Vim Project: use delete() function
Damienf0e9b722024-08-05 20:21:18 +020011" 2024 Jul 30 by Vim Project: fix opening remote zipfile
zeertzjqc5bdd662024-08-04 18:35:50 +020012" 2024 Aug 04 by Vim Project: escape '[' in name of file to be extracted
Damienf0e9b722024-08-05 20:21:18 +020013" 2024 Aug 05 by Vim Project: workaround for the FreeBSD's unzip
Christian Brabandta63f66e2024-08-05 20:47:34 +020014" 2024 Aug 05 by Vim Project: clean-up and make it work with shellslash on Windows
Christian Brabandt7790ea02024-08-20 22:41:52 +020015" 2024 Aug 18 by Vim Project: correctly handle special globbing chars
Christian Brabandtbc29ea62024-08-21 08:18:44 +020016" 2024 Aug 21 by Vim Project: simplify condition to detect MS-Windows
Christian Brabandtf209dcd2025-03-12 22:04:01 +010017" 2025 Mar 11 by Vim Project: handle filenames with leading '-' correctly
Bram Moolenaar9964e462007-05-05 17:54:07 +000018" License: Vim License (see vim's :help license)
Christian Brabandt1c673422024-06-15 14:49:24 +020019" Copyright: Copyright (C) 2005-2019 Charles E. Campbell {{{1
20" Permission is hereby granted to use and distribute this code,
21" with or without modifications, provided that this copyright
22" notice is copied with it. Like anything else that's free,
23" zip.vim and zipPlugin.vim are provided *as is* and comes with
24" no warranty of any kind, either expressed or implied. By using
25" this plugin, you agree that in no event will the copyright
26" holder be liable for any damages resulting from the use
27" of this software.
Bram Moolenaar60a795a2005-09-16 21:55:43 +000028
29" ---------------------------------------------------------------------
Bram Moolenaar9964e462007-05-05 17:54:07 +000030" Load Once: {{{1
Bram Moolenaar00a927d2010-05-14 23:24:24 +020031if &cp || exists("g:loaded_zip")
Bram Moolenaar60a795a2005-09-16 21:55:43 +000032 finish
33endif
Christian Brabandta336d8f2024-08-05 21:26:46 +020034let g:loaded_zip= "v34"
Bram Moolenaar00a927d2010-05-14 23:24:24 +020035let s:keepcpo= &cpo
36set cpo&vim
Bram Moolenaar60a795a2005-09-16 21:55:43 +000037
Bram Moolenaardb552d602006-03-23 22:59:57 +000038let s:zipfile_escape = ' ?&;\'
Bram Moolenaar9964e462007-05-05 17:54:07 +000039let s:ERROR = 2
40let s:WARNING = 1
41let s:NOTE = 0
42
43" ---------------------------------------------------------------------
44" Global Values: {{{1
45if !exists("g:zip_shq")
Bram Moolenaar446cb832008-06-24 21:56:24 +000046 if &shq != ""
47 let g:zip_shq= &shq
48 elseif has("unix")
Bram Moolenaar9964e462007-05-05 17:54:07 +000049 let g:zip_shq= "'"
50 else
51 let g:zip_shq= '"'
52 endif
53endif
Bram Moolenaarccc18222007-05-10 18:25:20 +000054if !exists("g:zip_zipcmd")
55 let g:zip_zipcmd= "zip"
56endif
57if !exists("g:zip_unzipcmd")
58 let g:zip_unzipcmd= "unzip"
59endif
Bram Moolenaard0796902016-09-16 20:02:31 +020060if !exists("g:zip_extractcmd")
61 let g:zip_extractcmd= g:zip_unzipcmd
62endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +000063
Christian Brabandt8d529262024-08-06 18:35:00 +020064" ---------------------------------------------------------------------
65" required early
66" s:Mess: {{{2
67fun! s:Mess(group, msg)
68 redraw!
69 exe "echohl " . a:group
70 echomsg a:msg
71 echohl Normal
72endfun
73
Christian Brabandte2d9b0d2024-08-07 08:13:32 +020074if v:version < 901
75 " required for defer
76 call s:Mess('WarningMsg', "***warning*** this version of zip needs vim 9.1 or later")
Christian Brabandt8d529262024-08-06 18:35:00 +020077 finish
78endif
Christian Brabandt7790ea02024-08-20 22:41:52 +020079" sanity checks
80if !executable(g:zip_unzipcmd)
81 call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
82 finish
83endif
D. Ben Knoblecd8a3ea2023-11-04 05:11:17 -040084if !dist#vim#IsSafeExecutable('zip', g:zip_unzipcmd)
Christian Brabandt8d529262024-08-06 18:35:00 +020085 call s:Mess('Error', "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!")
Christian Brabandt816fbcc2023-08-31 23:52:30 +020086 finish
87endif
Anton Sharonov67c951d2023-09-05 21:03:27 +020088
Bram Moolenaar60a795a2005-09-16 21:55:43 +000089" ----------------
90" Functions: {{{1
91" ----------------
92
93" ---------------------------------------------------------------------
94" zip#Browse: {{{2
95fun! zip#Browse(zipfile)
Damienc4be0662024-07-30 19:14:35 +020096 " sanity check: ensure that the zipfile has "PK" as its first two letters
97 " (zip files have a leading PK as a "magic cookie")
98 if filereadable(a:zipfile) && readblob(a:zipfile, 0, 2) != 0z50.4B
99 exe "noswapfile noautocmd e " .. fnameescape(a:zipfile)
Bram Moolenaar94f76b72013-07-04 22:50:40 +0200100 return
Bram Moolenaar94f76b72013-07-04 22:50:40 +0200101 endif
102
Christian Brabandt19636be2024-08-05 21:00:07 +0200103 let dict = s:SetSaneOpts()
Christian Brabandtafea6b92024-08-06 18:50:59 +0200104 defer s:RestoreOpts(dict)
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000105
106 " sanity checks
Bram Moolenaarccc18222007-05-10 18:25:20 +0000107 if !executable(g:zip_unzipcmd)
Christian Brabandt8d529262024-08-06 18:35:00 +0200108 call s:Mess('Error', "***error*** (zip#Browse) unzip not available on your system")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000109 return
110 endif
111 if !filereadable(a:zipfile)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000112 if a:zipfile !~# '^\a\+://'
Bram Moolenaar8024f932020-01-14 19:29:13 +0100113 " if it's an url, don't complain, let url-handlers such as vim do its thing
Christian Brabandt8d529262024-08-06 18:35:00 +0200114 call s:Mess('Error', "***error*** (zip#Browse) File not readable <".a:zipfile.">")
Bram Moolenaara5792f52005-11-23 21:25:05 +0000115 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000116 return
117 endif
118 if &ma != 1
119 set ma
120 endif
Bram Moolenaarccc18222007-05-10 18:25:20 +0000121 let b:zipfile= a:zipfile
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000122
123 setlocal noswapfile
124 setlocal buftype=nofile
125 setlocal bufhidden=hide
126 setlocal nobuflisted
127 setlocal nowrap
Bram Moolenaar519cc552021-11-16 19:18:26 +0000128
129 " Oct 12, 2021: need to re-use Bram's syntax/tar.vim.
130 " Setting the filetype to zip doesn't do anything (currently),
131 " but it is perhaps less confusing to curious perusers who do
132 " a :echo &ft
133 setf zip
134 run! syntax/tar.vim
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000135
136 " give header
Bram Moolenaar251e1912011-06-19 05:09:16 +0200137 call append(0, ['" zip.vim version '.g:loaded_zip,
Bram Moolenaar6be7f872012-01-20 21:08:56 +0100138 \ '" Browsing zipfile '.a:zipfile,
139 \ '" Select a file with cursor and press ENTER'])
Bram Moolenaar251e1912011-06-19 05:09:16 +0200140 keepj $
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000141
Damienf0e9b722024-08-05 20:21:18 +0200142 exe $"keepj sil r! {g:zip_unzipcmd} -Z1 -- {s:Escape(a:zipfile, 1)}"
Bram Moolenaard68071d2006-05-02 22:08:30 +0000143 if v:shell_error != 0
Christian Brabandt8d529262024-08-06 18:35:00 +0200144 call s:Mess('WarningMsg', "***warning*** (zip#Browse) ".fnameescape(a:zipfile)." is not a zip file")
Bram Moolenaar251e1912011-06-19 05:09:16 +0200145 keepj sil! %d
Bram Moolenaard68071d2006-05-02 22:08:30 +0000146 let eikeep= &ei
147 set ei=BufReadCmd,FileReadCmd
Bram Moolenaar251e1912011-06-19 05:09:16 +0200148 exe "keepj r ".fnameescape(a:zipfile)
Bram Moolenaard68071d2006-05-02 22:08:30 +0000149 let &ei= eikeep
Bram Moolenaar251e1912011-06-19 05:09:16 +0200150 keepj 1d
Bram Moolenaard68071d2006-05-02 22:08:30 +0000151 return
152 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000153
Bram Moolenaard0796902016-09-16 20:02:31 +0200154 " Maps associated with zip plugin
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000155 setlocal noma nomod ro
Bram Moolenaar29634562020-01-09 21:46:04 +0100156 noremap <silent> <buffer> <cr> :call <SID>ZipBrowseSelect()<cr>
157 noremap <silent> <buffer> x :call zip#Extract()<cr>
158 if &mouse != ""
159 noremap <silent> <buffer> <leftmouse> <leftmouse>:call <SID>ZipBrowseSelect()<cr>
160 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000161
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000162endfun
163
164" ---------------------------------------------------------------------
165" ZipBrowseSelect: {{{2
166fun! s:ZipBrowseSelect()
Christian Brabandt19636be2024-08-05 21:00:07 +0200167 let dict = s:SetSaneOpts()
Christian Brabandtafea6b92024-08-06 18:50:59 +0200168 defer s:RestoreOpts(dict)
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000169 let fname= getline(".")
Bram Moolenaar71badf92023-04-22 22:40:14 +0100170 if !exists("b:zipfile")
Bram Moolenaar71badf92023-04-22 22:40:14 +0100171 return
172 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000173
174 " sanity check
175 if fname =~ '^"'
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000176 return
177 endif
178 if fname =~ '/$'
Christian Brabandt8d529262024-08-06 18:35:00 +0200179 call s:Mess('Error', "***error*** (zip#Browse) Please specify a file, not a directory")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000180 return
181 endif
182
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000183 " get zipfile to the new-window
Bram Moolenaarccc18222007-05-10 18:25:20 +0000184 let zipfile = b:zipfile
Bram Moolenaar29634562020-01-09 21:46:04 +0100185 let curfile = expand("%")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000186
Bram Moolenaar29634562020-01-09 21:46:04 +0100187 noswapfile new
Bram Moolenaar446cb832008-06-24 21:56:24 +0000188 if !exists("g:zip_nomax") || g:zip_nomax == 0
189 wincmd _
190 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000191 let s:zipfile_{winnr()}= curfile
Bram Moolenaar519cc552021-11-16 19:18:26 +0000192 exe "noswapfile e ".fnameescape("zipfile://".zipfile.'::'.fname)
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000193 filetype detect
194
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000195endfun
196
197" ---------------------------------------------------------------------
198" zip#Read: {{{2
199fun! zip#Read(fname,mode)
Christian Brabandt19636be2024-08-05 21:00:07 +0200200 let dict = s:SetSaneOpts()
Christian Brabandtafea6b92024-08-06 18:50:59 +0200201 defer s:RestoreOpts(dict)
Bram Moolenaar36c31f72005-11-28 23:01:53 +0000202
Bram Moolenaard68071d2006-05-02 22:08:30 +0000203 if has("unix")
Bram Moolenaar519cc552021-11-16 19:18:26 +0000204 let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
205 let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
Bram Moolenaard68071d2006-05-02 22:08:30 +0000206 else
Bram Moolenaar519cc552021-11-16 19:18:26 +0000207 let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
208 let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
Bram Moolenaard68071d2006-05-02 22:08:30 +0000209 endif
Christian Brabandt7790ea02024-08-20 22:41:52 +0200210 let fname = fname->substitute('[', '[[]', 'g')->escape('?*\\')
Bram Moolenaard0796902016-09-16 20:02:31 +0200211 " sanity check
212 if !executable(substitute(g:zip_unzipcmd,'\s\+.*$','',''))
Christian Brabandt8d529262024-08-06 18:35:00 +0200213 call s:Mess('Error', "***error*** (zip#Read) sorry, your system doesn't appear to have the ".g:zip_unzipcmd." program")
Bram Moolenaard0796902016-09-16 20:02:31 +0200214 return
215 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000216
Bram Moolenaarff034192013-04-24 18:51:19 +0200217 " the following code does much the same thing as
zeertzjqc5bdd662024-08-04 18:35:50 +0200218 " exe "keepj sil! r! ".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1)
Bram Moolenaar519cc552021-11-16 19:18:26 +0000219 " but allows zipfile://... entries in quickfix lists
Bram Moolenaarff034192013-04-24 18:51:19 +0200220 let temp = tempname()
221 let fn = expand('%:p')
Damienf0e9b722024-08-05 20:21:18 +0200222 exe "sil !".g:zip_unzipcmd." -p -- ".s:Escape(zipfile,1)." ".s:Escape(fname,1).' > '.temp
Bram Moolenaarff034192013-04-24 18:51:19 +0200223 sil exe 'keepalt file '.temp
224 sil keepj e!
225 sil exe 'keepalt file '.fnameescape(fn)
226 call delete(temp)
227
Bram Moolenaar251e1912011-06-19 05:09:16 +0200228 filetype detect
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000229
230 " cleanup
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000231 set nomod
232
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000233endfun
234
235" ---------------------------------------------------------------------
236" zip#Write: {{{2
237fun! zip#Write(fname)
Christian Brabandt19636be2024-08-05 21:00:07 +0200238 let dict = s:SetSaneOpts()
Christian Brabandtafea6b92024-08-06 18:50:59 +0200239 defer s:RestoreOpts(dict)
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000240
241 " sanity checks
Bram Moolenaard0796902016-09-16 20:02:31 +0200242 if !executable(substitute(g:zip_zipcmd,'\s\+.*$','',''))
Christian Brabandt8d529262024-08-06 18:35:00 +0200243 call s:Mess('Error', "***error*** (zip#Write) sorry, your system doesn't appear to have the ".g:zip_zipcmd." program")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000244 return
245 endif
246 if !exists("*mkdir")
Christian Brabandt8d529262024-08-06 18:35:00 +0200247 call s:Mess('Error', "***error*** (zip#Write) sorry, mkdir() doesn't work on your system")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000248 return
249 endif
250
251 let curdir= getcwd()
252 let tmpdir= tempname()
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000253 if tmpdir =~ '\.'
254 let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
255 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000256 call mkdir(tmpdir,"p")
257
258 " attempt to change to the indicated directory
Bram Moolenaar9964e462007-05-05 17:54:07 +0000259 if s:ChgDir(tmpdir,s:ERROR,"(zip#Write) cannot cd to temporary directory")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000260 return
Bram Moolenaar9964e462007-05-05 17:54:07 +0000261 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000262
263 " place temporary files under .../_ZIPVIM_/
264 if isdirectory("_ZIPVIM_")
Damien2cad9412024-07-24 20:07:00 +0200265 call delete("_ZIPVIM_", "rf")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000266 endif
267 call mkdir("_ZIPVIM_")
268 cd _ZIPVIM_
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000269
Bram Moolenaard68071d2006-05-02 22:08:30 +0000270 if has("unix")
Bram Moolenaar519cc552021-11-16 19:18:26 +0000271 let zipfile = substitute(a:fname,'zipfile://\(.\{-}\)::[^\\].*$','\1','')
272 let fname = substitute(a:fname,'zipfile://.\{-}::\([^\\].*\)$','\1','')
Bram Moolenaard68071d2006-05-02 22:08:30 +0000273 else
Bram Moolenaar519cc552021-11-16 19:18:26 +0000274 let zipfile = substitute(a:fname,'^.\{-}zipfile://\(.\{-}\)::[^\\].*$','\1','')
275 let fname = substitute(a:fname,'^.\{-}zipfile://.\{-}::\([^\\].*\)$','\1','')
Bram Moolenaard68071d2006-05-02 22:08:30 +0000276 endif
Bram Moolenaarc7486e02005-12-29 22:48:26 +0000277
278 if fname =~ '/'
279 let dirpath = substitute(fname,'/[^/]\+$','','e')
Bram Moolenaarff034192013-04-24 18:51:19 +0200280 if has("win32unix") && executable("cygpath")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000281 let dirpath = substitute(system("cygpath ".s:Escape(dirpath,0)),'\n','','e')
Bram Moolenaarc7486e02005-12-29 22:48:26 +0000282 endif
283 call mkdir(dirpath,"p")
284 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000285 if zipfile !~ '/'
286 let zipfile= curdir.'/'.zipfile
287 endif
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000288
Bram Moolenaarc236c162008-07-13 17:41:49 +0000289 exe "w! ".fnameescape(fname)
Bram Moolenaarff034192013-04-24 18:51:19 +0200290 if has("win32unix") && executable("cygpath")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000291 let zipfile = substitute(system("cygpath ".s:Escape(zipfile,0)),'\n','','e')
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000292 endif
293
Bram Moolenaar9964e462007-05-05 17:54:07 +0000294 if (has("win32") || has("win95") || has("win64") || has("win16")) && &shell !~? 'sh$'
295 let fname = substitute(fname, '[', '[[]', 'g')
296 endif
297
Bram Moolenaare37d50a2008-08-06 17:06:04 +0000298 call system(g:zip_zipcmd." -u ".s:Escape(fnamemodify(zipfile,":p"),0)." ".s:Escape(fname,0))
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000299 if v:shell_error != 0
Christian Brabandt8d529262024-08-06 18:35:00 +0200300 call s:Mess('Error', "***error*** (zip#Write) sorry, unable to update ".zipfile." with ".fname)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000301
302 elseif s:zipfile_{winnr()} =~ '^\a\+://'
303 " support writing zipfiles across a network
304 let netzipfile= s:zipfile_{winnr()}
Bram Moolenaara5792f52005-11-23 21:25:05 +0000305 1split|enew
306 let binkeep= &binary
307 let eikeep = &ei
308 set binary ei=all
Bram Moolenaar29634562020-01-09 21:46:04 +0100309 exe "noswapfile e! ".fnameescape(zipfile)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000310 call netrw#NetWrite(netzipfile)
311 let &ei = eikeep
312 let &binary = binkeep
313 q!
314 unlet s:zipfile_{winnr()}
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000315 endif
Damien2cad9412024-07-24 20:07:00 +0200316
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000317 " cleanup and restore current directory
318 cd ..
Damien2cad9412024-07-24 20:07:00 +0200319 call delete("_ZIPVIM_", "rf")
Bram Moolenaar9964e462007-05-05 17:54:07 +0000320 call s:ChgDir(curdir,s:WARNING,"(zip#Write) unable to return to ".curdir."!")
Damien2cad9412024-07-24 20:07:00 +0200321 call delete(tmpdir, "rf")
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000322 setlocal nomod
323
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000324endfun
325
326" ---------------------------------------------------------------------
Bram Moolenaard0796902016-09-16 20:02:31 +0200327" zip#Extract: extract a file from a zip archive {{{2
328fun! zip#Extract()
Bram Moolenaard0796902016-09-16 20:02:31 +0200329
Christian Brabandt19636be2024-08-05 21:00:07 +0200330 let dict = s:SetSaneOpts()
Christian Brabandtafea6b92024-08-06 18:50:59 +0200331 defer s:RestoreOpts(dict)
Bram Moolenaard0796902016-09-16 20:02:31 +0200332 let fname= getline(".")
Bram Moolenaard0796902016-09-16 20:02:31 +0200333
334 " sanity check
335 if fname =~ '^"'
Bram Moolenaard0796902016-09-16 20:02:31 +0200336 return
337 endif
338 if fname =~ '/$'
Christian Brabandt8d529262024-08-06 18:35:00 +0200339 call s:Mess('Error', "***error*** (zip#Extract) Please specify a file, not a directory")
Bram Moolenaard0796902016-09-16 20:02:31 +0200340 return
341 endif
Christian Brabandt7790ea02024-08-20 22:41:52 +0200342 if filereadable(fname)
343 call s:Mess('Error', "***error*** (zip#Extract) <" .. fname .."> already exists in directory, not overwriting!")
344 return
345 endif
346 let target = fname->substitute('\[', '[[]', 'g')
Christian Brabandtf209dcd2025-03-12 22:04:01 +0100347 " unzip 6.0 does not support -- to denote end-of-arguments
348 " unzip 6.1 (2010) apparently supports, it, but hasn't been released
349 " so the workaround is to use glob '[-]' so that it won't be considered an argument
350 " else, it would be possible to use 'unzip -o <file.zip> '-d/tmp' to extract the whole archive
351 let target = target->substitute('^-', '[&]', '')
Christian Brabandtbc29ea62024-08-21 08:18:44 +0200352 if &shell =~ 'cmd' && has("win32")
Christian Brabandt7790ea02024-08-20 22:41:52 +0200353 let target = target
354 \ ->substitute('[?*]', '[&]', 'g')
355 \ ->substitute('[\\]', '?', 'g')
356 \ ->shellescape()
357 " there cannot be a file name with '\' in its name, unzip replaces it by _
358 let fname = fname->substitute('[\\?*]', '_', 'g')
359 else
360 let target = target->escape('*?\\')->shellescape()
361 endif
Bram Moolenaard0796902016-09-16 20:02:31 +0200362
363 " extract the file mentioned under the cursor
Christian Brabandt7790ea02024-08-20 22:41:52 +0200364 call system($"{g:zip_extractcmd} -o {shellescape(b:zipfile)} {target}")
Bram Moolenaard0796902016-09-16 20:02:31 +0200365 if v:shell_error != 0
Christian Brabandt8d529262024-08-06 18:35:00 +0200366 call s:Mess('Error', "***error*** ".g:zip_extractcmd." ".b:zipfile." ".fname.": failed!")
Bram Moolenaard0796902016-09-16 20:02:31 +0200367 elseif !filereadable(fname)
Christian Brabandt8d529262024-08-06 18:35:00 +0200368 call s:Mess('Error', "***error*** attempted to extract ".fname." but it doesn't appear to be present!")
Bram Moolenaard0796902016-09-16 20:02:31 +0200369 else
Christian Brabandt120c0dd2024-08-05 20:51:47 +0200370 echomsg "***note*** successfully extracted ".fname
Bram Moolenaard0796902016-09-16 20:02:31 +0200371 endif
372
Bram Moolenaard0796902016-09-16 20:02:31 +0200373endfun
374
375" ---------------------------------------------------------------------
Bram Moolenaarc236c162008-07-13 17:41:49 +0000376" s:Escape: {{{2
377fun! s:Escape(fname,isfilt)
Bram Moolenaarc236c162008-07-13 17:41:49 +0000378 if exists("*shellescape")
379 if a:isfilt
380 let qnameq= shellescape(a:fname,1)
381 else
382 let qnameq= shellescape(a:fname)
383 endif
Bram Moolenaar446cb832008-06-24 21:56:24 +0000384 else
385 let qnameq= g:zip_shq.escape(a:fname,g:zip_shq).g:zip_shq
386 endif
Bram Moolenaar446cb832008-06-24 21:56:24 +0000387 return qnameq
Bram Moolenaar9964e462007-05-05 17:54:07 +0000388endfun
389
390" ---------------------------------------------------------------------
Christian Brabandt19636be2024-08-05 21:00:07 +0200391" s:ChgDir: {{{2
Bram Moolenaar9964e462007-05-05 17:54:07 +0000392fun! s:ChgDir(newdir,errlvl,errmsg)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000393 try
Bram Moolenaare37d50a2008-08-06 17:06:04 +0000394 exe "cd ".fnameescape(a:newdir)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000395 catch /^Vim\%((\a\+)\)\=:E344/
396 redraw!
397 if a:errlvl == s:NOTE
Christian Brabandt120c0dd2024-08-05 20:51:47 +0200398 echomsg "***note*** ".a:errmsg
Bram Moolenaar9964e462007-05-05 17:54:07 +0000399 elseif a:errlvl == s:WARNING
Christian Brabandt8d529262024-08-06 18:35:00 +0200400 call s:Mess("WarningMsg", "***warning*** ".a:errmsg)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000401 elseif a:errlvl == s:ERROR
Christian Brabandt8d529262024-08-06 18:35:00 +0200402 call s:Mess("Error", "***error*** ".a:errmsg)
Bram Moolenaar9964e462007-05-05 17:54:07 +0000403 endif
Bram Moolenaar9964e462007-05-05 17:54:07 +0000404 return 1
405 endtry
406
Bram Moolenaar9964e462007-05-05 17:54:07 +0000407 return 0
408endfun
409
Christian Brabandt19636be2024-08-05 21:00:07 +0200410" ---------------------------------------------------------------------
411" s:SetSaneOpts: {{{2
412fun! s:SetSaneOpts()
413 let dict = {}
414 let dict.report = &report
415 let dict.shellslash = &shellslash
416
417 let &report = 10
418 let &shellslash = 0
419
420 return dict
421endfun
422
423" ---------------------------------------------------------------------
424" s:RestoreOpts: {{{2
425fun! s:RestoreOpts(dict)
426 for [key, val] in items(a:dict)
427 exe $"let &{key} = {val}"
428 endfor
429endfun
430
Bram Moolenaar60a795a2005-09-16 21:55:43 +0000431" ------------------------------------------------------------------------
432" Modelines And Restoration: {{{1
433let &cpo= s:keepcpo
434unlet s:keepcpo
Bram Moolenaarccc18222007-05-10 18:25:20 +0000435" vim:ts=8 fdm=marker