xref: /vim-8.2.3635/runtime/autoload/gzip.vim (revision 2ec618c9)
187e25fdfSBram Moolenaar" Vim autoload file for editing compressed files.
287e25fdfSBram Moolenaar" Maintainer: Bram Moolenaar <[email protected]>
3*2ec618c9SBram Moolenaar" Last Change: 2016 Sep 28
487e25fdfSBram Moolenaar
587e25fdfSBram Moolenaar" These functions are used by the gzip plugin.
687e25fdfSBram Moolenaar
787e25fdfSBram Moolenaar" Function to check that executing "cmd [-f]" works.
887e25fdfSBram Moolenaar" The result is cached in s:have_"cmd" for speed.
987e25fdfSBram Moolenaarfun s:check(cmd)
1087e25fdfSBram Moolenaar  let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
1187e25fdfSBram Moolenaar  if !exists("s:have_" . name)
1287e25fdfSBram Moolenaar    let e = executable(name)
1387e25fdfSBram Moolenaar    if e < 0
1487e25fdfSBram Moolenaar      let r = system(name . " --version")
1587e25fdfSBram Moolenaar      let e = (r !~ "not found" && r != "")
1687e25fdfSBram Moolenaar    endif
1787e25fdfSBram Moolenaar    exe "let s:have_" . name . "=" . e
1887e25fdfSBram Moolenaar  endif
1987e25fdfSBram Moolenaar  exe "return s:have_" . name
2087e25fdfSBram Moolenaarendfun
2187e25fdfSBram Moolenaar
2287e25fdfSBram Moolenaar" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on
2387e25fdfSBram Moolenaar" the flags in the compressed file.
2487e25fdfSBram Moolenaar" The only compression methods that can be detected are max speed (-1) and max
2587e25fdfSBram Moolenaar" compression (-9).
2687e25fdfSBram Moolenaarfun s:set_compression(line)
2787e25fdfSBram Moolenaar  " get the Compression Method
2887e25fdfSBram Moolenaar  let l:cm = char2nr(a:line[2])
2987e25fdfSBram Moolenaar  " if it's 8 (DEFLATE), we can check for the compression level
3087e25fdfSBram Moolenaar  if l:cm == 8
3187e25fdfSBram Moolenaar    " get the eXtra FLags
3287e25fdfSBram Moolenaar    let l:xfl = char2nr(a:line[8])
3387e25fdfSBram Moolenaar    " max compression
3487e25fdfSBram Moolenaar    if l:xfl == 2
3587e25fdfSBram Moolenaar      let b:gzip_comp_arg = "-9"
3687e25fdfSBram Moolenaar    " min compression
3787e25fdfSBram Moolenaar    elseif l:xfl == 4
3887e25fdfSBram Moolenaar      let b:gzip_comp_arg = "-1"
3987e25fdfSBram Moolenaar    endif
4087e25fdfSBram Moolenaar  endif
4187e25fdfSBram Moolenaarendfun
4287e25fdfSBram Moolenaar
4387e25fdfSBram Moolenaar
4487e25fdfSBram Moolenaar" After reading compressed file: Uncompress text in buffer with "cmd"
4587e25fdfSBram Moolenaarfun gzip#read(cmd)
4687e25fdfSBram Moolenaar  " don't do anything if the cmd is not supported
4787e25fdfSBram Moolenaar  if !s:check(a:cmd)
4887e25fdfSBram Moolenaar    return
4987e25fdfSBram Moolenaar  endif
5087e25fdfSBram Moolenaar
5187e25fdfSBram Moolenaar  " for gzip check current compression level and set b:gzip_comp_arg.
5287e25fdfSBram Moolenaar  silent! unlet b:gzip_comp_arg
5387e25fdfSBram Moolenaar  if a:cmd[0] == 'g'
5487e25fdfSBram Moolenaar    call s:set_compression(getline(1))
5587e25fdfSBram Moolenaar  endif
5687e25fdfSBram Moolenaar
5787e25fdfSBram Moolenaar  " make 'patchmode' empty, we don't want a copy of the written file
5887e25fdfSBram Moolenaar  let pm_save = &pm
5987e25fdfSBram Moolenaar  set pm=
6087e25fdfSBram Moolenaar  " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes
6187e25fdfSBram Moolenaar  let cpo_save = &cpo
6287e25fdfSBram Moolenaar  set cpo-=a cpo-=A
6387e25fdfSBram Moolenaar  " set 'modifiable'
6487e25fdfSBram Moolenaar  let ma_save = &ma
6587e25fdfSBram Moolenaar  setlocal ma
66*2ec618c9SBram Moolenaar  " set 'write'
67*2ec618c9SBram Moolenaar  let write_save = &write
68*2ec618c9SBram Moolenaar  set write
69c1762ccbSBram Moolenaar  " Reset 'foldenable', otherwise line numbers get adjusted.
70c1762ccbSBram Moolenaar  if has("folding")
71c1762ccbSBram Moolenaar    let fen_save = &fen
72c1762ccbSBram Moolenaar    setlocal nofen
73c1762ccbSBram Moolenaar  endif
74c1762ccbSBram Moolenaar
7587e25fdfSBram Moolenaar  " when filtering the whole buffer, it will become empty
7687e25fdfSBram Moolenaar  let empty = line("'[") == 1 && line("']") == line("$")
7787e25fdfSBram Moolenaar  let tmp = tempname()
7887e25fdfSBram Moolenaar  let tmpe = tmp . "." . expand("<afile>:e")
79c24dca26SBram Moolenaar  if exists('*fnameescape')
80c24dca26SBram Moolenaar    let tmp_esc = fnameescape(tmp)
81c24dca26SBram Moolenaar    let tmpe_esc = fnameescape(tmpe)
82c24dca26SBram Moolenaar  else
83c24dca26SBram Moolenaar    let tmp_esc = escape(tmp, ' ')
84c24dca26SBram Moolenaar    let tmpe_esc = escape(tmpe, ' ')
85c24dca26SBram Moolenaar  endif
8687e25fdfSBram Moolenaar  " write the just read lines to a temp file "'[,']w tmp.gz"
87c24dca26SBram Moolenaar  execute "silent '[,']w " . tmpe_esc
8887e25fdfSBram Moolenaar  " uncompress the temp file: call system("gzip -dn tmp.gz")
8960a495f0SBram Moolenaar  call system(a:cmd . " " . s:escape(tmpe))
9087e25fdfSBram Moolenaar  if !filereadable(tmp)
9187e25fdfSBram Moolenaar    " uncompress didn't work!  Keep the compressed file then.
9287e25fdfSBram Moolenaar    echoerr "Error: Could not read uncompressed file"
93c1762ccbSBram Moolenaar    let ok = 0
94c1762ccbSBram Moolenaar  else
95c1762ccbSBram Moolenaar    let ok = 1
9687e25fdfSBram Moolenaar    " delete the compressed lines; remember the line number
9787e25fdfSBram Moolenaar    let l = line("'[") - 1
9887e25fdfSBram Moolenaar    if exists(":lockmarks")
9987e25fdfSBram Moolenaar      lockmarks '[,']d _
10087e25fdfSBram Moolenaar    else
10187e25fdfSBram Moolenaar      '[,']d _
10287e25fdfSBram Moolenaar    endif
10387e25fdfSBram Moolenaar    " read in the uncompressed lines "'[-1r tmp"
104910f66f9SBram Moolenaar    " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
10587e25fdfSBram Moolenaar    setlocal nobin
10687e25fdfSBram Moolenaar    if exists(":lockmarks")
107910f66f9SBram Moolenaar      if empty
108c24dca26SBram Moolenaar	execute "silent lockmarks " . l . "r ++edit " . tmp_esc
109910f66f9SBram Moolenaar      else
110c24dca26SBram Moolenaar	execute "silent lockmarks " . l . "r " . tmp_esc
111910f66f9SBram Moolenaar      endif
11287e25fdfSBram Moolenaar    else
113c24dca26SBram Moolenaar      execute "silent " . l . "r " . tmp_esc
11487e25fdfSBram Moolenaar    endif
11587e25fdfSBram Moolenaar
11687e25fdfSBram Moolenaar    " if buffer became empty, delete trailing blank line
11787e25fdfSBram Moolenaar    if empty
11887e25fdfSBram Moolenaar      silent $delete _
11987e25fdfSBram Moolenaar      1
12087e25fdfSBram Moolenaar    endif
12187e25fdfSBram Moolenaar    " delete the temp file and the used buffers
12287e25fdfSBram Moolenaar    call delete(tmp)
123c24dca26SBram Moolenaar    silent! exe "bwipe " . tmp_esc
124c24dca26SBram Moolenaar    silent! exe "bwipe " . tmpe_esc
125c1762ccbSBram Moolenaar  endif
12632efaf61SBram Moolenaar  " Store the OK flag, so that we can use it when writing.
12732efaf61SBram Moolenaar  let b:uncompressOk = ok
128c1762ccbSBram Moolenaar
129c1762ccbSBram Moolenaar  " Restore saved option values.
13087e25fdfSBram Moolenaar  let &pm = pm_save
13187e25fdfSBram Moolenaar  let &cpo = cpo_save
13287e25fdfSBram Moolenaar  let &l:ma = ma_save
133*2ec618c9SBram Moolenaar  let &write = write_save
134c1762ccbSBram Moolenaar  if has("folding")
135c1762ccbSBram Moolenaar    let &l:fen = fen_save
136c1762ccbSBram Moolenaar  endif
137c1762ccbSBram Moolenaar
13887e25fdfSBram Moolenaar  " When uncompressed the whole buffer, do autocommands
139c1762ccbSBram Moolenaar  if ok && empty
140c24dca26SBram Moolenaar    if exists('*fnameescape')
141c24dca26SBram Moolenaar      let fname = fnameescape(expand("%:r"))
14287e25fdfSBram Moolenaar    else
143c24dca26SBram Moolenaar      let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
144c24dca26SBram Moolenaar    endif
145c24dca26SBram Moolenaar    if &verbose >= 8
146c24dca26SBram Moolenaar      execute "doau BufReadPost " . fname
147c24dca26SBram Moolenaar    else
148c24dca26SBram Moolenaar      execute "silent! doau BufReadPost " . fname
14987e25fdfSBram Moolenaar    endif
15087e25fdfSBram Moolenaar  endif
15187e25fdfSBram Moolenaarendfun
15287e25fdfSBram Moolenaar
15387e25fdfSBram Moolenaar" After writing compressed file: Compress written file with "cmd"
15487e25fdfSBram Moolenaarfun gzip#write(cmd)
15532efaf61SBram Moolenaar  if exists('b:uncompressOk') && !b:uncompressOk
15632efaf61SBram Moolenaar    echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
15787e25fdfSBram Moolenaar  " don't do anything if the cmd is not supported
15832efaf61SBram Moolenaar  elseif s:check(a:cmd)
15987e25fdfSBram Moolenaar    " Rename the file before compressing it.
16087e25fdfSBram Moolenaar    let nm = resolve(expand("<afile>"))
16187e25fdfSBram Moolenaar    let nmt = s:tempname(nm)
16287e25fdfSBram Moolenaar    if rename(nm, nmt) == 0
16387e25fdfSBram Moolenaar      if exists("b:gzip_comp_arg")
164c236c16dSBram Moolenaar	call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
16587e25fdfSBram Moolenaar      else
166c236c16dSBram Moolenaar	call system(a:cmd . " -- " . s:escape(nmt))
16787e25fdfSBram Moolenaar      endif
16887e25fdfSBram Moolenaar      call rename(nmt . "." . expand("<afile>:e"), nm)
16987e25fdfSBram Moolenaar    endif
17087e25fdfSBram Moolenaar  endif
17187e25fdfSBram Moolenaarendfun
17287e25fdfSBram Moolenaar
17387e25fdfSBram Moolenaar" Before appending to compressed file: Uncompress file with "cmd"
17487e25fdfSBram Moolenaarfun gzip#appre(cmd)
17587e25fdfSBram Moolenaar  " don't do anything if the cmd is not supported
17687e25fdfSBram Moolenaar  if s:check(a:cmd)
17787e25fdfSBram Moolenaar    let nm = expand("<afile>")
17887e25fdfSBram Moolenaar
17987e25fdfSBram Moolenaar    " for gzip check current compression level and set b:gzip_comp_arg.
18087e25fdfSBram Moolenaar    silent! unlet b:gzip_comp_arg
18187e25fdfSBram Moolenaar    if a:cmd[0] == 'g'
18287e25fdfSBram Moolenaar      call s:set_compression(readfile(nm, "b", 1)[0])
18387e25fdfSBram Moolenaar    endif
18487e25fdfSBram Moolenaar
18587e25fdfSBram Moolenaar    " Rename to a weird name to avoid the risk of overwriting another file
18687e25fdfSBram Moolenaar    let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
18787e25fdfSBram Moolenaar    let nmte = nmt . "." . expand("<afile>:e")
18887e25fdfSBram Moolenaar    if rename(nm, nmte) == 0
18987e25fdfSBram Moolenaar      if &patchmode != "" && getfsize(nm . &patchmode) == -1
19087e25fdfSBram Moolenaar	" Create patchmode file by creating the decompressed file new
191c236c16dSBram Moolenaar	call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
19287e25fdfSBram Moolenaar	call rename(nmte, nm . &patchmode)
19387e25fdfSBram Moolenaar      else
194c236c16dSBram Moolenaar	call system(a:cmd . " -- " . s:escape(nmte))
19587e25fdfSBram Moolenaar      endif
19687e25fdfSBram Moolenaar      call rename(nmt, nm)
19787e25fdfSBram Moolenaar    endif
19887e25fdfSBram Moolenaar  endif
19987e25fdfSBram Moolenaarendfun
20087e25fdfSBram Moolenaar
20187e25fdfSBram Moolenaar" find a file name for the file to be compressed.  Use "name" without an
20287e25fdfSBram Moolenaar" extension if possible.  Otherwise use a weird name to avoid overwriting an
20387e25fdfSBram Moolenaar" existing file.
20487e25fdfSBram Moolenaarfun s:tempname(name)
20587e25fdfSBram Moolenaar  let fn = fnamemodify(a:name, ":r")
20687e25fdfSBram Moolenaar  if !filereadable(fn) && !isdirectory(fn)
20787e25fdfSBram Moolenaar    return fn
20887e25fdfSBram Moolenaar  endif
20987e25fdfSBram Moolenaar  return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
21087e25fdfSBram Moolenaarendfun
21187e25fdfSBram Moolenaar
21260a495f0SBram Moolenaarfun s:escape(name)
21360a495f0SBram Moolenaar  " shellescape() was added by patch 7.0.111
2145c5b0941SBram Moolenaar  if exists("*shellescape")
21560a495f0SBram Moolenaar    return shellescape(a:name)
21660a495f0SBram Moolenaar  endif
21760a495f0SBram Moolenaar  return "'" . a:name . "'"
21860a495f0SBram Moolenaarendfun
21960a495f0SBram Moolenaar
22087e25fdfSBram Moolenaar" vim: set sw=2 :
221