diff options
Diffstat (limited to 'runtime/autoload/man.vim')
-rw-r--r-- | runtime/autoload/man.vim | 133 |
1 files changed, 97 insertions, 36 deletions
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim index 251e6eee41..dd71ede680 100644 --- a/runtime/autoload/man.vim +++ b/runtime/autoload/man.vim @@ -1,16 +1,31 @@ " Maintainer: Anmol Sethi <anmol@aubble.com> -let s:man_find_arg = "-w" +let s:find_arg = '-w' +let s:localfile_arg = v:true " Always use -l if possible. #6683 +let s:section_arg = '-s' -" TODO(nhooyr) Completion may work on SunOS; I'm not sure if `man -l` displays -" the list of searched directories. -try - if !has('win32') && $OSTYPE !~? 'cygwin\|linux' && system('uname -s') =~? 'SunOS' && system('uname -r') =~# '^5' - let s:man_find_arg = '-l' +function! s:init_section_flag() + call system(['env', 'MANPAGER=cat', 'man', s:section_arg, '1', 'man']) + if v:shell_error + let s:section_arg = '-S' endif -catch /E145:/ - " Ignore the error in restricted mode -endtry +endfunction + +function! s:init() abort + call s:init_section_flag() + " TODO(nhooyr): Does `man -l` on SunOS list searched directories? + try + if !has('win32') && $OSTYPE !~? 'cygwin\|linux' && system('uname -s') =~? 'SunOS' && system('uname -r') =~# '^5' + let s:find_arg = '-l' + endif + " Check for -l support. + call s:get_page(s:get_path('', 'man')[0:-2]) + catch /E145:/ + " Ignore the error in restricted mode + catch /command error .*/ + let s:localfile_arg = v:false + endtry +endfunction function! man#open_page(count, count1, mods, ...) abort if a:0 > 2 @@ -39,7 +54,6 @@ function! man#open_page(count, count1, mods, ...) abort let sect = string(a:count) endif let [sect, name, path] = s:verify_exists(sect, name) - let page = s:get_page(path) catch call s:error(v:exception) return @@ -47,11 +61,29 @@ function! man#open_page(count, count1, mods, ...) abort call s:push_tag() let bufname = 'man://'.name.(empty(sect)?'':'('.sect.')') - if a:mods !~# 'tab' && s:find_man() - noautocmd execute 'silent edit' fnameescape(bufname) - else - noautocmd execute 'silent' a:mods 'split' fnameescape(bufname) - endif + + try + set eventignore+=BufReadCmd + if a:mods !~# 'tab' && s:find_man() + execute 'silent edit' fnameescape(bufname) + else + execute 'silent' a:mods 'split' fnameescape(bufname) + endif + finally + set eventignore-=BufReadCmd + endtry + + try + let page = s:get_page(path) + catch + if a:mods =~# 'tab' || !s:find_man() + " a new window was opened + close + endif + call s:error(v:exception) + return + endtry + let b:man_sect = sect call s:put_page(page) endfunction @@ -59,21 +91,20 @@ endfunction function! man#read_page(ref) abort try let [sect, name] = man#extract_sect_and_name_ref(a:ref) - let [b:man_sect, name, path] = s:verify_exists(sect, name) + let [sect, name, path] = s:verify_exists(sect, name) let page = s:get_page(path) catch - " call to s:error() is unnecessary + call s:error(v:exception) return endtry + let b:man_sect = sect call s:put_page(page) endfunction " Handler for s:system() function. function! s:system_handler(jobid, data, event) dict abort - if a:event == 'stdout' - let self.stdout .= join(a:data, "\n") - elseif a:event == 'stderr' - let self.stderr .= join(a:data, "\n") + if a:event is# 'stdout' || a:event is# 'stderr' + let self[a:event] .= join(a:data, "\n") else let self.exit_code = a:data endif @@ -100,7 +131,7 @@ function! s:system(cmd, ...) abort try call jobstop(jobid) throw printf('command timed out: %s', join(a:cmd)) - catch /^Vim\%((\a\+)\)\=:E900/ + catch /^Vim(call):E900:/ endtry elseif res[0] == -2 throw printf('command interrupted: %s', join(a:cmd)) @@ -117,7 +148,8 @@ function! s:get_page(path) abort let manwidth = empty($MANWIDTH) ? winwidth(0) : $MANWIDTH " Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db). " http://comments.gmane.org/gmane.editors.vim.devel/29085 - return s:system(['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'man', a:path]) + let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'man'] + return s:system(cmd + (s:localfile_arg ? ['-l', a:path] : [a:path])) endfunction function! s:put_page(page) abort @@ -125,14 +157,39 @@ function! s:put_page(page) abort setlocal noreadonly silent keepjumps %delete _ silent put =a:page - " Remove all backspaced characters. - execute 'silent keeppatterns keepjumps %substitute,.\b,,e'.(&gdefault?'':'g') + " Remove all backspaced/escape characters. + execute 'silent keeppatterns keepjumps %substitute,.\b\|\e\[\d\+m,,e'.(&gdefault?'':'g') while getline(1) =~# '^\s*$' silent keepjumps 1delete _ endwhile setlocal filetype=man endfunction +function! man#show_toc() abort + let bufname = bufname('%') + let info = getloclist(0, {'winid': 1}) + if !empty(info) && getwinvar(info.winid, 'qf_toc') ==# bufname + lopen + return + endif + + let toc = [] + let lnum = 2 + let last_line = line('$') - 1 + while lnum && lnum < last_line + let text = getline(lnum) + if text =~# '^\%( \{3\}\)\=\S.*$' + call add(toc, {'bufnr': bufnr('%'), 'lnum': lnum, 'text': text}) + endif + let lnum = nextnonblank(lnum + 1) + endwhile + + call setloclist(0, toc, ' ') + call setloclist(0, [], 'a', {'title': 'Man TOC'}) + lopen + let w:qf_toc = bufname +endfunction + " attempt to extract the name and sect out of 'name(sect)' " otherwise just return the largest string of valid characters in ref function! man#extract_sect_and_name_ref(ref) abort @@ -156,24 +213,26 @@ endfunction function! s:get_path(sect, name) abort if empty(a:sect) - return s:system(['man', s:man_find_arg, a:name]) + return s:system(['man', s:find_arg, a:name]) endif " '-s' flag handles: " - tokens like 'printf(echo)' " - sections starting with '-' " - 3pcap section (found on macOS) " - commas between sections (for section priority) - return s:system(['man', s:man_find_arg, '-s', a:sect, a:name]) + return s:system(['man', s:find_arg, s:section_arg, a:sect, a:name]) endfunction function! s:verify_exists(sect, name) abort - let path = s:get_path(a:sect, a:name) - if path !~# '^\/' - let path = s:get_path(get(b:, 'man_default_sects', ''), a:name) - if path !~# '^\/' + try + let path = s:get_path(a:sect, a:name) + catch /^command error (/ + try + let path = s:get_path(get(b:, 'man_default_sects', ''), a:name) + catch /^command error (/ let path = s:get_path('', a:name) - endif - endif + endtry + endtry " We need to extract the section from the path because sometimes " the actual section of the manpage is more specific than the section " we provided to `man`. Try ':Man 3 App::CLI'. @@ -286,7 +345,7 @@ endfunction function! s:complete(sect, psect, name) abort try - let mandirs = join(split(s:system(['man', s:man_find_arg]), ':\|\n'), ',') + let mandirs = join(split(s:system(['man', s:find_arg]), ':\|\n'), ',') catch call s:error(v:exception) return @@ -311,8 +370,8 @@ function! s:format_candidate(path, psect) abort endfunction function! man#init_pager() abort - " Remove all backspaced characters. - execute 'silent keeppatterns keepjumps %substitute,.\b,,e'.(&gdefault?'':'g') + " Remove all backspaced/escape characters. + execute 'silent keeppatterns keepjumps %substitute,.\b\|\e\[\d\+m,,e'.(&gdefault?'':'g') if getline(1) =~# '^\s*$' silent keepjumps 1delete _ else @@ -328,3 +387,5 @@ function! man#init_pager() abort endtry execute 'silent file man://'.fnameescape(ref) endfunction + +call s:init() |