]> ruderich.org/simon Gitweb - config/dotfiles.git/blob - vim/vim/bundle/deb/autoload/deb.vim
vim: deb: sync with current version in Debian sid
[config/dotfiles.git] / vim / vim / bundle / deb / autoload / deb.vim
1 " Vim autoload file for browsing debian package.
2 " copyright (C) 2007-2008, arno renevier <arenevier@fdn.fr>
3 " Distributed under the GNU General Public License (version 2 or above)
4 " Last Change: 2008 april 1
5
6 " Inspired by autoload/tar.vim by Charles E Campbell
7 "
8 " Latest version of that file can be found at
9 " http://www.fdn.fr/~arenevier/vim/autoload/deb.vim
10 " It should also be available at
11 " http://www.vim.org/scripts/script.php?script_id=1970
12
13 if &cp || exists("g:loaded_deb") || v:version < 700
14     finish
15 endif
16 let g:loaded_deb= "v1.4"
17
18 fun! deb#read(debfile, member)
19
20     " checks if ar and tar are installed
21     if !s:hascmd("ar") || !s:hascmd("tar")
22         return
23     endif
24
25     let l:target = a:member
26
27     let l:archmember = s:dataFileName(a:debfile) " default archive member to extract
28     if l:archmember == ""
29         echohl WarningMsg | echo "***error*** (deb#read) no valid data member found in debian archive"
30         return
31     else
32         let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
33         if l:unpcmp =~# '^lzma' && !s:hascmd("lzma")
34             return
35         endif
36     endif
37
38     if a:member =~ '^\* ' " information control file
39         let l:target = substitute(l:target, "^\* ", "", "")
40         let l:archmember = s:controlFileName(a:debfile)
41         if l:archmember == ""
42             echohl WarningMsg | echo "***error*** (deb#read) no valid control member found in debian archive"
43             return
44         else
45             let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
46         endif
47     elseif a:member =~ ' -> ' " symbolic link
48         let l:target = split(a:member,' -> ')[0]
49         let l:linkname = split(a:member,' -> ')[1]
50
51         if l:linkname =~ "^\/" " direct symlink: path is already absolute
52             let l:target = ".".l:linkname
53
54         else 
55         " transform relative path to absolute path
56
57             " first, get basename for target
58             let l:target = substitute(l:target, "\/[^/]*$", "", "")
59
60             " while it begins with ../
61             while l:linkname =~ "^\.\.\/" 
62
63                 " removes one level of ../ in linkname
64                 let l:linkname = substitute(l:linkname, "^\.\.\/", "", "")
65
66                 " go one directory up in target
67                 let l:target = substitute(l:target, "\/[^/]*$", "", "")
68             endwhile
69
70             let l:target = l:target."/".l:linkname
71         endif
72     endif
73     
74     " we may preprocess some files (such as man pages, or changelogs)
75     let l:preproccmd = ""
76         
77     "
78     " unzip man pages
79     "
80     if l:target =~ "\.\/usr\/share\/man\/.*\.gz$"
81         
82         " try to fail gracefully if a command is not available
83         if !s:hascmd("gzip")
84             return
85         elseif !s:hascmd("nroff") 
86             let l:preproccmd = "| gzip -cd"
87         elseif !s:hascmd("col")
88             let l:preproccmd = "| gzip -cd | nroff -mandoc"
89         else
90             let l:preproccmd = "| gzip -cd | nroff -mandoc | col -b"
91         endif
92     
93     "
94     " unzip other .gz files
95     "
96     elseif l:target =~ '.*\.gz$'
97         if !s:hascmd("gzip")
98             return
99         endif
100         let l:preproccmd = "| gzip -cd"
101     endif
102
103     " read content
104     exe "silent r! ar p " . s:QuoteFile(a:debfile) . " " . s:QuoteFile(l:archmember) . " | " . l:unpcmp . " - " . s:QuoteFile(l:target) . l:preproccmd
105     " error will be treated in calling function
106     if v:shell_error != 0
107         return
108     endif
109
110     exe "file deb:".l:target
111
112     0d
113
114     setlocal nomodifiable nomodified readonly
115
116 endfun
117
118 fun! deb#browse(file)
119
120     " checks if necessary utils are installed
121     if !s:hascmd("dpkg") || !s:hascmd("ar") || !s:hascmd("tar")
122         return
123     endif
124
125     " checks if file is readable
126     if !filereadable(a:file)
127         return
128     endif
129     if a:file =~ "'"
130         echohl WarningMsg | echo "***error*** (deb#Browse) filename cannot contain quote character (" . a:file . ")"
131         return
132     endif
133
134     let keepmagic = &magic
135     set magic
136
137     " set filetype to "deb"
138     set ft=deb
139
140     setlocal modifiable noreadonly
141
142     " set header
143     exe "$put ='".'\"'." deb.vim version ".g:loaded_deb."'"
144     exe "$put ='".'\"'." Browsing debian package ".a:file."'"
145     $put=''
146
147     " package info
148     "exe "silent read! dpkg -I ".a:file
149     "$put=''
150
151     " display information control files
152     let l:infopos = line(".")
153     let l:ctrlmember = s:controlFileName(a:file)
154     if l:ctrlmember == ""
155        echohl WarningMsg | echo "***error*** (deb#Browser) no valid control member found in debian archive"
156        return
157     endif
158
159     let l:unpcmp = s:uncmp(l:ctrlmember)
160     if l:unpcmp =~# '^lzma' && !s:hascmd('lzma')
161         return
162     endif
163     exe "silent read! ar p " . s:QuoteFile(a:file) . " " . l:ctrlmember . ' | ' . l:unpcmp . 't'
164
165     $put=''
166
167     " display data files
168     let l:listpos = line(".")
169     exe "silent read! dpkg -c ". s:QuoteFile(a:file)
170
171     " format information control list
172     " removes '* ./' line
173     exe (l:infopos + 1). 'd'
174     " add a star before each line
175     exe "silent " . (l:infopos + 1). ',' . (l:listpos - 2) . 's/^/\* /'
176     
177     " format data list
178     exe "silent " . l:listpos . ',$s/^.*\s\(\.\/\(\S\|\).*\)$/\1/'
179     
180     if v:shell_error != 0
181         echohl WarningMsg | echo "***warning*** (deb#Browse) error when listing content of " . a:file
182         let &magic = keepmagic
183         return
184     endif
185
186     0d
187
188     setlocal nomodifiable readonly
189     noremap <silent> <buffer> <cr> :call <SID>DebBrowseSelect()<cr>
190     let &magic = keepmagic
191
192 endfun
193
194 fun! s:DebBrowseSelect()
195     let l:fname= getline(".")
196
197     " sanity check
198     if (l:fname !~ '^\.\/') && (l:fname !~ '^\* \.\/')
199         return
200     endif
201     if l:fname =~ "'"
202         echohl WarningMsg | echo "***error*** (DebBrowseSelect) filename cannot contain quote character (" . l:fname . ")"
203         return
204     endif
205
206     " do nothing on directories
207     " TODO: find a way to detect symlinks to directories, to be able not to
208     " open them
209     if (l:fname =~ '\/$')
210         return
211     endif
212
213     " need to get it now since a new window will open
214     let l:curfile= expand("%")
215    
216     " open new window
217     new
218     wincmd _
219
220     call deb#read(l:curfile, l:fname)
221
222     if v:shell_error != 0
223         echohl WarningMsg | echo "***warning*** (DebBrowseSelect) error when reading " . l:fname
224         return
225     endif
226
227     filetype detect
228
229     " zipped files, are unziped in deb#read, but filetype may not
230     " automatically work.
231     if l:fname =~ "\.\/usr\/share\/man\/.*\.gz$"
232         set filetype=man
233     elseif l:fname =~ "\.\/usr\/share\/doc\/.*\/changelog.Debian.gz$"
234         set filetype=debchangelog
235     endif
236
237 endfun
238
239 " return control file name for debian package. This can be either control.tar,
240 " control.tar.gz or control.tar.xz
241 fun s:controlFileName(deb)
242     return s:findFileName(a:deb, ["control.tar.gz", "control.tar.xz", "control.tar"])
243 endfun
244
245 " return data file name for debian package. This can be either data.tar.gz,
246 " data.tar.bz2 or data.tar.lzma
247 fun s:dataFileName(deb)
248     return s:findFileName(a:deb, ["data.tar.gz", "data.tar.bz2", "data.tar.lzma", "data.tar.xz", "data.tar"])
249 endfun
250
251 " return string which is the base command for uncompressing the given
252 " archive member.  Further tar options can be appended to the string to view
253 " or extract the contents.
254 fun s:uncmp(member)
255     return {
256         \ 'gz': 'tar z',
257         \ 'bz2': 'tar j',
258         \ 'lzma': 'lzma -d | tar ',
259         \ 'xz': 'tar J',
260         \ 'tar': 'tar ',
261         \}[fnamemodify(a:member, ':e')]
262 endfun
263
264 " return a file name for debian package. This will be the first match from
265 " the files passed as arguments.
266 fun s:findFileName(deb, list)
267     for fn in a:list
268         " [0:-2] is to remove trailing null character from command output
269         if (system("ar t " . "'" . a:deb . "'" . " " . fn))[0:-2] == fn
270             return fn
271         endif
272     endfor
273     return "" " cannot find file in this debian archive
274 endfun
275
276 fun s:QuoteFile(file)
277     " we need to escape %, #, <, and >
278     " see :help cmdline-specialk
279     return "'" .  substitute(a:file, '\([%#<>]\)', '\\\1', 'g') . "'"
280 endfun
281
282 " return 1 if cmd exists
283 " display error message and return 0 otherwise
284 fun s:hascmd(cmd)
285     if executable(a:cmd)
286         return 1
287     else
288         echohl Error | echo "***error*** " . a:cmd . " not available on your system"
289         return 0
290     else
291 endfu
292