blob: e4adec0947463bb2c9a490854cfa8d3f8578a017 [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 Moolenaar2ec618c2016-10-01 14:47:05 +02003" Last Change: 2016 Sep 28
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 Moolenaar2ec618c2016-10-01 14:47:05 +020066 " set 'write'
67 let write_save = &write
68 set write
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000069 " Reset 'foldenable', otherwise line numbers get adjusted.
70 if has("folding")
71 let fen_save = &fen
72 setlocal nofen
73 endif
74
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000075 " when filtering the whole buffer, it will become empty
76 let empty = line("'[") == 1 && line("']") == line("$")
77 let tmp = tempname()
78 let tmpe = tmp . "." . expand("<afile>:e")
Bram Moolenaarc24dca22008-05-29 20:41:57 +000079 if exists('*fnameescape')
80 let tmp_esc = fnameescape(tmp)
81 let tmpe_esc = fnameescape(tmpe)
82 else
83 let tmp_esc = escape(tmp, ' ')
84 let tmpe_esc = escape(tmpe, ' ')
85 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000086 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaarc24dca22008-05-29 20:41:57 +000087 execute "silent '[,']w " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000088 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000089 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000090 if !filereadable(tmp)
91 " uncompress didn't work! Keep the compressed file then.
92 echoerr "Error: Could not read uncompressed file"
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000093 let ok = 0
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000094 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000095 let ok = 1
96 " delete the compressed lines; remember the line number
97 let l = line("'[") - 1
98 if exists(":lockmarks")
99 lockmarks '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000100 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000101 '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000102 endif
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000103 " read in the uncompressed lines "'[-1r tmp"
104 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
105 setlocal nobin
106 if exists(":lockmarks")
107 if empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000108 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000109 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000110 execute "silent lockmarks " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000111 endif
112 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000113 execute "silent " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000114 endif
115
116 " if buffer became empty, delete trailing blank line
117 if empty
118 silent $delete _
119 1
120 endif
121 " delete the temp file and the used buffers
122 call delete(tmp)
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000123 silent! exe "bwipe " . tmp_esc
124 silent! exe "bwipe " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000125 endif
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100126 " Store the OK flag, so that we can use it when writing.
127 let b:uncompressOk = ok
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000128
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000129 " Restore saved option values.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000130 let &pm = pm_save
131 let &cpo = cpo_save
132 let &l:ma = ma_save
Bram Moolenaar2ec618c2016-10-01 14:47:05 +0200133 let &write = write_save
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000134 if has("folding")
135 let &l:fen = fen_save
136 endif
137
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000138 " When uncompressed the whole buffer, do autocommands
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000139 if ok && empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000140 if exists('*fnameescape')
141 let fname = fnameescape(expand("%:r"))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000142 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000143 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
144 endif
145 if &verbose >= 8
146 execute "doau BufReadPost " . fname
147 else
148 execute "silent! doau BufReadPost " . fname
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000149 endif
150 endif
151endfun
152
153" After writing compressed file: Compress written file with "cmd"
154fun gzip#write(cmd)
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100155 if exists('b:uncompressOk') && !b:uncompressOk
156 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000157 " don't do anything if the cmd is not supported
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100158 elseif s:check(a:cmd)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000159 " Rename the file before compressing it.
160 let nm = resolve(expand("<afile>"))
161 let nmt = s:tempname(nm)
162 if rename(nm, nmt) == 0
163 if exists("b:gzip_comp_arg")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000164 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000165 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000166 call system(a:cmd . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000167 endif
168 call rename(nmt . "." . expand("<afile>:e"), nm)
169 endif
170 endif
171endfun
172
173" Before appending to compressed file: Uncompress file with "cmd"
174fun gzip#appre(cmd)
175 " don't do anything if the cmd is not supported
176 if s:check(a:cmd)
177 let nm = expand("<afile>")
178
179 " for gzip check current compression level and set b:gzip_comp_arg.
180 silent! unlet b:gzip_comp_arg
181 if a:cmd[0] == 'g'
182 call s:set_compression(readfile(nm, "b", 1)[0])
183 endif
184
185 " Rename to a weird name to avoid the risk of overwriting another file
186 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
187 let nmte = nmt . "." . expand("<afile>:e")
188 if rename(nm, nmte) == 0
189 if &patchmode != "" && getfsize(nm . &patchmode) == -1
190 " Create patchmode file by creating the decompressed file new
Bram Moolenaarc236c162008-07-13 17:41:49 +0000191 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000192 call rename(nmte, nm . &patchmode)
193 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000194 call system(a:cmd . " -- " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000195 endif
196 call rename(nmt, nm)
197 endif
198 endif
199endfun
200
201" find a file name for the file to be compressed. Use "name" without an
202" extension if possible. Otherwise use a weird name to avoid overwriting an
203" existing file.
204fun s:tempname(name)
205 let fn = fnamemodify(a:name, ":r")
206 if !filereadable(fn) && !isdirectory(fn)
207 return fn
208 endif
209 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
210endfun
211
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000212fun s:escape(name)
213 " shellescape() was added by patch 7.0.111
Bram Moolenaar5c5b0942007-05-06 12:07:59 +0000214 if exists("*shellescape")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000215 return shellescape(a:name)
216 endif
217 return "'" . a:name . "'"
218endfun
219
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000220" vim: set sw=2 :