neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

gzip.vim (6819B)


      1 " Vim autoload file for editing compressed files.
      2 " Maintainer:	The Vim Project <https://github.com/vim/vim>
      3 " Last Change:	2024 Nov 25
      4 " Former Maintainer: Bram Moolenaar <Bram@vim.org>
      5 
      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.
     10 fun s:check(cmd)
     11  let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
     12  if !exists("s:have_" . name)
     13    " safety check, don't execute anything from the current directory
     14    let f = dist#vim#IsSafeExecutable('gzip', name)
     15    if !f
     16      echoerr "Warning: NOT executing " .. name .. " from current directory!"
     17    endif
     18    let e = executable(name)
     19    if e < 0
     20      let r = system(name . " --version")
     21      let e = (r !~ "not found" && r != "")
     22    endif
     23    exe "let s:have_" . name . "=" . (e && f)
     24  endif
     25  exe "return s:have_" . name
     26 endfun
     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).
     32 fun 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
     47 endfun
     48 
     49 
     50 " After reading compressed file: Uncompress text in buffer with "cmd"
     51 fun 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
     72  " set 'write'
     73  let write_save = &write
     74  set write
     75  " Reset 'foldenable', otherwise line numbers get adjusted.
     76  if has("folding")
     77    let fen_save = &fen
     78    setlocal nofen
     79  endif
     80 
     81  " 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")
     85  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
     92  " write the just read lines to a temp file "'[,']w tmp.gz"
     93  execute "silent '[,']w " . tmpe_esc
     94  " uncompress the temp file: call system("gzip -dn tmp.gz")
     95  call system(a:cmd . " " . s:escape(tmpe))
     96  if !filereadable(tmp)
     97    " uncompress didn't work!  Keep the compressed file then.
     98    echoerr "Error: Could not read uncompressed file"
     99    let ok = 0
    100  else
    101    let ok = 1
    102    " delete the compressed lines; remember the line number
    103    let l = line("'[") - 1
    104    if exists(":lockmarks")
    105      lockmarks '[,']d _
    106    else
    107      '[,']d _
    108    endif
    109    " 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
    114 execute "silent lockmarks " . l . "r ++edit " . tmp_esc
    115      else
    116 execute "silent lockmarks " . l . "r " . tmp_esc
    117      endif
    118    else
    119      execute "silent " . l . "r " . tmp_esc
    120    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)
    129    silent! exe "bwipe " . tmp_esc
    130    silent! exe "bwipe " . tmpe_esc
    131  endif
    132  " Store the OK flag, so that we can use it when writing.
    133  let b:uncompressOk = ok
    134 
    135  " Restore saved option values.
    136  let &pm = pm_save
    137  let &cpo = cpo_save
    138  let &l:ma = ma_save
    139  let &write = write_save
    140  if has("folding")
    141    let &l:fen = fen_save
    142  endif
    143 
    144  " When uncompressed the whole buffer, do autocommands
    145  if ok && empty
    146    if exists('*fnameescape')
    147      let fname = fnameescape(expand("%:r"))
    148    else
    149      let fname = escape(expand("%:r"), " \t\n*?[{`$\\%#'\"|!<")
    150    endif
    151    if filereadable(undofile(expand("%")))
    152      exe "sil rundo " . fnameescape(undofile(expand("%")))
    153    endif
    154    if &verbose >= 8
    155      execute "doau BufReadPost " . fname
    156    else
    157      execute "silent! doau BufReadPost " . fname
    158    endif
    159  endif
    160 endfun
    161 
    162 " After writing compressed file: Compress written file with "cmd"
    163 fun gzip#write(cmd)
    164  if exists('b:uncompressOk') && !b:uncompressOk
    165    echomsg "Not compressing file because uncompress failed; reset b:uncompressOk to compress anyway"
    166  " don't do anything if the cmd is not supported
    167  elseif s:check(a:cmd)
    168    " 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")
    173 call system(a:cmd . " " . b:gzip_comp_arg . " -- " . s:escape(nmt))
    174      else
    175 call system(a:cmd . " -- " . s:escape(nmt))
    176      endif
    177      call rename(nmt . "." . expand("<afile>:e"), nm)
    178    endif
    179  endif
    180 endfun
    181 
    182 " Before appending to compressed file: Uncompress file with "cmd"
    183 fun 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
    200 call system(a:cmd . " -c -- " . s:escape(nmte) . " > " . s:escape(nmt))
    201 call rename(nmte, nm . &patchmode)
    202      else
    203 call system(a:cmd . " -- " . s:escape(nmte))
    204      endif
    205      call rename(nmt, nm)
    206    endif
    207  endif
    208 endfun
    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.
    213 fun 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"
    219 endfun
    220 
    221 fun s:escape(name)
    222  " shellescape() was added by patch 7.0.111
    223  if exists("*shellescape")
    224    return shellescape(a:name)
    225  endif
    226  return "'" . a:name . "'"
    227 endfun
    228 
    229 " vim: set sw=2 :