1" Vim autoload file for editing compressed files. 2" Maintainer: Bram Moolenaar <Bram@vim.org> 3" Last Change: 2008 Jul 04 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 124 " Restore saved option values. 125 let &pm = pm_save 126 let &cpo = cpo_save 127 let &l:ma = ma_save 128 if has("folding") 129 let &l:fen = fen_save 130 endif 131 132 " When uncompressed the whole buffer, do autocommands 133 if ok && empty 134 if exists('*fnameescape') 135 let fname = fnameescape(expand("%:r")) 136 else 137 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<") 138 endif 139 if &verbose >= 8 140 execute "doau BufReadPost " . fname 141 else 142 execute "silent! doau BufReadPost " . fname 143 endif 144 endif 145endfun 146 147" After writing compressed file: Compress written file with "cmd" 148fun gzip#write(cmd) 149 " don't do anything if the cmd is not supported 150 if s:check(a:cmd) 151 " Rename the file before compressing it. 152 let nm = resolve(expand("<afile>")) 153 let nmt = s:tempname(nm) 154 if rename(nm, nmt) == 0 155 if exists("b:gzip_comp_arg") 156 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt)) 157 else 158 call system(a:cmd . " -- " . s:escape(nmt)) 159 endif 160 call rename(nmt . "." . expand("<afile>:e"), nm) 161 endif 162 endif 163endfun 164 165" Before appending to compressed file: Uncompress file with "cmd" 166fun gzip#appre(cmd) 167 " don't do anything if the cmd is not supported 168 if s:check(a:cmd) 169 let nm = expand("<afile>") 170 171 " for gzip check current compression level and set b:gzip_comp_arg. 172 silent! unlet b:gzip_comp_arg 173 if a:cmd[0] == 'g' 174 call s:set_compression(readfile(nm, "b", 1)[0]) 175 endif 176 177 " Rename to a weird name to avoid the risk of overwriting another file 178 let nmt = expand("<afile>:p:h") . "/X~=@l9q5" 179 let nmte = nmt . "." . expand("<afile>:e") 180 if rename(nm, nmte) == 0 181 if &patchmode != "" && getfsize(nm . &patchmode) == -1 182 " Create patchmode file by creating the decompressed file new 183 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt)) 184 call rename(nmte, nm . &patchmode) 185 else 186 call system(a:cmd . " -- " . s:escape(nmte)) 187 endif 188 call rename(nmt, nm) 189 endif 190 endif 191endfun 192 193" find a file name for the file to be compressed. Use "name" without an 194" extension if possible. Otherwise use a weird name to avoid overwriting an 195" existing file. 196fun s:tempname(name) 197 let fn = fnamemodify(a:name, ":r") 198 if !filereadable(fn) && !isdirectory(fn) 199 return fn 200 endif 201 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5" 202endfun 203 204fun s:escape(name) 205 " shellescape() was added by patch 7.0.111 206 if exists("*shellescape") 207 return shellescape(a:name) 208 endif 209 return "'" . a:name . "'" 210endfun 211 212" vim: set sw=2 : 213