blob: ac9e37bf85e7ed49d3f51d2d318de31ba92e4f09 [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)
Christian Brabandt816fbcc2023-08-31 23:52:30 +020013 " safety check, don't execute anything from the current directory
14 let f = fnamemodify(exepath(name), ":p:h") !=# getcwd()
15 if !f
16 echoerr "Warning: NOT executing " .. name .. " from current directory!"
17 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000018 let e = executable(name)
19 if e < 0
20 let r = system(name . " --version")
21 let e = (r !~ "not found" && r != "")
22 endif
Christian Brabandt816fbcc2023-08-31 23:52:30 +020023 exe "let s:have_" . name . "=" . (e && f)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000024 endif
25 exe "return s:have_" . name
26endfun
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).
32fun 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
47endfun
48
49
50" After reading compressed file: Uncompress text in buffer with "cmd"
51fun 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
Bram Moolenaar2ec618c2016-10-01 14:47:05 +020072 " set 'write'
73 let write_save = &write
74 set write
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000075 " Reset 'foldenable', otherwise line numbers get adjusted.
76 if has("folding")
77 let fen_save = &fen
78 setlocal nofen
79 endif
80
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000081 " 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")
Bram Moolenaarc24dca22008-05-29 20:41:57 +000085 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
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000092 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaarc24dca22008-05-29 20:41:57 +000093 execute "silent '[,']w " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000094 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000095 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000096 if !filereadable(tmp)
97 " uncompress didn't work! Keep the compressed file then.
98 echoerr "Error: Could not read uncompressed file"
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000099 let ok = 0
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000100 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000101 let ok = 1
102 " delete the compressed lines; remember the line number
103 let l = line("'[") - 1
104 if exists(":lockmarks")
105 lockmarks '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000106 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000107 '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000108 endif
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000109 " 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
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000114 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000115 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000116 execute "silent lockmarks " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000117 endif
118 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000119 execute "silent " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000120 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)
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000129 silent! exe "bwipe " . tmp_esc
130 silent! exe "bwipe " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000131 endif
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100132 " Store the OK flag, so that we can use it when writing.
133 let b:uncompressOk = ok
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000134
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000135 " Restore saved option values.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000136 let &pm = pm_save
137 let &cpo = cpo_save
138 let &l:ma = ma_save
Bram Moolenaar2ec618c2016-10-01 14:47:05 +0200139 let &write = write_save
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000140 if has("folding")
141 let &l:fen = fen_save
142 endif
143
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000144 " When uncompressed the whole buffer, do autocommands
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000145 if ok && empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000146 if exists('*fnameescape')
147 let fname = fnameescape(expand("%:r"))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000148 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000149 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
150 endif
151 if &verbose >= 8
152 execute "doau BufReadPost " . fname
153 else
154 execute "silent! doau BufReadPost " . fname
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000155 endif
156 endif
157endfun
158
159" After writing compressed file: Compress written file with "cmd"
160fun gzip#write(cmd)
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100161 if exists('b:uncompressOk') && !b:uncompressOk
162 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000163 " don't do anything if the cmd is not supported
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100164 elseif s:check(a:cmd)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000165 " Rename the file before compressing it.
166 let nm = resolve(expand("<afile>"))
167 let nmt = s:tempname(nm)
168 if rename(nm, nmt) == 0
169 if exists("b:gzip_comp_arg")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000170 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000171 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000172 call system(a:cmd . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000173 endif
174 call rename(nmt . "." . expand("<afile>:e"), nm)
175 endif
176 endif
177endfun
178
179" Before appending to compressed file: Uncompress file with "cmd"
180fun gzip#appre(cmd)
181 " don't do anything if the cmd is not supported
182 if s:check(a:cmd)
183 let nm = expand("<afile>")
184
185 " for gzip check current compression level and set b:gzip_comp_arg.
186 silent! unlet b:gzip_comp_arg
187 if a:cmd[0] == 'g'
188 call s:set_compression(readfile(nm, "b", 1)[0])
189 endif
190
191 " Rename to a weird name to avoid the risk of overwriting another file
192 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
193 let nmte = nmt . "." . expand("<afile>:e")
194 if rename(nm, nmte) == 0
195 if &patchmode != "" && getfsize(nm . &patchmode) == -1
196 " Create patchmode file by creating the decompressed file new
Bram Moolenaarc236c162008-07-13 17:41:49 +0000197 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000198 call rename(nmte, nm . &patchmode)
199 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000200 call system(a:cmd . " -- " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000201 endif
202 call rename(nmt, nm)
203 endif
204 endif
205endfun
206
207" find a file name for the file to be compressed. Use "name" without an
208" extension if possible. Otherwise use a weird name to avoid overwriting an
209" existing file.
210fun s:tempname(name)
211 let fn = fnamemodify(a:name, ":r")
212 if !filereadable(fn) && !isdirectory(fn)
213 return fn
214 endif
215 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
216endfun
217
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000218fun s:escape(name)
219 " shellescape() was added by patch 7.0.111
Bram Moolenaar5c5b0942007-05-06 12:07:59 +0000220 if exists("*shellescape")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000221 return shellescape(a:name)
222 endif
223 return "'" . a:name . "'"
224endfun
225
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000226" vim: set sw=2 :