blob: 5b8b4456db1459b701adfd87f10ab30f95bf390a [file] [log] [blame]
Bram Moolenaard799daa2022-06-20 11:17:32 +01001" Vim filetype plugin autoload file
2" Language: man
3" Maintainer: Jason Franklin <vim@justemail.net>
4" Maintainer: SungHyun Nam <goweol@gmail.com>
5" Autoload Split: Bram Moolenaar
goweol6e5ab2b2023-08-18 06:12:42 +09006" Last Change: 2023 Jun 28
Bram Moolenaard799daa2022-06-20 11:17:32 +01007
8let s:cpo_save = &cpo
9set cpo-=C
10
11let s:man_tag_depth = 0
12
13let s:man_sect_arg = ""
14let s:man_find_arg = "-w"
15try
16 if !has("win32") && $OSTYPE !~ 'cygwin\|linux' && system('uname -s') =~ "SunOS" && system('uname -r') =~ "^5"
17 let s:man_sect_arg = "-s"
18 let s:man_find_arg = "-l"
19 endif
20catch /E145:/
21 " Ignore the error in restricted mode
22endtry
23
goweol8cfe52e2023-08-18 06:13:29 +090024func s:ParseIntoPageAndSection()
25 " Accommodate a reference that terminates in a hyphen.
26 "
27 " See init_charset_table() at
28 " https://git.savannah.gnu.org/cgit/groff.git/tree/src/roff/troff/input.cpp?h=1.22.4#n6794
29 "
30 " See can_break_after() at
31 " https://git.savannah.gnu.org/cgit/groff.git/tree/src/roff/troff/charinfo.h?h=1.22.4#n140
32 "
33 " Assumptions and limitations:
34 " 1) Manual-page references (in consequence of command-related filenames)
35 " do not contain non-ASCII HYPHENs (0x2010), any terminating HYPHEN
36 " must have been introduced to mark division of a word at the end of
37 " a line and can be discarded; whereas similar references may contain
38 " ASCII HYPHEN-MINUSes (0x002d) and any terminating HYPHEN-MINUS forms
39 " a compound word in addition to marking word division.
40 " 2) Well-formed manual-page references always have a section suffix, e.g.
41 " "git-commit(1)", therefore suspended hyphenated compounds are not
42 " determined, e.g. [V] (With cursor at _git-merge-_ below...)
43 " ".................... git-merge- and git-merge-base. (See git-cherry-
44 " pick(1) and git-cherry(1).)" (... look up "git-merge-pick(1)".)
45 "
46 " Note that EM DASH (0x2014), a third stooge from init_charset_table(),
47 " neither connects nor divides parts of a word.
48 let str = expand("<cWORD>")
49
50 if str =~ '\%u2010$' " HYPHEN (-1).
51 let str = strpart(str, 0, strridx(str, "\u2010"))
52
53 " Append the leftmost WORD (or an empty string) from the line below.
54 let str .= get(split(get(getbufline(bufnr('%'), line('.') + 1), 0, '')), 0, '')
55 elseif str =~ '-$' " HYPHEN-MINUS.
56 " Append the leftmost WORD (or an empty string) from the line below.
57 let str .= get(split(get(getbufline(bufnr('%'), line('.') + 1), 0, '')), 0, '')
58 endif
59
60 " According to man(1), section name formats vary (MANSECT):
61 " 1 n l 8 3 2 3posix 3pm 3perl 3am 5 4 9 6 7
62 let parts = matchlist(str, '\(\k\+\)(\(\k\+\))')
63 return (len(parts) > 2)
64 \ ? {'page': parts[1], 'section': parts[2]}
65 \ : {'page': matchstr(str, '\k\+'), 'section': ''}
66endfunc
67
Bram Moolenaard799daa2022-06-20 11:17:32 +010068func dist#man#PreGetPage(cnt)
69 if a:cnt == 0
goweol8cfe52e2023-08-18 06:13:29 +090070 let what = s:ParseIntoPageAndSection()
71 let sect = what.section
72 let page = what.page
Bram Moolenaard799daa2022-06-20 11:17:32 +010073 else
goweol8cfe52e2023-08-18 06:13:29 +090074 let what = s:ParseIntoPageAndSection()
Bram Moolenaard799daa2022-06-20 11:17:32 +010075 let sect = a:cnt
goweol8cfe52e2023-08-18 06:13:29 +090076 let page = what.page
Bram Moolenaard799daa2022-06-20 11:17:32 +010077 endif
goweol8cfe52e2023-08-18 06:13:29 +090078
Bram Moolenaard799daa2022-06-20 11:17:32 +010079 call dist#man#GetPage('', sect, page)
80endfunc
81
82func s:GetCmdArg(sect, page)
Bram Moolenaard799daa2022-06-20 11:17:32 +010083 if empty(a:sect)
84 return shellescape(a:page)
85 endif
86
87 return s:man_sect_arg . ' ' . shellescape(a:sect) . ' ' . shellescape(a:page)
88endfunc
89
90func s:FindPage(sect, page)
91 let l:cmd = printf('man %s %s', s:man_find_arg, s:GetCmdArg(a:sect, a:page))
92 call system(l:cmd)
93
94 if v:shell_error
95 return 0
96 endif
97
98 return 1
99endfunc
100
101func dist#man#GetPage(cmdmods, ...)
102 if a:0 >= 2
103 let sect = a:1
104 let page = a:2
105 elseif a:0 >= 1
106 let sect = ""
107 let page = a:1
108 else
109 return
110 endif
111
goweol8cfe52e2023-08-18 06:13:29 +0900112 " To support: nmap K :Man <cWORD><CR>
113 if page ==? '<cword>'
114 let what = s:ParseIntoPageAndSection()
115 let sect = what.section
116 let page = what.page
Bram Moolenaard799daa2022-06-20 11:17:32 +0100117 endif
118
119 if !exists('g:ft_man_no_sect_fallback') || (g:ft_man_no_sect_fallback == 0)
120 if sect != "" && s:FindPage(sect, page) == 0
121 let sect = ""
122 endif
123 endif
124 if s:FindPage(sect, page) == 0
125 let msg = 'man.vim: no manual entry for "' . page . '"'
126 if !empty(sect)
127 let msg .= ' in section ' . sect
128 endif
129 echomsg msg
130 return
131 endif
132 exec "let s:man_tag_buf_".s:man_tag_depth." = ".bufnr("%")
133 exec "let s:man_tag_lin_".s:man_tag_depth." = ".line(".")
134 exec "let s:man_tag_col_".s:man_tag_depth." = ".col(".")
135 let s:man_tag_depth = s:man_tag_depth + 1
136
137 let open_cmd = 'edit'
138
139 " Use an existing "man" window if it exists, otherwise open a new one.
140 if &filetype != "man"
141 let thiswin = winnr()
142 exe "norm! \<C-W>b"
143 if winnr() > 1
144 exe "norm! " . thiswin . "\<C-W>w"
145 while 1
146 if &filetype == "man"
147 break
148 endif
149 exe "norm! \<C-W>w"
150 if thiswin == winnr()
151 break
152 endif
153 endwhile
154 endif
155 if &filetype != "man"
156 if exists("g:ft_man_open_mode")
157 if g:ft_man_open_mode == 'vert'
158 let open_cmd = 'vsplit'
159 elseif g:ft_man_open_mode == 'tab'
160 let open_cmd = 'tabedit'
161 else
162 let open_cmd = 'split'
163 endif
164 else
165 let open_cmd = a:cmdmods . ' split'
166 endif
167 endif
168 endif
169
170 silent execute open_cmd . " $HOME/" . page . '.' . sect . '~'
171
172 " Avoid warning for editing the dummy file twice
173 setl buftype=nofile noswapfile
174
175 setl fdc=0 ma nofen nonu nornu
176 %delete _
177 let unsetwidth = 0
178 if empty($MANWIDTH)
179 let $MANWIDTH = winwidth(0)
180 let unsetwidth = 1
181 endif
182
183 " Ensure Vim is not recursively invoked (man-db does this) when doing ctrl-[
184 " on a man page reference by unsetting MANPAGER.
185 " Some versions of env(1) do not support the '-u' option, and in such case
186 " we set MANPAGER=cat.
187 if !exists('s:env_has_u')
188 call system('env -u x true')
189 let s:env_has_u = (v:shell_error == 0)
190 endif
191 let env_cmd = s:env_has_u ? 'env -u MANPAGER' : 'env MANPAGER=cat'
192 let env_cmd .= ' GROFF_NO_SGR=1'
193 let man_cmd = env_cmd . ' man ' . s:GetCmdArg(sect, page) . ' | col -b'
194 silent exec "r !" . man_cmd
195
196 if unsetwidth
197 let $MANWIDTH = ''
198 endif
199 " Remove blank lines from top and bottom.
200 while line('$') > 1 && getline(1) =~ '^\s*$'
201 1delete _
202 endwhile
203 while line('$') > 1 && getline('$') =~ '^\s*$'
204 $delete _
205 endwhile
206 1
207 setl ft=man nomod
208 setl bufhidden=hide
209 setl nobuflisted
210 setl noma
211endfunc
212
213func dist#man#PopPage()
214 if s:man_tag_depth > 0
215 let s:man_tag_depth = s:man_tag_depth - 1
216 exec "let s:man_tag_buf=s:man_tag_buf_".s:man_tag_depth
217 exec "let s:man_tag_lin=s:man_tag_lin_".s:man_tag_depth
218 exec "let s:man_tag_col=s:man_tag_col_".s:man_tag_depth
goweol6e5ab2b2023-08-18 06:12:42 +0900219
Bram Moolenaard799daa2022-06-20 11:17:32 +0100220 exec s:man_tag_buf."b"
goweol6e5ab2b2023-08-18 06:12:42 +0900221 call cursor(s:man_tag_lin, s:man_tag_col)
222
Bram Moolenaard799daa2022-06-20 11:17:32 +0100223 exec "unlet s:man_tag_buf_".s:man_tag_depth
224 exec "unlet s:man_tag_lin_".s:man_tag_depth
225 exec "unlet s:man_tag_col_".s:man_tag_depth
226 unlet s:man_tag_buf s:man_tag_lin s:man_tag_col
227 endif
228endfunc
229
230let &cpo = s:cpo_save
231unlet s:cpo_save
232
233" vim: set sw=2 ts=8 noet: