blob: 2b9b5238dc12c107f0d9e4bc4f830f2cb49ede7e [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Vim plugin for editing compressed files.
2" Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003" Last Change: 2004 Jul 30
Bram Moolenaar071d4272004-06-13 20:20:40 +00004
5" Exit quickly when:
6" - this plugin was already loaded
7" - when 'compatible' is set
8" - some autocommands are already taking care of compressed files
9if exists("loaded_gzip") || &cp || exists("#BufReadPre#*.gz")
10 finish
11endif
12let loaded_gzip = 1
13
14augroup gzip
15 " Remove all gzip autocommands
16 au!
17
18 " Enable editing of gzipped files
19 " set binary mode before reading the file
20 " use "gzip -d", gunzip isn't always available
21 autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z setlocal bin
22 autocmd BufReadPost,FileReadPost *.gz call s:read("gzip -dn")
23 autocmd BufReadPost,FileReadPost *.bz2 call s:read("bzip2 -d")
24 autocmd BufReadPost,FileReadPost *.Z call s:read("uncompress")
25 autocmd BufWritePost,FileWritePost *.gz call s:write("gzip")
26 autocmd BufWritePost,FileWritePost *.bz2 call s:write("bzip2")
27 autocmd BufWritePost,FileWritePost *.Z call s:write("compress -f")
28 autocmd FileAppendPre *.gz call s:appre("gzip -dn")
29 autocmd FileAppendPre *.bz2 call s:appre("bzip2 -d")
30 autocmd FileAppendPre *.Z call s:appre("uncompress")
31 autocmd FileAppendPost *.gz call s:write("gzip")
32 autocmd FileAppendPost *.bz2 call s:write("bzip2")
33 autocmd FileAppendPost *.Z call s:write("compress -f")
34augroup END
35
36" Function to check that executing "cmd [-f]" works.
37" The result is cached in s:have_"cmd" for speed.
38fun s:check(cmd)
39 let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
40 if !exists("s:have_" . name)
41 let e = executable(name)
42 if e < 0
43 let r = system(name . " --version")
44 let e = (r !~ "not found" && r != "")
45 endif
46 exe "let s:have_" . name . "=" . e
47 endif
48 exe "return s:have_" . name
49endfun
50
51" After reading compressed file: Uncompress text in buffer with "cmd"
52fun s:read(cmd)
53 " don't do anything if the cmd is not supported
54 if !s:check(a:cmd)
55 return
56 endif
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 " when filtering the whole buffer, it will become empty
67 let empty = line("'[") == 1 && line("']") == line("$")
68 let tmp = tempname()
69 let tmpe = tmp . "." . expand("<afile>:e")
70 " write the just read lines to a temp file "'[,']w tmp.gz"
71 execute "silent '[,']w " . tmpe
72 " uncompress the temp file: call system("gzip -dn tmp.gz")
73 call system(a:cmd . " " . tmpe)
Bram Moolenaard4755bb2004-09-02 19:12:26 +000074 if !filereadable(tmp)
75 " uncompress didn't work! Keep the compressed file then.
76 echoerr "Error: Could not read uncompressed file"
77 return
78 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000079 " delete the compressed lines; remember the line number
80 let l = line("'[") - 1
81 if exists(":lockmarks")
82 lockmarks '[,']d _
83 else
84 '[,']d _
85 endif
86 " read in the uncompressed lines "'[-1r tmp"
87 setlocal nobin
88 if exists(":lockmarks")
89 execute "silent lockmarks " . l . "r " . tmp
90 else
91 execute "silent " . l . "r " . tmp
92 endif
93
94 " if buffer became empty, delete trailing blank line
95 if empty
96 silent $delete _
97 1
98 endif
99 " delete the temp file and the used buffers
100 call delete(tmp)
101 silent! exe "bwipe " . tmp
102 silent! exe "bwipe " . tmpe
103 let &pm = pm_save
104 let &cpo = cpo_save
105 let &l:ma = ma_save
106 " When uncompressed the whole buffer, do autocommands
107 if empty
108 if &verbose >= 8
109 execute "doau BufReadPost " . expand("%:r")
110 else
111 execute "silent! doau BufReadPost " . expand("%:r")
112 endif
113 endif
114endfun
115
116" After writing compressed file: Compress written file with "cmd"
117fun s:write(cmd)
118 " don't do anything if the cmd is not supported
119 if s:check(a:cmd)
120 " Rename the file before compressing it.
121 let nm = expand("<afile>")
122 let nmt = s:tempname(nm)
123 if rename(nm, nmt) == 0
124 call system(a:cmd . " " . nmt)
125 call rename(nmt . "." . expand("<afile>:e"), nm)
126 endif
127 endif
128endfun
129
130" Before appending to compressed file: Uncompress file with "cmd"
131fun s:appre(cmd)
132 " don't do anything if the cmd is not supported
133 if s:check(a:cmd)
134 " Rename to a weird name to avoid the risk of overwriting another file
135 let nm = expand("<afile>")
136 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
137 let nmte = nmt . "." . expand("<afile>:e")
138 if rename(nm, nmte) == 0
139 if &patchmode != "" && getfsize(nm . &patchmode) == -1
140 " Create patchmode file by creating the decompressed file new
141 call system(a:cmd . " -c " . nmte . " > " . nmt)
142 call rename(nmte, nm . &patchmode)
143 else
144 call system(a:cmd . " " . nmte)
145 endif
146 call rename(nmt, nm)
147 endif
148 endif
149endfun
150
151" find a file name for the file to be compressed. Use "name" without an
152" extension if possible. Otherwise use a weird name to avoid overwriting an
153" existing file.
154fun s:tempname(name)
155 let fn = fnamemodify(a:name, ":r")
156 if !filereadable(fn) && !isdirectory(fn)
157 return fn
158 endif
159 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
160endfun
161
162" vim: set sw=2 :