xref: /vim-8.2.3635/runtime/autoload/gzip.vim (revision cf2d8dee)
1" Vim autoload file for editing compressed files.
2" Maintainer: Bram Moolenaar <[email protected]>
3" Last Change: 2014 Nov 05
4
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
66  " Reset 'foldenable', otherwise line numbers get adjusted.
67  if has("folding")
68    let fen_save = &fen
69    setlocal nofen
70  endif
71
72  " when filtering the whole buffer, it will become empty
73  let empty = line("'[") == 1 && line("']") == line("$")
74  let tmp = tempname()
75  let tmpe = tmp . "." . expand("<afile>:e")
76  if exists('*fnameescape')
77    let tmp_esc = fnameescape(tmp)
78    let tmpe_esc = fnameescape(tmpe)
79  else
80    let tmp_esc = escape(tmp, ' ')
81    let tmpe_esc = escape(tmpe, ' ')
82  endif
83  " write the just read lines to a temp file "'[,']w tmp.gz"
84  execute "silent '[,']w " . tmpe_esc
85  " uncompress the temp file: call system("gzip -dn tmp.gz")
86  call system(a:cmd . " " . s:escape(tmpe))
87  if !filereadable(tmp)
88    " uncompress didn't work!  Keep the compressed file then.
89    echoerr "Error: Could not read uncompressed file"
90    let ok = 0
91  else
92    let ok = 1
93    " delete the compressed lines; remember the line number
94    let l = line("'[") - 1
95    if exists(":lockmarks")
96      lockmarks '[,']d _
97    else
98      '[,']d _
99    endif
100    " read in the uncompressed lines "'[-1r tmp"
101    " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
102    setlocal nobin
103    if exists(":lockmarks")
104      if empty
105	execute "silent lockmarks " . l . "r ++edit " . tmp_esc
106      else
107	execute "silent lockmarks " . l . "r " . tmp_esc
108      endif
109    else
110      execute "silent " . l . "r " . tmp_esc
111    endif
112
113    " if buffer became empty, delete trailing blank line
114    if empty
115      silent $delete _
116      1
117    endif
118    " delete the temp file and the used buffers
119    call delete(tmp)
120    silent! exe "bwipe " . tmp_esc
121    silent! exe "bwipe " . tmpe_esc
122  endif
123  " Store the OK flag, so that we can use it when writing.
124  let b:uncompressOk = ok
125
126  " Restore saved option values.
127  let &pm = pm_save
128  let &cpo = cpo_save
129  let &l:ma = ma_save
130  if has("folding")
131    let &l:fen = fen_save
132  endif
133
134  " When uncompressed the whole buffer, do autocommands
135  if ok && empty
136    if exists('*fnameescape')
137      let fname = fnameescape(expand("%:r"))
138    else
139      let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
140    endif
141    if &verbose >= 8
142      execute "doau BufReadPost " . fname
143    else
144      execute "silent! doau BufReadPost " . fname
145    endif
146  endif
147endfun
148
149" After writing compressed file: Compress written file with "cmd"
150fun gzip#write(cmd)
151  if exists('b:uncompressOk') && !b:uncompressOk
152    echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
153  " don't do anything if the cmd is not supported
154  elseif s:check(a:cmd)
155    " Rename the file before compressing it.
156    let nm = resolve(expand("<afile>"))
157    let nmt = s:tempname(nm)
158    if rename(nm, nmt) == 0
159      if exists("b:gzip_comp_arg")
160	call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
161      else
162	call system(a:cmd . " -- " . s:escape(nmt))
163      endif
164      call rename(nmt . "." . expand("<afile>:e"), nm)
165    endif
166  endif
167endfun
168
169" Before appending to compressed file: Uncompress file with "cmd"
170fun gzip#appre(cmd)
171  " don't do anything if the cmd is not supported
172  if s:check(a:cmd)
173    let nm = expand("<afile>")
174
175    " for gzip check current compression level and set b:gzip_comp_arg.
176    silent! unlet b:gzip_comp_arg
177    if a:cmd[0] == 'g'
178      call s:set_compression(readfile(nm, "b", 1)[0])
179    endif
180
181    " Rename to a weird name to avoid the risk of overwriting another file
182    let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
183    let nmte = nmt . "." . expand("<afile>:e")
184    if rename(nm, nmte) == 0
185      if &patchmode != "" && getfsize(nm . &patchmode) == -1
186	" Create patchmode file by creating the decompressed file new
187	call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
188	call rename(nmte, nm . &patchmode)
189      else
190	call system(a:cmd . " -- " . s:escape(nmte))
191      endif
192      call rename(nmt, nm)
193    endif
194  endif
195endfun
196
197" find a file name for the file to be compressed.  Use "name" without an
198" extension if possible.  Otherwise use a weird name to avoid overwriting an
199" existing file.
200fun s:tempname(name)
201  let fn = fnamemodify(a:name, ":r")
202  if !filereadable(fn) && !isdirectory(fn)
203    return fn
204  endif
205  return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
206endfun
207
208fun s:escape(name)
209  " shellescape() was added by patch 7.0.111
210  if exists("*shellescape")
211    return shellescape(a:name)
212  endif
213  return "'" . a:name . "'"
214endfun
215
216" vim: set sw=2 :
217