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