blob: a6fbe2c336ef7a206d5760e7c05afa3b372916e6 [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>
Christian Brabandt7e501f42024-11-26 15:10:33 +01003" Last Change: 2024 Nov 25
Christian Brabandte978b452023-08-13 10:33:05 +02004" 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
D. Ben Knoblecd8a3ea2023-11-04 05:11:17 -040014 let f = dist#vim#IsSafeExecutable('gzip', name)
Christian Brabandt816fbcc2023-08-31 23:52:30 +020015 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
Christian Brabandt7e501f42024-11-26 15:10:33 +0100151 if filereadable(undofile(expand("%")))
152 exe "sil rundo " . fnameescape(undofile(expand("%")))
153 endif
Bram Moolenaarc24dca22008-05-29 20:41:57 +0000154 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 :