blob: 95dd9067945afc2b1008883aae3fff37954b7b2f [file] [log] [blame]
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00001" Vim autoload file for editing compressed files.
Christian Brabandte978b452023-08-13 10:33:05 +02002" Maintainer: The Vim Project <https://github.com/vim/vim>
3" Last Change: 2023 Aug 10
4" Former Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00005
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.
10fun s:check(cmd)
11 let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
12 if !exists("s:have_" . name)
13 let e = executable(name)
14 if e < 0
15 let r = system(name . " --version")
16 let e = (r !~ "not found" && r != "")
17 endif
18 exe "let s:have_" . name . "=" . e
19 endif
20 exe "return s:have_" . name
21endfun
22
23" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on
24" the flags in the compressed file.
25" The only compression methods that can be detected are max speed (-1) and max
26" compression (-9).
27fun s:set_compression(line)
28 " get the Compression Method
29 let l:cm = char2nr(a:line[2])
30 " if it's 8 (DEFLATE), we can check for the compression level
31 if l:cm == 8
32 " get the eXtra FLags
33 let l:xfl = char2nr(a:line[8])
34 " max compression
35 if l:xfl == 2
36 let b:gzip_comp_arg = "-9"
37 " min compression
38 elseif l:xfl == 4
39 let b:gzip_comp_arg = "-1"
40 endif
41 endif
42endfun
43
44
45" After reading compressed file: Uncompress text in buffer with "cmd"
46fun gzip#read(cmd)
47 " don't do anything if the cmd is not supported
48 if !s:check(a:cmd)
49 return
50 endif
51
52 " for gzip check current compression level and set b:gzip_comp_arg.
53 silent! unlet b:gzip_comp_arg
54 if a:cmd[0] == 'g'
55 call s:set_compression(getline(1))
56 endif
57
58 " make 'patchmode' empty, we don't want a copy of the written file
59 let pm_save = &pm
60 set pm=
61 " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes
62 let cpo_save = &cpo
63 set cpo-=a cpo-=A
64 " set 'modifiable'
65 let ma_save = &ma
66 setlocal ma
Bram Moolenaar2ec618c2016-10-01 14:47:05 +020067 " set 'write'
68 let write_save = &write
69 set write
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000070 " Reset 'foldenable', otherwise line numbers get adjusted.
71 if has("folding")
72 let fen_save = &fen
73 setlocal nofen
74 endif
75
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000076 " when filtering the whole buffer, it will become empty
77 let empty = line("'[") == 1 && line("']") == line("$")
78 let tmp = tempname()
79 let tmpe = tmp . "." . expand("<afile>:e")
Bram Moolenaarc24dca22008-05-29 20:41:57 +000080 if exists('*fnameescape')
81 let tmp_esc = fnameescape(tmp)
82 let tmpe_esc = fnameescape(tmpe)
83 else
84 let tmp_esc = escape(tmp, ' ')
85 let tmpe_esc = escape(tmpe, ' ')
86 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000087 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaarc24dca22008-05-29 20:41:57 +000088 execute "silent '[,']w " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000089 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000090 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000091 if !filereadable(tmp)
92 " uncompress didn't work! Keep the compressed file then.
93 echoerr "Error: Could not read uncompressed file"
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000094 let ok = 0
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000095 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000096 let ok = 1
97 " delete the compressed lines; remember the line number
98 let l = line("'[") - 1
99 if exists(":lockmarks")
100 lockmarks '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000101 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000102 '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000103 endif
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000104 " read in the uncompressed lines "'[-1r tmp"
105 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
106 setlocal nobin
107 if exists(":lockmarks")
108 if empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000109 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000110 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000111 execute "silent lockmarks " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000112 endif
113 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000114 execute "silent " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000115 endif
116
117 " if buffer became empty, delete trailing blank line
118 if empty
119 silent $delete _
120 1
121 endif
122 " delete the temp file and the used buffers
123 call delete(tmp)
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000124 silent! exe "bwipe " . tmp_esc
125 silent! exe "bwipe " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000126 endif
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100127 " Store the OK flag, so that we can use it when writing.
128 let b:uncompressOk = ok
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000129
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000130 " Restore saved option values.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000131 let &pm = pm_save
132 let &cpo = cpo_save
133 let &l:ma = ma_save
Bram Moolenaar2ec618c2016-10-01 14:47:05 +0200134 let &write = write_save
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000135 if has("folding")
136 let &l:fen = fen_save
137 endif
138
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000139 " When uncompressed the whole buffer, do autocommands
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000140 if ok && empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000141 if exists('*fnameescape')
142 let fname = fnameescape(expand("%:r"))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000143 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000144 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
145 endif
146 if &verbose >= 8
147 execute "doau BufReadPost " . fname
148 else
149 execute "silent! doau BufReadPost " . fname
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000150 endif
151 endif
152endfun
153
154" After writing compressed file: Compress written file with "cmd"
155fun gzip#write(cmd)
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100156 if exists('b:uncompressOk') && !b:uncompressOk
157 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000158 " don't do anything if the cmd is not supported
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100159 elseif s:check(a:cmd)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000160 " Rename the file before compressing it.
161 let nm = resolve(expand("<afile>"))
162 let nmt = s:tempname(nm)
163 if rename(nm, nmt) == 0
164 if exists("b:gzip_comp_arg")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000165 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000166 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000167 call system(a:cmd . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000168 endif
169 call rename(nmt . "." . expand("<afile>:e"), nm)
170 endif
171 endif
172endfun
173
174" Before appending to compressed file: Uncompress file with "cmd"
175fun gzip#appre(cmd)
176 " don't do anything if the cmd is not supported
177 if s:check(a:cmd)
178 let nm = expand("<afile>")
179
180 " for gzip check current compression level and set b:gzip_comp_arg.
181 silent! unlet b:gzip_comp_arg
182 if a:cmd[0] == 'g'
183 call s:set_compression(readfile(nm, "b", 1)[0])
184 endif
185
186 " Rename to a weird name to avoid the risk of overwriting another file
187 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
188 let nmte = nmt . "." . expand("<afile>:e")
189 if rename(nm, nmte) == 0
190 if &patchmode != "" && getfsize(nm . &patchmode) == -1
191 " Create patchmode file by creating the decompressed file new
Bram Moolenaarc236c162008-07-13 17:41:49 +0000192 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000193 call rename(nmte, nm . &patchmode)
194 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000195 call system(a:cmd . " -- " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000196 endif
197 call rename(nmt, nm)
198 endif
199 endif
200endfun
201
202" find a file name for the file to be compressed. Use "name" without an
203" extension if possible. Otherwise use a weird name to avoid overwriting an
204" existing file.
205fun s:tempname(name)
206 let fn = fnamemodify(a:name, ":r")
207 if !filereadable(fn) && !isdirectory(fn)
208 return fn
209 endif
210 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
211endfun
212
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000213fun s:escape(name)
214 " shellescape() was added by patch 7.0.111
Bram Moolenaar5c5b0942007-05-06 12:07:59 +0000215 if exists("*shellescape")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000216 return shellescape(a:name)
217 endif
218 return "'" . a:name . "'"
219endfun
220
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000221" vim: set sw=2 :