aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload/man.vim
blob: 79977641ddd66100eceafdcd82bf4b08d4820815 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
let s:man_tag_depth = 0
let s:man_sect_arg = ''
let s:man_find_arg = '-w'

try
  if !has('win32') && $OSTYPE !~? 'cygwin\|linux' && system('uname -s') =~? 'SunOS' && system('uname -r') =~? '^5'
    let s:man_sect_arg = '-s'
    let s:man_find_arg = '-l'
  endif
catch /E145:/
  " Ignore the error in restricted mode
endtry

" Expects a string like 'access' or 'access(2)'.
function s:parse_page_and_section(str)
  try
    let save_isk = &iskeyword
    setlocal iskeyword-=(,)
    let page = substitute(a:str, '(*\(\k\+\).*', '\1', '')
    let sect = substitute(a:str, '\(\k\+\)(\([^()]*\)).*', '\2', '')
    if sect == page || -1 == match(sect, '^[0-9 ]\+$')
      let sect = ''
    endif
  catch
    let &l:iskeyword = save_isk
    echoerr 'man.vim: failed to parse: "'.a:str.'"'
  endtry

  return [page, sect]
endfunction

function man#get_page(...)
  if a:0 == 0
    echoerr 'argument required'
    return
  elseif a:0 > 2
    echoerr 'too many arguments'
    return
  elseif a:0 == 2
    let [sect, page] = [a:1, a:2]
  elseif type(1) == type(a:1)
    let [page, sect] = ['<cword>', a:1]
  else
    let [page, sect] = [a:1, '']
  endif

  if page == '<cword>'
    let page = expand('<cword>')
  endif

  let [page, sect] = s:parse_page_and_section(page)

  if sect !=# '' && s:FindPage(sect, page) == 0
    let sect = ''
  endif

  if s:FindPage(sect, page) == 0
    echo "\nNo manual entry for '".page."'"
    return
  endif

  exec 'let s:man_tag_buf_'.s:man_tag_depth.' = '.bufnr('%')
  exec 'let s:man_tag_lin_'.s:man_tag_depth.' = '.line('.')
  exec 'let s:man_tag_col_'.s:man_tag_depth.' = '.col('.')
  let s:man_tag_depth = s:man_tag_depth + 1

  " Use an existing "man" window if it exists, otherwise open a new one.
  if &filetype != 'man'
    let thiswin = winnr()
    wincmd b
    if winnr() > 1
      exe "norm! " . thiswin . "\<C-W>w"
      while 1
        if &filetype == 'man'
          break
        endif
        wincmd w
        if thiswin == winnr()
          break
        endif
      endwhile
    endif
    if &filetype != 'man'
      tabnew
      " window-local options
      setlocal foldcolumn=0 nonumber nolist norelativenumber nofoldenable
    endif
  endif
  silent exec 'edit man://'.page.(empty(sect)?'':'('.sect.')')

  setlocal modifiable
  silent keepjumps norm! 1G"_dG
  let $MANWIDTH = winwidth(0)
  silent exec 'r!/usr/bin/man '.s:GetCmdArg(sect, page).' | col -b'
  " Remove blank lines from top and bottom.
  while getline(1) =~ '^\s*$'
    silent keepjumps norm! gg"_dd
  endwhile
  while getline('$') =~ '^\s*$'
    silent keepjumps norm! G"_dd
  endwhile
  setlocal filetype=man
endfunction

function man#pop_page()
  if s:man_tag_depth > 0
    let s:man_tag_depth = s:man_tag_depth - 1
    exec "let s:man_tag_buf=s:man_tag_buf_".s:man_tag_depth
    exec "let s:man_tag_lin=s:man_tag_lin_".s:man_tag_depth
    exec "let s:man_tag_col=s:man_tag_col_".s:man_tag_depth
    exec s:man_tag_buf."b"
    exec s:man_tag_lin
    exec "norm! ".s:man_tag_col."|"
    exec "unlet s:man_tag_buf_".s:man_tag_depth
    exec "unlet s:man_tag_lin_".s:man_tag_depth
    exec "unlet s:man_tag_col_".s:man_tag_depth
    unlet s:man_tag_buf s:man_tag_lin s:man_tag_col
  endif
endfunction

function s:GetCmdArg(sect, page)
  if a:sect == ''
    return a:page
  endif
  return s:man_sect_arg.' '.a:sect.' '.a:page
endfunction

function s:FindPage(sect, page)
  let where = system('/usr/bin/man '.s:man_find_arg.' '.s:GetCmdArg(a:sect, a:page))
  if where !~ "^/"
    if matchstr(where, " [^ ]*$") !~ "^ /"
      return 0
    endif
  endif
  return 1
endfunction