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
6 " Inspired by autoload/tar.vim by Charles E Campbell
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
13 if &cp || exists("g:loaded_deb") || v:version < 700
16 let g:loaded_deb= "v1.4"
18 fun! deb#read(debfile, member)
20 " checks if ar and tar are installed
21 if !s:hascmd("ar") || !s:hascmd("tar")
25 let l:target = a:member
27 let l:archmember = s:dataFileName(a:debfile) " default archive member to extract
29 echohl WarningMsg | echo "***error*** (deb#read) no valid data member found in debian archive"
32 let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
33 if l:unpcmp =~# '^lzma' && !s:hascmd("lzma")
38 if a:member =~ '^\* ' " information control file
39 let l:target = substitute(l:target, "^\* ", "", "")
40 let l:archmember = s:controlFileName(a:debfile)
42 echohl WarningMsg | echo "***error*** (deb#read) no valid control member found in debian archive"
45 let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
47 elseif a:member =~ ' -> ' " symbolic link
48 let l:target = split(a:member,' -> ')[0]
49 let l:linkname = split(a:member,' -> ')[1]
51 if l:linkname =~ "^\/" " direct symlink: path is already absolute
52 let l:target = ".".l:linkname
55 " transform relative path to absolute path
57 " first, get basename for target
58 let l:target = substitute(l:target, "\/[^/]*$", "", "")
60 " while it begins with ../
61 while l:linkname =~ "^\.\.\/"
63 " removes one level of ../ in linkname
64 let l:linkname = substitute(l:linkname, "^\.\.\/", "", "")
66 " go one directory up in target
67 let l:target = substitute(l:target, "\/[^/]*$", "", "")
70 let l:target = l:target."/".l:linkname
74 " we may preprocess some files (such as man pages, or changelogs)
80 if l:target =~ "\.\/usr\/share\/man\/.*\.gz$"
82 " try to fail gracefully if a command is not available
85 elseif !s:hascmd("nroff")
86 let l:preproccmd = "| gzip -cd"
87 elseif !s:hascmd("col")
88 let l:preproccmd = "| gzip -cd | nroff -mandoc"
90 let l:preproccmd = "| gzip -cd | nroff -mandoc | col -b"
94 " unzip other .gz files
96 elseif l:target =~ '.*\.gz$'
100 let l:preproccmd = "| gzip -cd"
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
110 exe "file deb:".l:target
114 setlocal nomodifiable nomodified readonly
118 fun! deb#browse(file)
120 " checks if necessary utils are installed
121 if !s:hascmd("dpkg") || !s:hascmd("ar") || !s:hascmd("tar")
125 " checks if file is readable
126 if !filereadable(a:file)
130 echohl WarningMsg | echo "***error*** (deb#Browse) filename cannot contain quote character (" . a:file . ")"
134 let keepmagic = &magic
137 " set filetype to "deb"
140 setlocal modifiable noreadonly
143 exe "$put ='".'\"'." deb.vim version ".g:loaded_deb."'"
144 exe "$put ='".'\"'." Browsing debian package ".a:file."'"
148 "exe "silent read! dpkg -I ".a:file
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"
159 let l:unpcmp = s:uncmp(l:ctrlmember)
160 if l:unpcmp =~# '^lzma' && !s:hascmd('lzma')
163 exe "silent read! ar p " . s:QuoteFile(a:file) . " " . l:ctrlmember . ' | ' . l:unpcmp . 't'
168 let l:listpos = line(".")
169 exe "silent read! dpkg -c ". s:QuoteFile(a:file)
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/^/\* /'
178 exe "silent " . l:listpos . ',$s/^.*\s\(\.\/\(\S\|\).*\)$/\1/'
180 if v:shell_error != 0
181 echohl WarningMsg | echo "***warning*** (deb#Browse) error when listing content of " . a:file
182 let &magic = keepmagic
188 setlocal nomodifiable readonly
189 noremap <silent> <buffer> <cr> :call <SID>DebBrowseSelect()<cr>
190 let &magic = keepmagic
194 fun! s:DebBrowseSelect()
195 let l:fname= getline(".")
198 if (l:fname !~ '^\.\/') && (l:fname !~ '^\* \.\/')
202 echohl WarningMsg | echo "***error*** (DebBrowseSelect) filename cannot contain quote character (" . l:fname . ")"
206 " do nothing on directories
207 " TODO: find a way to detect symlinks to directories, to be able not to
209 if (l:fname =~ '\/$')
213 " need to get it now since a new window will open
214 let l:curfile= expand("%")
220 call deb#read(l:curfile, l:fname)
222 if v:shell_error != 0
223 echohl WarningMsg | echo "***warning*** (DebBrowseSelect) error when reading " . l:fname
229 " zipped files, are unziped in deb#read, but filetype may not
230 " automatically work.
231 if l:fname =~ "\.\/usr\/share\/man\/.*\.gz$"
233 elseif l:fname =~ "\.\/usr\/share\/doc\/.*\/changelog.Debian.gz$"
234 set filetype=debchangelog
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"])
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"])
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.
258 \ 'lzma': 'lzma -d | tar ',
261 \}[fnamemodify(a:member, ':e')]
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)
268 " [0:-2] is to remove trailing null character from command output
269 if (system("ar t " . "'" . a:deb . "'" . " " . fn))[0:-2] == fn
273 return "" " cannot find file in this debian archive
276 fun s:QuoteFile(file)
277 " we need to escape %, #, <, and >
278 " see :help cmdline-specialk
279 return "'" . substitute(a:file, '\([%#<>]\)', '\\\1', 'g') . "'"
282 " return 1 if cmd exists
283 " display error message and return 0 otherwise
288 echohl Error | echo "***error*** " . a:cmd . " not available on your system"