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