summaryrefslogtreecommitdiff
path: root/runtime/plugin/gzip.vim
blob: 2b9b5238dc12c107f0d9e4bc4f830f2cb49ede7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
" Vim plugin for editing compressed files.
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2004 Jul 30

" Exit quickly when:
" - this plugin was already loaded
" - when 'compatible' is set
" - some autocommands are already taking care of compressed files
if exists("loaded_gzip") || &cp || exists("#BufReadPre#*.gz")
  finish
endif
let loaded_gzip = 1

augroup gzip
  " Remove all gzip autocommands
  au!

  " Enable editing of gzipped files
  " set binary mode before reading the file
  " use "gzip -d", gunzip isn't always available
  autocmd BufReadPre,FileReadPre	*.gz,*.bz2,*.Z setlocal bin
  autocmd BufReadPost,FileReadPost	*.gz  call s:read("gzip -dn")
  autocmd BufReadPost,FileReadPost	*.bz2 call s:read("bzip2 -d")
  autocmd BufReadPost,FileReadPost	*.Z   call s:read("uncompress")
  autocmd BufWritePost,FileWritePost	*.gz  call s:write("gzip")
  autocmd BufWritePost,FileWritePost	*.bz2 call s:write("bzip2")
  autocmd BufWritePost,FileWritePost	*.Z   call s:write("compress -f")
  autocmd FileAppendPre			*.gz  call s:appre("gzip -dn")
  autocmd FileAppendPre			*.bz2 call s:appre("bzip2 -d")
  autocmd FileAppendPre			*.Z   call s:appre("uncompress")
  autocmd FileAppendPost		*.gz  call s:write("gzip")
  autocmd FileAppendPost		*.bz2 call s:write("bzip2")
  autocmd FileAppendPost		*.Z   call s:write("compress -f")
augroup END

" Function to check that executing "cmd [-f]" works.
" The result is cached in s:have_"cmd" for speed.
fun s:check(cmd)
  let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
  if !exists("s:have_" . name)
    let e = executable(name)
    if e < 0
      let r = system(name . " --version")
      let e = (r !~ "not found" && r != "")
    endif
    exe "let s:have_" . name . "=" . e
  endif
  exe "return s:have_" . name
endfun

" After reading compressed file: Uncompress text in buffer with "cmd"
fun s:read(cmd)
  " don't do anything if the cmd is not supported
  if !s:check(a:cmd)
    return
  endif
  " make 'patchmode' empty, we don't want a copy of the written file
  let pm_save = &pm
  set pm=
  " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes
  let cpo_save = &cpo
  set cpo-=a cpo-=A
  " set 'modifiable'
  let ma_save = &ma
  setlocal ma
  " when filtering the whole buffer, it will become empty
  let empty = line("'[") == 1 && line("']") == line("$")
  let tmp = tempname()
  let tmpe = tmp . "." . expand("<afile>:e")
  " write the just read lines to a temp file "'[,']w tmp.gz"
  execute "silent '[,']w " . tmpe
  " uncompress the temp file: call system("gzip -dn tmp.gz")
  call system(a:cmd . " " . tmpe)
  if !filereadable(tmp)
    " uncompress didn't work!  Keep the compressed file then.
    echoerr "Error: Could not read uncompressed file"
    return
  endif
  " delete the compressed lines; remember the line number
  let l = line("'[") - 1
  if exists(":lockmarks")
    lockmarks '[,']d _
  else
    '[,']d _
  endif
  " read in the uncompressed lines "'[-1r tmp"
  setlocal nobin
  if exists(":lockmarks")
    execute "silent lockmarks " . l . "r " . tmp
  else
    execute "silent " . l . "r " . tmp
  endif

  " if buffer became empty, delete trailing blank line
  if empty
    silent $delete _
    1
  endif
  " delete the temp file and the used buffers
  call delete(tmp)
  silent! exe "bwipe " . tmp
  silent! exe "bwipe " . tmpe
  let &pm = pm_save
  let &cpo = cpo_save
  let &l:ma = ma_save
  " When uncompressed the whole buffer, do autocommands
  if empty
    if &verbose >= 8
      execute "doau BufReadPost " . expand("%:r")
    else
      execute "silent! doau BufReadPost " . expand("%:r")
    endif
  endif
endfun

" After writing compressed file: Compress written file with "cmd"
fun s:write(cmd)
  " don't do anything if the cmd is not supported
  if s:check(a:cmd)
    " Rename the file before compressing it.
    let nm = expand("<afile>")
    let nmt = s:tempname(nm)
    if rename(nm, nmt) == 0
      call system(a:cmd . " " . nmt)
      call rename(nmt . "." . expand("<afile>:e"), nm)
    endif
  endif
endfun

" Before appending to compressed file: Uncompress file with "cmd"
fun s:appre(cmd)
  " don't do anything if the cmd is not supported
  if s:check(a:cmd)
    " Rename to a weird name to avoid the risk of overwriting another file
    let nm = expand("<afile>")
    let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
    let nmte = nmt . "." . expand("<afile>:e")
    if rename(nm, nmte) == 0
      if &patchmode != "" && getfsize(nm . &patchmode) == -1
	" Create patchmode file by creating the decompressed file new
	call system(a:cmd . " -c " . nmte . " > " . nmt)
	call rename(nmte, nm . &patchmode)
      else
	call system(a:cmd . " " . nmte)
      endif
      call rename(nmt, nm)
    endif
  endif
endfun

" find a file name for the file to be compressed.  Use "name" without an
" extension if possible.  Otherwise use a weird name to avoid overwriting an
" existing file.
fun s:tempname(name)
  let fn = fnamemodify(a:name, ":r")
  if !filereadable(fn) && !isdirectory(fn)
    return fn
  endif
  return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
endfun

" vim: set sw=2 :