1" Vim autoload file for editing compressed files. 2" Maintainer: Bram Moolenaar <[email protected]> 3" Last Change: 2014 Nov 05 4 5" These functions are used by the gzip plugin. 6 7" Function to check that executing "cmd [-f]" works. 8" The result is cached in s:have_"cmd" for speed. 9fun s:check(cmd) 10 let name = substitute(a:cmd, '\(\S*\).*', '\1', '') 11 if !exists("s:have_" . name) 12 let e = executable(name) 13 if e < 0 14 let r = system(name . " --version") 15 let e = (r !~ "not found" && r != "") 16 endif 17 exe "let s:have_" . name . "=" . e 18 endif 19 exe "return s:have_" . name 20endfun 21 22" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on 23" the flags in the compressed file. 24" The only compression methods that can be detected are max speed (-1) and max 25" compression (-9). 26fun s:set_compression(line) 27 " get the Compression Method 28 let l:cm = char2nr(a:line[2]) 29 " if it's 8 (DEFLATE), we can check for the compression level 30 if l:cm == 8 31 " get the eXtra FLags 32 let l:xfl = char2nr(a:line[8]) 33 " max compression 34 if l:xfl == 2 35 let b:gzip_comp_arg = "-9" 36 " min compression 37 elseif l:xfl == 4 38 let b:gzip_comp_arg = "-1" 39 endif 40 endif 41endfun 42 43 44" After reading compressed file: Uncompress text in buffer with "cmd" 45fun gzip#read(cmd) 46 " don't do anything if the cmd is not supported 47 if !s:check(a:cmd) 48 return 49 endif 50 51 " for gzip check current compression level and set b:gzip_comp_arg. 52 silent! unlet b:gzip_comp_arg 53 if a:cmd[0] == 'g' 54 call s:set_compression(getline(1)) 55 endif 56 57 " make 'patchmode' empty, we don't want a copy of the written file 58 let pm_save = &pm 59 set pm= 60 " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes 61 let cpo_save = &cpo 62 set cpo-=a cpo-=A 63 " set 'modifiable' 64 let ma_save = &ma 65 setlocal ma 66 " Reset 'foldenable', otherwise line numbers get adjusted. 67 if has("folding") 68 let fen_save = &fen 69 setlocal nofen 70 endif 71 72 " when filtering the whole buffer, it will become empty 73 let empty = line("'[") == 1 && line("']") == line("$") 74 let tmp = tempname() 75 let tmpe = tmp . "." . expand("<afile>:e") 76 if exists('*fnameescape') 77 let tmp_esc = fnameescape(tmp) 78 let tmpe_esc = fnameescape(tmpe) 79 else 80 let tmp_esc = escape(tmp, ' ') 81 let tmpe_esc = escape(tmpe, ' ') 82 endif 83 " write the just read lines to a temp file "'[,']w tmp.gz" 84 execute "silent '[,']w " . tmpe_esc 85 " uncompress the temp file: call system("gzip -dn tmp.gz") 86 call system(a:cmd . " " . s:escape(tmpe)) 87 if !filereadable(tmp) 88 " uncompress didn't work! Keep the compressed file then. 89 echoerr "Error: Could not read uncompressed file" 90 let ok = 0 91 else 92 let ok = 1 93 " delete the compressed lines; remember the line number 94 let l = line("'[") - 1 95 if exists(":lockmarks") 96 lockmarks '[,']d _ 97 else 98 '[,']d _ 99 endif 100 " read in the uncompressed lines "'[-1r tmp" 101 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options. 102 setlocal nobin 103 if exists(":lockmarks") 104 if empty 105 execute "silent lockmarks " . l . "r ++edit " . tmp_esc 106 else 107 execute "silent lockmarks " . l . "r " . tmp_esc 108 endif 109 else 110 execute "silent " . l . "r " . tmp_esc 111 endif 112 113 " if buffer became empty, delete trailing blank line 114 if empty 115 silent $delete _ 116 1 117 endif 118 " delete the temp file and the used buffers 119 call delete(tmp) 120 silent! exe "bwipe " . tmp_esc 121 silent! exe "bwipe " . tmpe_esc 122 endif 123 " Store the OK flag, so that we can use it when writing. 124 let b:uncompressOk = ok 125 126 " Restore saved option values. 127 let &pm = pm_save 128 let &cpo = cpo_save 129 let &l:ma = ma_save 130 if has("folding") 131 let &l:fen = fen_save 132 endif 133 134 " When uncompressed the whole buffer, do autocommands 135 if ok && empty 136 if exists('*fnameescape') 137 let fname = fnameescape(expand("%:r")) 138 else 139 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<") 140 endif 141 if &verbose >= 8 142 execute "doau BufReadPost " . fname 143 else 144 execute "silent! doau BufReadPost " . fname 145 endif 146 endif 147endfun 148 149" After writing compressed file: Compress written file with "cmd" 150fun gzip#write(cmd) 151 if exists('b:uncompressOk') && !b:uncompressOk 152 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway" 153 " don't do anything if the cmd is not supported 154 elseif s:check(a:cmd) 155 " Rename the file before compressing it. 156 let nm = resolve(expand("<afile>")) 157 let nmt = s:tempname(nm) 158 if rename(nm, nmt) == 0 159 if exists("b:gzip_comp_arg") 160 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt)) 161 else 162 call system(a:cmd . " -- " . s:escape(nmt)) 163 endif 164 call rename(nmt . "." . expand("<afile>:e"), nm) 165 endif 166 endif 167endfun 168 169" Before appending to compressed file: Uncompress file with "cmd" 170fun gzip#appre(cmd) 171 " don't do anything if the cmd is not supported 172 if s:check(a:cmd) 173 let nm = expand("<afile>") 174 175 " for gzip check current compression level and set b:gzip_comp_arg. 176 silent! unlet b:gzip_comp_arg 177 if a:cmd[0] == 'g' 178 call s:set_compression(readfile(nm, "b", 1)[0]) 179 endif 180 181 " Rename to a weird name to avoid the risk of overwriting another file 182 let nmt = expand("<afile>:p:h") . "/X~=@l9q5" 183 let nmte = nmt . "." . expand("<afile>:e") 184 if rename(nm, nmte) == 0 185 if &patchmode != "" && getfsize(nm . &patchmode) == -1 186 " Create patchmode file by creating the decompressed file new 187 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt)) 188 call rename(nmte, nm . &patchmode) 189 else 190 call system(a:cmd . " -- " . s:escape(nmte)) 191 endif 192 call rename(nmt, nm) 193 endif 194 endif 195endfun 196 197" find a file name for the file to be compressed. Use "name" without an 198" extension if possible. Otherwise use a weird name to avoid overwriting an 199" existing file. 200fun s:tempname(name) 201 let fn = fnamemodify(a:name, ":r") 202 if !filereadable(fn) && !isdirectory(fn) 203 return fn 204 endif 205 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5" 206endfun 207 208fun s:escape(name) 209 " shellescape() was added by patch 7.0.111 210 if exists("*shellescape") 211 return shellescape(a:name) 212 endif 213 return "'" . a:name . "'" 214endfun 215 216" vim: set sw=2 : 217