187e25fdfSBram Moolenaar" Vim autoload file for editing compressed files. 287e25fdfSBram Moolenaar" Maintainer: Bram Moolenaar <[email protected]> 3*2ec618c9SBram Moolenaar" Last Change: 2016 Sep 28 487e25fdfSBram Moolenaar 587e25fdfSBram Moolenaar" These functions are used by the gzip plugin. 687e25fdfSBram Moolenaar 787e25fdfSBram Moolenaar" Function to check that executing "cmd [-f]" works. 887e25fdfSBram Moolenaar" The result is cached in s:have_"cmd" for speed. 987e25fdfSBram Moolenaarfun s:check(cmd) 1087e25fdfSBram Moolenaar let name = substitute(a:cmd, '\(\S*\).*', '\1', '') 1187e25fdfSBram Moolenaar if !exists("s:have_" . name) 1287e25fdfSBram Moolenaar let e = executable(name) 1387e25fdfSBram Moolenaar if e < 0 1487e25fdfSBram Moolenaar let r = system(name . " --version") 1587e25fdfSBram Moolenaar let e = (r !~ "not found" && r != "") 1687e25fdfSBram Moolenaar endif 1787e25fdfSBram Moolenaar exe "let s:have_" . name . "=" . e 1887e25fdfSBram Moolenaar endif 1987e25fdfSBram Moolenaar exe "return s:have_" . name 2087e25fdfSBram Moolenaarendfun 2187e25fdfSBram Moolenaar 2287e25fdfSBram Moolenaar" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on 2387e25fdfSBram Moolenaar" the flags in the compressed file. 2487e25fdfSBram Moolenaar" The only compression methods that can be detected are max speed (-1) and max 2587e25fdfSBram Moolenaar" compression (-9). 2687e25fdfSBram Moolenaarfun s:set_compression(line) 2787e25fdfSBram Moolenaar " get the Compression Method 2887e25fdfSBram Moolenaar let l:cm = char2nr(a:line[2]) 2987e25fdfSBram Moolenaar " if it's 8 (DEFLATE), we can check for the compression level 3087e25fdfSBram Moolenaar if l:cm == 8 3187e25fdfSBram Moolenaar " get the eXtra FLags 3287e25fdfSBram Moolenaar let l:xfl = char2nr(a:line[8]) 3387e25fdfSBram Moolenaar " max compression 3487e25fdfSBram Moolenaar if l:xfl == 2 3587e25fdfSBram Moolenaar let b:gzip_comp_arg = "-9" 3687e25fdfSBram Moolenaar " min compression 3787e25fdfSBram Moolenaar elseif l:xfl == 4 3887e25fdfSBram Moolenaar let b:gzip_comp_arg = "-1" 3987e25fdfSBram Moolenaar endif 4087e25fdfSBram Moolenaar endif 4187e25fdfSBram Moolenaarendfun 4287e25fdfSBram Moolenaar 4387e25fdfSBram Moolenaar 4487e25fdfSBram Moolenaar" After reading compressed file: Uncompress text in buffer with "cmd" 4587e25fdfSBram Moolenaarfun gzip#read(cmd) 4687e25fdfSBram Moolenaar " don't do anything if the cmd is not supported 4787e25fdfSBram Moolenaar if !s:check(a:cmd) 4887e25fdfSBram Moolenaar return 4987e25fdfSBram Moolenaar endif 5087e25fdfSBram Moolenaar 5187e25fdfSBram Moolenaar " for gzip check current compression level and set b:gzip_comp_arg. 5287e25fdfSBram Moolenaar silent! unlet b:gzip_comp_arg 5387e25fdfSBram Moolenaar if a:cmd[0] == 'g' 5487e25fdfSBram Moolenaar call s:set_compression(getline(1)) 5587e25fdfSBram Moolenaar endif 5687e25fdfSBram Moolenaar 5787e25fdfSBram Moolenaar " make 'patchmode' empty, we don't want a copy of the written file 5887e25fdfSBram Moolenaar let pm_save = &pm 5987e25fdfSBram Moolenaar set pm= 6087e25fdfSBram Moolenaar " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes 6187e25fdfSBram Moolenaar let cpo_save = &cpo 6287e25fdfSBram Moolenaar set cpo-=a cpo-=A 6387e25fdfSBram Moolenaar " set 'modifiable' 6487e25fdfSBram Moolenaar let ma_save = &ma 6587e25fdfSBram Moolenaar setlocal ma 66*2ec618c9SBram Moolenaar " set 'write' 67*2ec618c9SBram Moolenaar let write_save = &write 68*2ec618c9SBram Moolenaar set write 69c1762ccbSBram Moolenaar " Reset 'foldenable', otherwise line numbers get adjusted. 70c1762ccbSBram Moolenaar if has("folding") 71c1762ccbSBram Moolenaar let fen_save = &fen 72c1762ccbSBram Moolenaar setlocal nofen 73c1762ccbSBram Moolenaar endif 74c1762ccbSBram Moolenaar 7587e25fdfSBram Moolenaar " when filtering the whole buffer, it will become empty 7687e25fdfSBram Moolenaar let empty = line("'[") == 1 && line("']") == line("$") 7787e25fdfSBram Moolenaar let tmp = tempname() 7887e25fdfSBram Moolenaar let tmpe = tmp . "." . expand("<afile>:e") 79c24dca26SBram Moolenaar if exists('*fnameescape') 80c24dca26SBram Moolenaar let tmp_esc = fnameescape(tmp) 81c24dca26SBram Moolenaar let tmpe_esc = fnameescape(tmpe) 82c24dca26SBram Moolenaar else 83c24dca26SBram Moolenaar let tmp_esc = escape(tmp, ' ') 84c24dca26SBram Moolenaar let tmpe_esc = escape(tmpe, ' ') 85c24dca26SBram Moolenaar endif 8687e25fdfSBram Moolenaar " write the just read lines to a temp file "'[,']w tmp.gz" 87c24dca26SBram Moolenaar execute "silent '[,']w " . tmpe_esc 8887e25fdfSBram Moolenaar " uncompress the temp file: call system("gzip -dn tmp.gz") 8960a495f0SBram Moolenaar call system(a:cmd . " " . s:escape(tmpe)) 9087e25fdfSBram Moolenaar if !filereadable(tmp) 9187e25fdfSBram Moolenaar " uncompress didn't work! Keep the compressed file then. 9287e25fdfSBram Moolenaar echoerr "Error: Could not read uncompressed file" 93c1762ccbSBram Moolenaar let ok = 0 94c1762ccbSBram Moolenaar else 95c1762ccbSBram Moolenaar let ok = 1 9687e25fdfSBram Moolenaar " delete the compressed lines; remember the line number 9787e25fdfSBram Moolenaar let l = line("'[") - 1 9887e25fdfSBram Moolenaar if exists(":lockmarks") 9987e25fdfSBram Moolenaar lockmarks '[,']d _ 10087e25fdfSBram Moolenaar else 10187e25fdfSBram Moolenaar '[,']d _ 10287e25fdfSBram Moolenaar endif 10387e25fdfSBram Moolenaar " read in the uncompressed lines "'[-1r tmp" 104910f66f9SBram Moolenaar " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options. 10587e25fdfSBram Moolenaar setlocal nobin 10687e25fdfSBram Moolenaar if exists(":lockmarks") 107910f66f9SBram Moolenaar if empty 108c24dca26SBram Moolenaar execute "silent lockmarks " . l . "r ++edit " . tmp_esc 109910f66f9SBram Moolenaar else 110c24dca26SBram Moolenaar execute "silent lockmarks " . l . "r " . tmp_esc 111910f66f9SBram Moolenaar endif 11287e25fdfSBram Moolenaar else 113c24dca26SBram Moolenaar execute "silent " . l . "r " . tmp_esc 11487e25fdfSBram Moolenaar endif 11587e25fdfSBram Moolenaar 11687e25fdfSBram Moolenaar " if buffer became empty, delete trailing blank line 11787e25fdfSBram Moolenaar if empty 11887e25fdfSBram Moolenaar silent $delete _ 11987e25fdfSBram Moolenaar 1 12087e25fdfSBram Moolenaar endif 12187e25fdfSBram Moolenaar " delete the temp file and the used buffers 12287e25fdfSBram Moolenaar call delete(tmp) 123c24dca26SBram Moolenaar silent! exe "bwipe " . tmp_esc 124c24dca26SBram Moolenaar silent! exe "bwipe " . tmpe_esc 125c1762ccbSBram Moolenaar endif 12632efaf61SBram Moolenaar " Store the OK flag, so that we can use it when writing. 12732efaf61SBram Moolenaar let b:uncompressOk = ok 128c1762ccbSBram Moolenaar 129c1762ccbSBram Moolenaar " Restore saved option values. 13087e25fdfSBram Moolenaar let &pm = pm_save 13187e25fdfSBram Moolenaar let &cpo = cpo_save 13287e25fdfSBram Moolenaar let &l:ma = ma_save 133*2ec618c9SBram Moolenaar let &write = write_save 134c1762ccbSBram Moolenaar if has("folding") 135c1762ccbSBram Moolenaar let &l:fen = fen_save 136c1762ccbSBram Moolenaar endif 137c1762ccbSBram Moolenaar 13887e25fdfSBram Moolenaar " When uncompressed the whole buffer, do autocommands 139c1762ccbSBram Moolenaar if ok && empty 140c24dca26SBram Moolenaar if exists('*fnameescape') 141c24dca26SBram Moolenaar let fname = fnameescape(expand("%:r")) 14287e25fdfSBram Moolenaar else 143c24dca26SBram Moolenaar let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<") 144c24dca26SBram Moolenaar endif 145c24dca26SBram Moolenaar if &verbose >= 8 146c24dca26SBram Moolenaar execute "doau BufReadPost " . fname 147c24dca26SBram Moolenaar else 148c24dca26SBram Moolenaar execute "silent! doau BufReadPost " . fname 14987e25fdfSBram Moolenaar endif 15087e25fdfSBram Moolenaar endif 15187e25fdfSBram Moolenaarendfun 15287e25fdfSBram Moolenaar 15387e25fdfSBram Moolenaar" After writing compressed file: Compress written file with "cmd" 15487e25fdfSBram Moolenaarfun gzip#write(cmd) 15532efaf61SBram Moolenaar if exists('b:uncompressOk') && !b:uncompressOk 15632efaf61SBram Moolenaar echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway" 15787e25fdfSBram Moolenaar " don't do anything if the cmd is not supported 15832efaf61SBram Moolenaar elseif s:check(a:cmd) 15987e25fdfSBram Moolenaar " Rename the file before compressing it. 16087e25fdfSBram Moolenaar let nm = resolve(expand("<afile>")) 16187e25fdfSBram Moolenaar let nmt = s:tempname(nm) 16287e25fdfSBram Moolenaar if rename(nm, nmt) == 0 16387e25fdfSBram Moolenaar if exists("b:gzip_comp_arg") 164c236c16dSBram Moolenaar call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt)) 16587e25fdfSBram Moolenaar else 166c236c16dSBram Moolenaar call system(a:cmd . " -- " . s:escape(nmt)) 16787e25fdfSBram Moolenaar endif 16887e25fdfSBram Moolenaar call rename(nmt . "." . expand("<afile>:e"), nm) 16987e25fdfSBram Moolenaar endif 17087e25fdfSBram Moolenaar endif 17187e25fdfSBram Moolenaarendfun 17287e25fdfSBram Moolenaar 17387e25fdfSBram Moolenaar" Before appending to compressed file: Uncompress file with "cmd" 17487e25fdfSBram Moolenaarfun gzip#appre(cmd) 17587e25fdfSBram Moolenaar " don't do anything if the cmd is not supported 17687e25fdfSBram Moolenaar if s:check(a:cmd) 17787e25fdfSBram Moolenaar let nm = expand("<afile>") 17887e25fdfSBram Moolenaar 17987e25fdfSBram Moolenaar " for gzip check current compression level and set b:gzip_comp_arg. 18087e25fdfSBram Moolenaar silent! unlet b:gzip_comp_arg 18187e25fdfSBram Moolenaar if a:cmd[0] == 'g' 18287e25fdfSBram Moolenaar call s:set_compression(readfile(nm, "b", 1)[0]) 18387e25fdfSBram Moolenaar endif 18487e25fdfSBram Moolenaar 18587e25fdfSBram Moolenaar " Rename to a weird name to avoid the risk of overwriting another file 18687e25fdfSBram Moolenaar let nmt = expand("<afile>:p:h") . "/X~=@l9q5" 18787e25fdfSBram Moolenaar let nmte = nmt . "." . expand("<afile>:e") 18887e25fdfSBram Moolenaar if rename(nm, nmte) == 0 18987e25fdfSBram Moolenaar if &patchmode != "" && getfsize(nm . &patchmode) == -1 19087e25fdfSBram Moolenaar " Create patchmode file by creating the decompressed file new 191c236c16dSBram Moolenaar call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt)) 19287e25fdfSBram Moolenaar call rename(nmte, nm . &patchmode) 19387e25fdfSBram Moolenaar else 194c236c16dSBram Moolenaar call system(a:cmd . " -- " . s:escape(nmte)) 19587e25fdfSBram Moolenaar endif 19687e25fdfSBram Moolenaar call rename(nmt, nm) 19787e25fdfSBram Moolenaar endif 19887e25fdfSBram Moolenaar endif 19987e25fdfSBram Moolenaarendfun 20087e25fdfSBram Moolenaar 20187e25fdfSBram Moolenaar" find a file name for the file to be compressed. Use "name" without an 20287e25fdfSBram Moolenaar" extension if possible. Otherwise use a weird name to avoid overwriting an 20387e25fdfSBram Moolenaar" existing file. 20487e25fdfSBram Moolenaarfun s:tempname(name) 20587e25fdfSBram Moolenaar let fn = fnamemodify(a:name, ":r") 20687e25fdfSBram Moolenaar if !filereadable(fn) && !isdirectory(fn) 20787e25fdfSBram Moolenaar return fn 20887e25fdfSBram Moolenaar endif 20987e25fdfSBram Moolenaar return fnamemodify(a:name, ":p:h") . "/X~=@l9q5" 21087e25fdfSBram Moolenaarendfun 21187e25fdfSBram Moolenaar 21260a495f0SBram Moolenaarfun s:escape(name) 21360a495f0SBram Moolenaar " shellescape() was added by patch 7.0.111 2145c5b0941SBram Moolenaar if exists("*shellescape") 21560a495f0SBram Moolenaar return shellescape(a:name) 21660a495f0SBram Moolenaar endif 21760a495f0SBram Moolenaar return "'" . a:name . "'" 21860a495f0SBram Moolenaarendfun 21960a495f0SBram Moolenaar 22087e25fdfSBram Moolenaar" vim: set sw=2 : 221