blob: 6d0bb13401a8a3543b9fa48fc98827fd1cdd3c16 [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
Anton Sharonov67c951d2023-09-05 21:03:27 +020014 let s:tmp_cwd = getcwd()
15 let f = (fnamemodify(exepath(name), ":p:h") !=# s:tmp_cwd
16 \ || (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) != -1 && s:tmp_cwd != '.'))
17 unlet s:tmp_cwd
Christian Brabandt816fbcc2023-08-31 23:52:30 +020018 if !f
19 echoerr "Warning: NOT executing " .. name .. " from current directory!"
20 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000021 let e = executable(name)
22 if e < 0
23 let r = system(name . " --version")
24 let e = (r !~ "not found" && r != "")
25 endif
Christian Brabandt816fbcc2023-08-31 23:52:30 +020026 exe "let s:have_" . name . "=" . (e && f)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000027 endif
28 exe "return s:have_" . name
29endfun
30
31" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on
32" the flags in the compressed file.
33" The only compression methods that can be detected are max speed (-1) and max
34" compression (-9).
35fun s:set_compression(line)
36 " get the Compression Method
37 let l:cm = char2nr(a:line[2])
38 " if it's 8 (DEFLATE), we can check for the compression level
39 if l:cm == 8
40 " get the eXtra FLags
41 let l:xfl = char2nr(a:line[8])
42 " max compression
43 if l:xfl == 2
44 let b:gzip_comp_arg = "-9"
45 " min compression
46 elseif l:xfl == 4
47 let b:gzip_comp_arg = "-1"
48 endif
49 endif
50endfun
51
52
53" After reading compressed file: Uncompress text in buffer with "cmd"
54fun gzip#read(cmd)
55 " don't do anything if the cmd is not supported
56 if !s:check(a:cmd)
57 return
58 endif
59
60 " for gzip check current compression level and set b:gzip_comp_arg.
61 silent! unlet b:gzip_comp_arg
62 if a:cmd[0] == 'g'
63 call s:set_compression(getline(1))
64 endif
65
66 " make 'patchmode' empty, we don't want a copy of the written file
67 let pm_save = &pm
68 set pm=
69 " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes
70 let cpo_save = &cpo
71 set cpo-=a cpo-=A
72 " set 'modifiable'
73 let ma_save = &ma
74 setlocal ma
Bram Moolenaar2ec618c2016-10-01 14:47:05 +020075 " set 'write'
76 let write_save = &write
77 set write
Bram Moolenaarc1762cc2007-05-10 16:56:30 +000078 " Reset 'foldenable', otherwise line numbers get adjusted.
79 if has("folding")
80 let fen_save = &fen
81 setlocal nofen
82 endif
83
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000084 " when filtering the whole buffer, it will become empty
85 let empty = line("'[") == 1 && line("']") == line("$")
86 let tmp = tempname()
87 let tmpe = tmp . "." . expand("<afile>:e")
Bram Moolenaarc24dca22008-05-29 20:41:57 +000088 if exists('*fnameescape')
89 let tmp_esc = fnameescape(tmp)
90 let tmpe_esc = fnameescape(tmpe)
91 else
92 let tmp_esc = escape(tmp, ' ')
93 let tmpe_esc = escape(tmpe, ' ')
94 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000095 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaarc24dca22008-05-29 20:41:57 +000096 execute "silent '[,']w " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000097 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000098 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000099 if !filereadable(tmp)
100 " uncompress didn't work! Keep the compressed file then.
101 echoerr "Error: Could not read uncompressed file"
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000102 let ok = 0
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000103 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000104 let ok = 1
105 " delete the compressed lines; remember the line number
106 let l = line("'[") - 1
107 if exists(":lockmarks")
108 lockmarks '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000109 else
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000110 '[,']d _
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000111 endif
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000112 " read in the uncompressed lines "'[-1r tmp"
113 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
114 setlocal nobin
115 if exists(":lockmarks")
116 if empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000117 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000118 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000119 execute "silent lockmarks " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000120 endif
121 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000122 execute "silent " . l . "r " . tmp_esc
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000123 endif
124
125 " if buffer became empty, delete trailing blank line
126 if empty
127 silent $delete _
128 1
129 endif
130 " delete the temp file and the used buffers
131 call delete(tmp)
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000132 silent! exe "bwipe " . tmp_esc
133 silent! exe "bwipe " . tmpe_esc
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000134 endif
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100135 " Store the OK flag, so that we can use it when writing.
136 let b:uncompressOk = ok
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000137
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000138 " Restore saved option values.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000139 let &pm = pm_save
140 let &cpo = cpo_save
141 let &l:ma = ma_save
Bram Moolenaar2ec618c2016-10-01 14:47:05 +0200142 let &write = write_save
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000143 if has("folding")
144 let &l:fen = fen_save
145 endif
146
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000147 " When uncompressed the whole buffer, do autocommands
Bram Moolenaarc1762cc2007-05-10 16:56:30 +0000148 if ok && empty
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000149 if exists('*fnameescape')
150 let fname = fnameescape(expand("%:r"))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000151 else
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000152 let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
153 endif
154 if &verbose >= 8
155 execute "doau BufReadPost " . fname
156 else
157 execute "silent! doau BufReadPost " . fname
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000158 endif
159 endif
160endfun
161
162" After writing compressed file: Compress written file with "cmd"
163fun gzip#write(cmd)
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100164 if exists('b:uncompressOk') && !b:uncompressOk
165 echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000166 " don't do anything if the cmd is not supported
Bram Moolenaar32efaf62014-11-05 17:02:17 +0100167 elseif s:check(a:cmd)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000168 " Rename the file before compressing it.
169 let nm = resolve(expand("<afile>"))
170 let nmt = s:tempname(nm)
171 if rename(nm, nmt) == 0
172 if exists("b:gzip_comp_arg")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000173 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000174 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000175 call system(a:cmd . " -- " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000176 endif
177 call rename(nmt . "." . expand("<afile>:e"), nm)
178 endif
179 endif
180endfun
181
182" Before appending to compressed file: Uncompress file with "cmd"
183fun gzip#appre(cmd)
184 " don't do anything if the cmd is not supported
185 if s:check(a:cmd)
186 let nm = expand("<afile>")
187
188 " for gzip check current compression level and set b:gzip_comp_arg.
189 silent! unlet b:gzip_comp_arg
190 if a:cmd[0] == 'g'
191 call s:set_compression(readfile(nm, "b", 1)[0])
192 endif
193
194 " Rename to a weird name to avoid the risk of overwriting another file
195 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
196 let nmte = nmt . "." . expand("<afile>:e")
197 if rename(nm, nmte) == 0
198 if &patchmode != "" && getfsize(nm . &patchmode) == -1
199 " Create patchmode file by creating the decompressed file new
Bram Moolenaarc236c162008-07-13 17:41:49 +0000200 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000201 call rename(nmte, nm . &patchmode)
202 else
Bram Moolenaarc236c162008-07-13 17:41:49 +0000203 call system(a:cmd . " -- " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000204 endif
205 call rename(nmt, nm)
206 endif
207 endif
208endfun
209
210" find a file name for the file to be compressed. Use "name" without an
211" extension if possible. Otherwise use a weird name to avoid overwriting an
212" existing file.
213fun s:tempname(name)
214 let fn = fnamemodify(a:name, ":r")
215 if !filereadable(fn) && !isdirectory(fn)
216 return fn
217 endif
218 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
219endfun
220
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000221fun s:escape(name)
222 " shellescape() was added by patch 7.0.111
Bram Moolenaar5c5b0942007-05-06 12:07:59 +0000223 if exists("*shellescape")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000224 return shellescape(a:name)
225 endif
226 return "'" . a:name . "'"
227endfun
228
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000229" vim: set sw=2 :