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