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