aboutsummaryrefslogtreecommitdiff
path: root/runtime/autoload/man.vim
blob: 49663d7e5adb3272373263b288dfb605e9efb2e3 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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

function man#get_page(...) abort
  let invoked_from_man = (&filetype ==# 'man')

  if a:0 == 0
    echoerr 'argument required'
    return
  elseif a:0 > 2
    echoerr 'too many arguments'
    return
  elseif a:0 == 2
    let [page, sect] = [a:2, 0 + a:1]
  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(sect, page)

  if 0 + sect > 0 && s:find_page(sect, page) == 0
    let sect = ''
  endif

  if s:find_page(sect, page) == 0
    echo 'No 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

  let editcmd = 'edit'
  " Use an existing 'man' window, else 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'
      let editcmd = 'tabnew'
    endif
  endif

  silent exec editcmd.' man://'.page.(empty(sect)?'':'('.sect.')')

  setlocal modifiable
  silent keepjumps norm! 1G"_dG
  if empty($MANWIDTH)
    let $MANWIDTH = winwidth(0)
  endif
  silent exec 'r!/usr/bin/man '.s:cmd(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 nomodified
  setlocal filetype=man

  if invoked_from_man || editcmd ==# 'tabnew'
    call s:set_window_local_options()
  endif
endfunction

function s:set_window_local_options() abort
  setlocal colorcolumn=0 foldcolumn=0 nonumber
  setlocal nolist norelativenumber nofoldenable
endfunction

function man#pop_page() abort
  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

" Expects a string like 'access' or 'access(2)'.
function s:parse_page_and_section(sect, str) abort
  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 = a:sect
    endif
  catch
    let &l:iskeyword = save_isk
    echoerr 'man.vim: failed to parse: "'.a:str.'"'
  endtry

  return [page, sect]
endfunction

function s:cmd(sect, page) abort
  if 0 + a:sect > 0
    return s:man_sect_arg.' '.a:sect.' '.a:page
  endif
  return a:page
endfunction

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