blob: a6b4605b0637c87a281c5d42ebfffb9fc3f9ded9 [file] [log] [blame]
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00001" Vim autoload file for editing compressed files.
2" Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaar32efaf62014-11-05 17:02:17 +01003" Last Change: 2014 Nov 05
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00004
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
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000066 " Reset 'foldenable', otherwise line numbers get adjusted.
67 if has("folding")
68 let fen_save = &fen
69 setlocal nofen
70 endif
71
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000072 " 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")
Bram Moolenaarc24dca22008-05-29 20:41:57 +000076 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
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000083 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaarc24dca22008-05-29 20:41:57 +000084 execute "silent '[,']w " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000085 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000086 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000087 if !filereadable(tmp)
88 " uncompress didn't work! Keep the compressed file then.
89 echoerr "Error: Could not read uncompressed file"
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000090 let ok = 0
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000091 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000092 let ok = 1
93 " delete the compressed lines; remember the line number
94 let l = line("'[") - 1
95 if exists(":lockmarks")
96 lockmarks '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +000097 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000098 '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +000099 endif
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000100 " 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
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000105 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000106 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000107 execute "silent lockmarks " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000108 endif
109 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000110 execute "silent " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000111 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)
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000120 silent! exe "bwipe " . tmp_esc
121 silent! exe "bwipe " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000122 endif
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100123 " Store the OK flag, so that we can use it when writing.
124 let b:uncompressOk = ok
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000125
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000126 " Restore saved option values.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000127 let &pm = pm_save
128 let &cpo = cpo_save
129 let &l:ma = ma_save
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000130 if has("folding")
131 let &l:fen = fen_save
132 endif
133
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000134 " When uncompressed the whole buffer, do autocommands
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000135 if ok && empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000136 if exists('*fnameescape')
137 let fname = fnameescape(expand("%:r"))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000138 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000139 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
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000145 endif
146 endif
147endfun
148
149" After writing compressed file: Compress written file with "cmd"
150fun gzip#write(cmd)
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100151 if exists('b:uncompressOk') && !b:uncompressOk
152 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000153 " don't do anything if the cmd is not supported
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100154 elseif s:check(a:cmd)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000155 " 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")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000160 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000161 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000162 call system(a:cmd . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000163 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
Bram Moolenaarc236c162008-07-13 17:41:49 +0000187 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000188 call rename(nmte, nm . &patchmode)
189 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000190 call system(a:cmd . " -- " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000191 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
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000208fun s:escape(name)
209 " shellescape() was added by patch 7.0.111
Bram Moolenaar5c5b0942007-05-06 12:07:59 +0000210 if exists("*shellescape")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000211 return shellescape(a:name)
212 endif
213 return "'" . a:name . "'"
214endfun
215
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000216" vim: set sw=2 :