From a67f338939851f184038f74bc35fc55eacb15e1d Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Wed, 5 Sep 2007 13:08:05 +0000 Subject: [PATCH] Use vim for manpages and infopages. git-svn-id: https://svn.cambridge.iain.cx/profile/trunk@70 6be0d1a5-5cfe-0310-89b6-964be062b18b --- .profile.d/man.bashrc | 24 +++ .vim/plugin/info.vim | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 .profile.d/man.bashrc create mode 100644 .vim/plugin/info.vim diff --git a/.profile.d/man.bashrc b/.profile.d/man.bashrc new file mode 100644 index 0000000..229a5f2 --- /dev/null +++ b/.profile.d/man.bashrc @@ -0,0 +1,24 @@ +# $Id$ +# +# Use vim for manpages and infopages. +# Requires vim 5+ and info.vim plugin. +# + +vimmajor=$(vim --help 2>&1 | head -n 1 | sed 's/^VIM[^0-9]*\([0-9]*\)\..*/\1/') + +function vman() { + vim -c "runtime ftplugin/man.vim" -c "Man ${1-man}" \ + -c "set nolist noruler ls=0" +"wincmd o" +} + +function vinfo() { + vim -c "Info ${1-info}" \ + -c "set nolist noruler ls=0" +"wincmd o" +} + +if [ ! -z "$vimmajor" -a $vimmajor -gt 4 ]; then + alias man=vman + alias info=vinfo +fi + +unset vimmajor diff --git a/.vim/plugin/info.vim b/.vim/plugin/info.vim new file mode 100644 index 0000000..f78f0d9 --- /dev/null +++ b/.vim/plugin/info.vim @@ -0,0 +1,396 @@ +" GNU Info browser +" +" Copyright (c) 2001, 2002 Slavik Gorbanyov +" All rights reserved. +" +" Redistribution and use, with or without modification, are permitted +" provided that the following conditions are met: +" +" 1. Redistributions must retain the above copyright notice, this list +" of conditions and the following disclaimer. +" +" 2. The name of the author may not be used to endorse or promote +" products derived from this script without specific prior written +" permission. +" +" THIS SCRIPT IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. +" +" $Id: info.vim,v 1.7 2002/11/30 21:59:05 rnd Exp $ + +let s:infoCmd = 'info --output=-' +if has('win32') + let s:infoBufferName = '-Info- ' +else + let s:infoBufferName = 'Info: ' +endif +let s:dirPattern = '^\* [^:]*: \(([^)]*)\)' +let s:menuPattern = '^\* \([^:]*\)::' +let s:notePattern = '\*[Nn]ote\%(\s\|$\)' +let s:indexPattern = '^\* [^:]*:\s*\([^.]*\)\.$' +let s:indexPatternHL = '^\* [^:]*:\s\+[^(]' + +command! -nargs=* Info call s:Info() + +fun! s:Info(...) + let file = "(dir)" + let node = "Top" + if a:0 + let file = a:1 + if file[0] != '(' + let file = '('.file.')' + endif + if a:0 > 1 + let node = a:2 + let arg_idx = 3 + while arg_idx <= a:0 + exe 'let node = node ." ". a:'.arg_idx + let arg_idx = arg_idx + 1 + endwhile + endif + endif + + call s:InfoExec(file, node) + if winheight(2) != -1 + exe 'resize' &helpheight + endif +endfun + +fun! s:InfoExec(file, node, ...) + " a:0 != 0 means last node requested + if a:0 + let line = a:1 + else + let line = 1 + endif + if a:0 == 0 && exists('b:info_file') + let last_file = b:info_file + let last_node = b:info_node + let last_line = line('.') + endif + let bufname = s:infoBufferName.a:file.a:node + if buflisted(bufname) && a:0 < 2 + if &ft == 'info' + silent exe 'b!' escape(bufname, '\ ') + else + silent exe 'sb' escape(bufname, '\ ') + endif + else + if &ft == 'info' + let command = 'e!' + else + let command = 'new' + endif + silent! exe command "+exe'setlocal''modifiable''noswapfile''buftype=nofile''bufhidden=delete'" escape(bufname, '\ ') + setf info + + let cmd = s:infoCmd." '".a:file.a:node."' 2>/dev/null" + + " handle shell redirection portable + if $OS !~? 'Windows' + let save_shell = &shell + set shell=/bin/sh + endif + let save_shellredir = &shellredir + set shellredir=> + exe "silent 0r!".cmd + let &shellredir = save_shellredir + if $OS !~? 'Windows' + let &shell = save_shell + endif + + call s:InfoBufferInit() + endif + let b:info_file = a:file + let b:info_node = a:node + if exists('last_file') + let b:info_last_file = last_file + let b:info_last_node = last_node + let b:info_last_line = last_line + endif + setlocal nomodifiable + if s:InfoFirstLine() + exe line + else + echohl ErrorMsg | echo 'Info failed (node not found)' | echohl None + endif +endfun + +fun! s:InfoBufferInit() + + " remove all insert mode abbreviations + iabc + + if has("syntax") && exists("g:syntax_on") + syn case match + syn match infoMenuTitle /^\* Menu:/hs=s+2,he=e-1 + syn match infoTitle /^[A-Z][0-9A-Za-z `',/&]\{,43}\([a-z']\|[A-Z]\{2}\)$/ + syn match infoTitle /^[-=*]\{,45}$/ + syn match infoString /`[^`]*'/ + exec 'syn match infoLink /'.s:menuPattern.'/hs=s+2' + exec 'syn match infoLink /'.s:dirPattern.'/hs=s+2' + exec 'syn match infoLink /'.s:indexPatternHL.'/hs=s+2,he=e-2' + syn region infoLink start=/\*[Nn]ote/ end=/\(::\|[.,]\)/ + + if !exists("g:did_info_syntax_inits") + let g:did_info_syntax_inits = 1 + hi def link infoMenuTitle Title + hi def link infoTitle Comment + hi def link infoLink Directory + hi def link infoString String + endif + endif + + " FIXME: is move cursor left + noremap h :call Help() + noremap :call FollowLink() + noremap :call FollowLink() + " FIXME: is move cursor right +" noremap l :call LastNode() + noremap ; :call LastNode() + noremap :call LastNode() + noremap / + " FIXME: is go to next match +" noremap n :call NextNode() + noremap . :call NextNode() + noremap p :call PrevNode() + noremap > :call NextNode() + noremap < :call PrevNode() + noremap u :call UpNode() + noremap t :call TopNode() + noremap d :call DirNode() + noremap s :call Search() + noremap :call NextRef() + nnoremap q :q! + noremap + noremap + + runtime info-local.vim +endfun + +fun! s:Help() + echohl Title + echo 'Info browser keys' + echo '-----------------' + echohl None + echo ' Scroll forward (page down).' + echo ' Scroll backward (page up).' + echo ' Move cursor to next hyperlink within this node.' + echo ', Follow hyperlink under cursor.' + echo ';, Return to last seen node.' + echo '.,> Move to the "next" node of this node.' + echo 'p,< Move to the "previous" node of this node.' + echo 'u Move "up" from this node.' + echo 'd Move to "directory" node.' + echo 't Move to the Top node.' + echo ' Search forward within current node only.' + echo 's Search forward through all nodes for a specified string.' + echo 'q Quit browser.' + echohl SpecialKey + echo 'Note: "," means "or"' + echohl None +endfun + +fun! s:InfoFirstLine() + let b:info_next_node = '' + let b:info_prev_node = '' + let b:info_up_node = '' + let line = getline(1) + let node_offset = matchend(line, '^File: [^, ]*') + if node_offset == -1 + return 0 + endif + let file = strpart(line, 6, node_offset-6) + if file == 'dir' + return 1 + endif +" let file = substitute(file, '\(.*\)\.info\(\.gz\)\=', '\1', '') + let b:info_next_node = s:GetSubmatch( line, '\s\+Next: \([^,]*\),') + let b:info_prev_node = s:GetSubmatch( line, '\s\+Prev: \([^,]*\),') + let b:info_up_node = s:GetSubmatch( line, '\s\+Up: \(.*\)') + return 1 +endfun + +fun! s:GetSubmatch(string, pattern) + let matched = matchstr(a:string, a:pattern) + if matched != '' + let matched = substitute(matched, a:pattern, '\1', '') + endif + return matched +endfun + +fun! s:NextNode() + if exists('b:info_next_node') && b:info_next_node != '' + \ && match(b:info_next_node, '(.*)') == -1 + call s:InfoExec(b:info_file, b:info_next_node) + return 1 + else + echohl ErrorMsg | echo 'This is the last node' | echohl None + endif +endfun + +fun! s:TopNode() + if b:info_node == 'Top' + if b:info_file == '(dir)' + echohl ErrorMsg | echo 'Already at top node' | echohl None + return + endif + let file = '(dir)' + let node = b:info_node + else + let file = b:info_file + let node = 'Top' + endif + call s:InfoExec(file, node) +endfun + +fun! s:DirNode() + call s:InfoExec('(dir)', 'Top') +endfun + +fun! s:LastNode() + if !exists('b:info_last_node') + echohl ErrorMsg | echo 'No last node' | echohl None + return + endif + call s:InfoExec(b:info_last_file, b:info_last_node, b:info_last_line) +endfun + +fun! s:FollowLink() + let current_line = getline('.') + let link = matchstr(current_line, s:notePattern) + if link == '' + let link = matchstr(current_line, s:dirPattern) + if link == '' + let link = matchstr(current_line, s:menuPattern) + if link == '' + let link = matchstr(current_line, s:indexPattern) + if link == '' + echohl ErrorMsg | echo 'No link under cursor' | echohl None + return + endif + let successPattern = s:indexPattern + else + let successPattern = s:menuPattern + endif + let file = b:info_file + let node = substitute(link, successPattern, '\1', '') + else + let successPattern = s:dirPattern + let file = substitute(link, successPattern, '\1', '') + let node = 'Top' + endif + else + " we got a `*note' link. + let successPattern = s:notePattern + let current_line = current_line.' '.getline(line('.') + 1) + + if exists('g:info_debug') + echo 'current_line:' current_line + endif + + let link_pattern = '\*[Nn]ote [^:.]\+: \([^.,]\+\)\%([,.]\|$\)' + let link = matchstr(current_line, link_pattern) + if link == '' + let link_pattern = '\*[Nn]ote \([^:]\+\)\%(::\)' + let link = matchstr(current_line, link_pattern) + if link == '' + echohl ErrorMsg | echo 'No link under cursor' | echohl None + return + endif + endif + let node = substitute(link, link_pattern, '\1', '') + let successPattern = link_pattern + + let link_pattern = '^\(([^)]*)\)\=\s*\(.*\)' + let link = matchstr(node, link_pattern) + let file = substitute(link, link_pattern, '\1', '') + let node = substitute(link, link_pattern, '\2', '') + if file == '' + let file = b:info_file + endif + if node == '' + let node = 'Top' + endif + endif + let link_start_pos = match(current_line, successPattern) + let link_end_pos = matchend(current_line, successPattern) + let cursor_pos = col('.') + if cursor_pos <= link_start_pos || cursor_pos > link_end_pos + echohl ErrorMsg | echo 'No link under cursor' | echohl None + return + endif + if exists('g:info_debug') + echo 'Link:' strpart(current_line, link_start_pos, link_end_pos - link_start_pos) + echo 'File:' file 'Node:' node + endif + call s:InfoExec(file, node) +endfun + +fun! s:NextRef() + let link_pos = search('\('.s:dirPattern.'\|'.s:menuPattern.'\|'.s:notePattern.'\|'.s:indexPatternHL.'\)', 'w') + if link_pos == 0 + echohl ErrorMsg | echo 'No hyperlinks' | echohl None + else + echo + endif +endfun + +fun! s:PrevNode() + if exists('b:info_prev_node') && b:info_prev_node != '' + \ && match(b:info_prev_node, '(.*)') == -1 + call s:InfoExec(b:info_file, b:info_prev_node) + return 1 + else + echohl ErrorMsg | echo 'This is the first node' | echohl None + endif +endfun + +fun! s:UpNode() + if exists('b:info_up_node') && b:info_up_node != '' + \ && match(b:info_up_node, '(.*)') == -1 + call s:InfoExec(b:info_file, b:info_up_node) + return 1 + else + echohl ErrorMsg | echo 'This is the top node' | echohl None + endif +endfun + +" FIXME: there is no way to correctly abort searching. +" messes up the command window and stops at empty buffer. +fun! s:Search() + if !exists('s:info_search_string') + let s:info_search_string = '' + endif + let new_search = input('Search all nodes: ', s:info_search_string) + if new_search == '' + return + endif + let s:info_search_string = new_search + let start_file = b:info_file + let start_node = b:info_node + let start_line = line('.') + while search(s:info_search_string, 'W') == 0 + if !exists('b:info_next_node') || b:info_next_node == '' + \ || match(b:info_next_node, '(.*)') != -1 + silent! exe 'bwipe' escape(s:infoBufferName.start_file.start_node, '\ ') + silent! call s:InfoExec(start_file, start_node, start_line, 'force') + echohl ErrorMsg | echo "\rSearch pattern not found" | echohl None + return + endif + echo "\rSearching ... ".b:info_file b:info_next_node + let file = b:info_file + let node = b:info_next_node + silent bwipe + silent call s:InfoExec(file, node, 2) + endwhile +endfun -- 2.7.4