(Customizing Faces): Remove doubled `the'.
[bpt/emacs.git] / lisp / man.el
CommitLineData
effdc6a2 1;;; man.el --- browse UNIX manual pages
6594deb0 2
00ed33e7 3;; Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
9750e079 4
effdc6a2 5;; Author: Barry A. Warsaw <bwarsaw@cen.com>
5bbf0b3c 6;; Maintainer: FSF
effdc6a2 7;; Keywords: help
b3435a2f 8;; Adapted-By: ESR, pot
e5167999 9
1a20f48d
JA
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
e5167999 14;; the Free Software Foundation; either version 2, or (at your option)
1a20f48d
JA
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
1a20f48d 26
edbd2f74
ER
27;;; Commentary:
28
b3435a2f
FP
29;; This code provides a function, `man', with which you can browse
30;; UNIX manual pages. Formatting is done in background so that you
31;; can continue to use your Emacs while processing is going on.
effdc6a2
RS
32;;
33;; The mode also supports hypertext-like following of manual page SEE
34;; ALSO references, and other features. See below or do `?' in a
35;; manual page buffer for details.
36
5bbf0b3c 37;; ========== Credits and History ==========
effdc6a2
RS
38;; In mid 1991, several people posted some interesting improvements to
39;; man.el from the standard emacs 18.57 distribution. I liked many of
a7acbbe4 40;; these, but wanted everything in one single package, so I decided
b3435a2f 41;; to incorporate them into a single manual browsing mode. While
effdc6a2
RS
42;; much of the code here has been rewritten, and some features added,
43;; these folks deserve lots of credit for providing the initial
44;; excellent packages on which this one is based.
45
46;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice
47;; improvement which retrieved and cleaned the manpages in a
48;; background process, and which correctly deciphered such options as
49;; man -k.
50
51;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which
52;; provided a very nice manual browsing mode.
53
eb8c3be9 54;; This package was available as `superman.el' from the LCD package
effdc6a2
RS
55;; for some time before it was accepted into Emacs 19. The entry
56;; point and some other names have been changed to make it a drop-in
57;; replacement for the old man.el package.
58
b3435a2f
FP
59;; Francesco Potorti` <pot@cnuce.cnr.it> cleaned it up thoroughly,
60;; making it faster, more robust and more tolerant of different
a7acbbe4 61;; systems' man idiosyncrasies.
b3435a2f 62
effdc6a2
RS
63;; ========== Features ==========
64;; + Runs "man" in the background and pipes the results through a
65;; series of sed and awk scripts so that all retrieving and cleaning
66;; is done in the background. The cleaning commands are configurable.
67;; + Syntax is the same as Un*x man
68;; + Functionality is the same as Un*x man, including "man -k" and
c3343fcf 69;; "man <section>", etc.
effdc6a2
RS
70;; + Provides a manual browsing mode with keybindings for traversing
71;; the sections of a manpage, following references in the SEE ALSO
72;; section, and more.
73;; + Multiple manpages created with the same man command are put into
74;; a narrowed buffer circular list.
edbd2f74 75
b3435a2f
FP
76;; ============= TODO ===========
77;; - Add a command for printing.
78;; - The awk script deletes multiple blank lines. This behaviour does
79;; not allow to understand if there was indeed a blank line at the
80;; end or beginning of a page (after the header, or before the
81;; footer). A different algorithm should be used. It is easy to
82;; compute how many blank lines there are before and after the page
83;; headers, and after the page footer. But it is possible to compute
84;; the number of blank lines before the page footer by euristhics
85;; only. Is it worth doing?
98fd7017
FP
86;; - Allow a user option to mean that all the manpages should go in
87;; the same buffer, where they can be browsed with M-n and M-p.
b3435a2f
FP
88;; - Allow completion on the manpage name when calling man. This
89;; requires a reliable list of places where manpages can be found. The
90;; drawback would be that if the list is not complete, the user might
91;; be led to believe that the manpages in the missing directories do
92;; not exist.
93
d0aede3f 94\f
e5167999
ER
95;;; Code:
96
effdc6a2 97(require 'assoc)
effdc6a2 98
d0aede3f
FP
99;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
100;; empty defvars (keep the compiler quiet)
101
00ed33e7
RS
102(defgroup man nil
103 "Browse UNIX manual pages."
104 :prefix "Man-"
105 :group 'help)
106
107
d0aede3f
FP
108(defvar Man-notify)
109(defvar Man-current-page)
110(defvar Man-page-list)
00ed33e7 111(defcustom Man-filter-list nil
58ffb6ae
RS
112 "*Manpage cleaning filter command phrases.
113This variable contains a list of the following form:
114
115'((command-string phrase-string*)*)
116
117Each phrase-string is concatenated onto the command-string to form a
118command filter. The (standard) output (and standard error) of the Un*x
119man command is piped through each command filter in the order the
120commands appear in the association list. The final output is placed in
00ed33e7
RS
121the manpage buffer."
122 :type '(repeat (list (string :tag "Command String")
123 (repeat :inline t
124 (string :tag "Phrase String"))))
125 :group 'man)
58ffb6ae 126
d0aede3f
FP
127(defvar Man-original-frame)
128(defvar Man-arguments)
d0aede3f
FP
129(defvar Man-sections-alist)
130(defvar Man-refpages-alist)
58ffb6ae 131(defvar Man-uses-untabify-flag t
5bbf0b3c 132 "Non-nil means use `untabify' instead of `Man-untabify-command'.")
d0aede3f 133(defvar Man-page-mode-string)
58ffb6ae
RS
134(defvar Man-sed-script nil
135 "Script for sed to nuke backspaces and ANSI codes from manpages.")
d0aede3f 136
effdc6a2
RS
137;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
138;; user variables
139
00ed33e7 140(defcustom Man-fontify-manpage-flag t
5bbf0b3c 141 "*Non-nil means make up the manpage with fonts."
00ed33e7
RS
142 :type 'boolean
143 :group 'man)
6e7e47f6 144
00ed33e7
RS
145(defcustom Man-overstrike-face 'bold
146 "*Face to use when fontifying overstrike."
147 :type 'face
148 :group 'man)
6e7e47f6 149
00ed33e7
RS
150(defcustom Man-underline-face 'underline
151 "*Face to use when fontifying underlining."
152 :type 'face
153 :group 'man)
2788b7c9 154
b3435a2f 155;; Use the value of the obsolete user option Man-notify, if set.
00ed33e7 156(defcustom Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly)
effdc6a2 157 "*Selects the behavior when manpage is ready.
b3435a2f
FP
158This variable may have one of the following values, where (sf) means
159that the frames are switched, so the manpage is displayed in the frame
160where the man command was called from:
effdc6a2 161
b51aeeff 162newframe -- put the manpage in its own frame (see `Man-frame-parameters')
b3435a2f
FP
163pushy -- make the manpage the current buffer in the current window
164bully -- make the manpage the current buffer and only window (sf)
165aggressive -- make the manpage the current buffer in the other window (sf)
166friendly -- display manpage in the other window but don't make current (sf)
167polite -- don't display manpage, but prints message and beep when ready
effdc6a2 168quiet -- like `polite', but don't beep
b3435a2f 169meek -- make no indication that the manpage is ready
effdc6a2 170
00ed33e7
RS
171Any other value of `Man-notify-method' is equivalent to `meek'."
172 :type '(radio (const newframe) (const pushy) (const bully)
173 (const aggressive) (const friendly)
174 (const polite) (const quiet) (const meek))
175 :group 'man)
effdc6a2 176
00ed33e7
RS
177(defcustom Man-frame-parameters nil
178 "*Frame parameter list for creating a new frame for a manual page."
179 :type 'sexp
180 :group 'man)
b51aeeff 181
00ed33e7 182(defcustom Man-downcase-section-letters-flag t
5bbf0b3c 183 "*Non-nil means letters in sections are converted to lower case.
effdc6a2
RS
184Some Un*x man commands can't handle uppercase letters in sections, for
185example \"man 2V chmod\", but they are often displayed in the manpage
c3343fcf 186with the upper case letter. When this variable is t, the section
effdc6a2 187letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before
00ed33e7
RS
188being sent to the man background process."
189 :type 'boolean
190 :group 'man)
effdc6a2 191
00ed33e7 192(defcustom Man-circular-pages-flag t
5bbf0b3c 193 "*Non-nil means the manpage list is treated as circular for traversal."
00ed33e7
RS
194 :type 'boolean
195 :group 'man)
effdc6a2 196
00ed33e7 197(defcustom Man-section-translations-alist
b3435a2f
FP
198 (list
199 '("3C++" . "3")
200 ;; Some systems have a real 3x man section, so let's comment this.
201 ;; '("3X" . "3") ; Xlib man pages
202 '("3X11" . "3")
203 '("1-UCB" . ""))
effdc6a2
RS
204 "*Association list of bogus sections to real section numbers.
205Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in
c3343fcf 206their references which Un*x `man' does not recognize. This
eb8c3be9 207association list is used to translate those sections, when found, to
00ed33e7
RS
208the associated section number."
209 :type '(repeat (cons (string :tag "Bogus Section")
210 (string :tag "Real Section")))
211 :group 'man)
effdc6a2 212
6e7e47f6
FP
213(defvar manual-program "man"
214 "The name of the program that produces man pages.")
215
b3435a2f 216(defvar Man-untabify-command "pr"
6e7e47f6 217 "Command used for untabifying.")
b3435a2f
FP
218
219(defvar Man-untabify-command-args (list "-t" "-e")
5bbf0b3c 220 "List of arguments to be passed to `Man-untabify-command' (which see).")
b3435a2f
FP
221
222(defvar Man-sed-command "sed"
6e7e47f6 223 "Command used for processing sed scripts.")
b3435a2f
FP
224
225(defvar Man-awk-command "awk"
6e7e47f6 226 "Command used for processing awk scripts.")
effdc6a2
RS
227
228(defvar Man-mode-line-format
6f72f1c2
AS
229 '("-"
230 mode-line-mule-info
231 mode-line-modified
232 mode-line-frame-identification
233 mode-line-buffer-identification " "
234 global-mode-string
235 " " Man-page-mode-string
236 " %[(" mode-name mode-line-process minor-mode-alist "%n)%]--"
237 (line-number-mode "L%l--")
238 (column-number-mode "C%c--")
239 (-3 . "%p") "-%-")
6e7e47f6 240 "Mode line format for manual mode buffer.")
effdc6a2
RS
241
242(defvar Man-mode-map nil
6e7e47f6 243 "Keymap for Man mode.")
effdc6a2 244
e660d0db 245(defvar Man-mode-hook nil
6e7e47f6 246 "Hook run when Man mode is enabled.")
effdc6a2 247
c2d606f4 248(defvar Man-cooked-hook nil
5bbf0b3c 249 "Hook run after removing backspaces but before `Man-mode' processing.")
b3435a2f
FP
250
251(defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*"
6e7e47f6 252 "Regular expression describing the name of a manpage (without section).")
c2d606f4 253
f5f76002 254(defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
6e7e47f6 255 "Regular expression describing a manpage section within parentheses.")
effdc6a2 256
b3435a2f 257(defvar Man-page-header-regexp
635ad748
KH
258 (if (and (string-match "-solaris2\\." system-configuration)
259 (not (string-match "-solaris2\\.[123435]$" system-configuration)))
260 (concat "^[-A-Za-z0-9_].*[ \t]\\(" Man-name-regexp
261 "(\\(" Man-section-regexp "\\))\\)$")
262 (concat "^[ \t]*\\(" Man-name-regexp
263 "(\\(" Man-section-regexp "\\))\\).*\\1"))
6e7e47f6 264 "Regular expression describing the heading of a page.")
b3435a2f
FP
265
266(defvar Man-heading-regexp "^\\([A-Z][A-Z ]+\\)$"
6e7e47f6 267 "Regular expression describing a manpage heading entry.")
effdc6a2
RS
268
269(defvar Man-see-also-regexp "SEE ALSO"
6e7e47f6 270 "Regular expression for SEE ALSO heading (or your equivalent).
effdc6a2
RS
271This regexp should not start with a `^' character.")
272
2cd4790e 273(defvar Man-first-heading-regexp "^[ \t]*NAME$\\|^[ \t]*No manual entry fo.*$"
6e7e47f6 274 "Regular expression describing first heading on a manpage.
effdc6a2
RS
275This regular expression should start with a `^' character.")
276
3eedeb85 277(defvar Man-reference-regexp
b3435a2f 278 (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
6e7e47f6 279 "Regular expression describing a reference in the SEE ALSO section.")
effdc6a2 280
733155db 281(defvar Man-switches ""
6e7e47f6 282 "Switches passed to the man command, as a single string.")
effdc6a2 283
e660d0db
RS
284(defvar Man-specified-section-option
285 (if (string-match "-solaris[0-9.]*$" system-configuration)
286 "-s"
287 "")
6e7e47f6 288 "Option that indicates a specified a manual section name.")
9de0760c 289
effdc6a2
RS
290;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
291;; end user variables
effdc6a2
RS
292\f
293;; other variables and keymap initializations
294(make-variable-buffer-local 'Man-sections-alist)
295(make-variable-buffer-local 'Man-refpages-alist)
296(make-variable-buffer-local 'Man-page-list)
297(make-variable-buffer-local 'Man-current-page)
298(make-variable-buffer-local 'Man-page-mode-string)
75db9a64 299(make-variable-buffer-local 'Man-original-frame)
b3435a2f 300(make-variable-buffer-local 'Man-arguments)
effdc6a2
RS
301
302(setq-default Man-sections-alist nil)
303(setq-default Man-refpages-alist nil)
304(setq-default Man-page-list nil)
305(setq-default Man-current-page 0)
b3435a2f 306(setq-default Man-page-mode-string "1 of 1")
effdc6a2 307
6e7e47f6
FP
308(defconst Man-sysv-sed-script "\
309/\b/ { s/_\b//g
310 s/\b_//g
311 s/o\b+/o/g
f90531cc 312 s/+\bo/o/g
6e7e47f6
FP
313 :ovstrk
314 s/\\(.\\)\b\\1/\\1/g
315 t ovstrk
316 }
317/\e\\[[0-9][0-9]*m/ s///g"
318 "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.")
319
320(defconst Man-berkeley-sed-script "\
321/\b/ { s/_\b//g\\
322 s/\b_//g\\
323 s/o\b+/o/g\\
f90531cc 324 s/+\bo/o/g\\
6e7e47f6
FP
325 :ovstrk\\
326 s/\\(.\\)\b\\1/\\1/g\\
327 t ovstrk\\
328 }\\
329/\e\\[[0-9][0-9]*m/ s///g"
330 "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
331
f655106b
KH
332(defvar man-mode-syntax-table
333 (let ((table (copy-syntax-table (standard-syntax-table))))
334 (modify-syntax-entry ?. "w" table)
335 (modify-syntax-entry ?_ "w" table)
336 table)
337 "Syntax table used in Man mode buffers.")
338
effdc6a2
RS
339(if Man-mode-map
340 nil
341 (setq Man-mode-map (make-keymap))
342 (suppress-keymap Man-mode-map)
343 (define-key Man-mode-map " " 'scroll-up)
344 (define-key Man-mode-map "\177" 'scroll-down)
345 (define-key Man-mode-map "n" 'Man-next-section)
346 (define-key Man-mode-map "p" 'Man-previous-section)
347 (define-key Man-mode-map "\en" 'Man-next-manpage)
348 (define-key Man-mode-map "\ep" 'Man-previous-manpage)
b3435a2f
FP
349 (define-key Man-mode-map ">" 'end-of-buffer)
350 (define-key Man-mode-map "<" 'beginning-of-buffer)
351 (define-key Man-mode-map "." 'beginning-of-buffer)
effdc6a2 352 (define-key Man-mode-map "r" 'Man-follow-manual-reference)
effdc6a2
RS
353 (define-key Man-mode-map "g" 'Man-goto-section)
354 (define-key Man-mode-map "s" 'Man-goto-see-also-section)
b3435a2f 355 (define-key Man-mode-map "k" 'Man-kill)
effdc6a2 356 (define-key Man-mode-map "q" 'Man-quit)
b3435a2f 357 (define-key Man-mode-map "m" 'man)
e7bf8d10 358 (define-key Man-mode-map "\r" 'man-follow)
effdc6a2
RS
359 (define-key Man-mode-map "?" 'describe-mode)
360 )
361
362\f
363;; ======================================================================
364;; utilities
365
58ffb6ae 366(defun Man-init-defvars ()
bf55e415 367 "Used for initialising variables based on display's color support.
5bbf0b3c 368This is necessary if one wants to dump man.el with Emacs."
b3435a2f 369
fd5733a9
KH
370 ;; Avoid possible error in call-process by using a directory that must exist.
371 (let ((default-directory "/"))
372 (setq Man-sed-script
373 (cond
374 (Man-fontify-manpage-flag
375 nil)
376 ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
377 Man-sysv-sed-script)
378 ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
379 Man-berkeley-sed-script)
380 (t
381 nil))))
58ffb6ae
RS
382
383 (setq Man-filter-list
1ac26bf5
AS
384 ;; Avoid trailing nil which confuses customize.
385 (apply 'list
b3435a2f 386 (cons
58ffb6ae
RS
387 Man-sed-command
388 (list
389 (if Man-sed-script
390 (concat "-e '" Man-sed-script "'")
391 "")
392 "-e '/^[\001-\032][\001-\032]*$/d'"
393 "-e '/\e[789]/s///g'"
394 "-e '/Reformatting page. Wait/d'"
395 "-e '/Reformatting entry. Wait/d'"
396 "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
397 "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
398 "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
399 "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
400 "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
401 "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
008d825a 402 "-e '/^[A-Za-z].*Last[ \t]change:/d'"
58ffb6ae
RS
403 "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
404 "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
405 "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
406 ))
407 (cons
408 Man-awk-command
409 (list
410 "'\n"
411 "BEGIN { blankline=0; anonblank=0; }\n"
412 "/^$/ { if (anonblank==0) next; }\n"
413 "{ anonblank=1; }\n"
414 "/^$/ { blankline++; next; }\n"
415 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
416 "'"
417 ))
418 (if (not Man-uses-untabify-flag)
1ac26bf5
AS
419 ;; The outer list will be stripped off by apply.
420 (list (cons
421 Man-untabify-command
422 Man-untabify-command-args))
58ffb6ae 423 )))
b3435a2f 424)
effdc6a2 425
d0aede3f
FP
426(defsubst Man-match-substring (&optional n string)
427 "Return the substring matched by the last search.
428Optional arg N means return the substring matched by the Nth paren
429grouping. Optional second arg STRING means return a substring from
430that string instead of from the current buffer."
431 (if (null n) (setq n 0))
432 (if string
433 (substring string (match-beginning n) (match-end n))
434 (buffer-substring (match-beginning n) (match-end n))))
435
b3435a2f
FP
436(defsubst Man-make-page-mode-string ()
437 "Formats part of the mode line for Man mode."
438 (format "%s page %d of %d"
439 (or (nth 2 (nth (1- Man-current-page) Man-page-list))
440 "")
441 Man-current-page
442 (length Man-page-list)))
443
444(defsubst Man-build-man-command ()
effdc6a2 445 "Builds the entire background manpage and cleaning command."
0020dbcd
EZ
446 (let ((command (concat manual-program " " Man-switches
447 ; Stock MS-DOS shells cannot redirect stderr;
448 ; `call-process' below sends it to /dev/null,
449 ; so we don't need `2>' even with DOS shells
450 ; which do support stderr redirection.
451 (if (not (fboundp 'start-process))
452 " %s"
3945a18a 453 (concat " %s 2>" null-device))))
effdc6a2 454 (flist Man-filter-list))
b3435a2f 455 (while (and flist (car flist))
effdc6a2 456 (let ((pcom (car (car flist)))
b3435a2f
FP
457 (pargs (cdr (car flist))))
458 (setq command
459 (concat command " | " pcom " "
d6373ed5
SM
460 (mapconcat (lambda (phrase)
461 (if (not (stringp phrase))
462 (error "Malformed Man-filter-list"))
463 phrase)
b3435a2f
FP
464 pargs " ")))
465 (setq flist (cdr flist))))
effdc6a2
RS
466 command))
467
effdc6a2 468(defun Man-translate-references (ref)
b3435a2f
FP
469 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
470Leave it as is if already in that style. Possibly downcase and
471translate the section (see the Man-downcase-section-letters-flag
2f2228c0 472and the Man-section-translations-alist variables)."
b3435a2f
FP
473 (let ((name "")
474 (section "")
475 (slist Man-section-translations-alist))
effdc6a2 476 (cond
b3435a2f 477 ;; "chmod(2V)" case ?
2f2228c0 478 ((string-match (concat "^" Man-reference-regexp "$") ref)
b3435a2f
FP
479 (setq name (Man-match-substring 1 ref)
480 section (Man-match-substring 2 ref)))
481 ;; "2v chmod" case ?
2f2228c0 482 ((string-match (concat "^\\(" Man-section-regexp
b3435a2f
FP
483 "\\) +\\(" Man-name-regexp "\\)$") ref)
484 (setq name (Man-match-substring 2 ref)
485 section (Man-match-substring 1 ref))))
486 (if (string= name "")
487 ref ; Return the reference as is
488 (if Man-downcase-section-letters-flag
489 (setq section (downcase section)))
490 (while slist
491 (let ((s1 (car (car slist)))
492 (s2 (cdr (car slist))))
493 (setq slist (cdr slist))
494 (if Man-downcase-section-letters-flag
495 (setq s1 (downcase s1)))
496 (if (not (string= s1 section)) nil
497 (setq section (if Man-downcase-section-letters-flag
498 (downcase s2)
499 s2)
500 slist nil))))
501 (concat Man-specified-section-option section " " name))))
502
effdc6a2
RS
503\f
504;; ======================================================================
b3435a2f 505;; default man entry: get word under point
effdc6a2 506
b3435a2f 507(defsubst Man-default-man-entry ()
effdc6a2 508 "Make a guess at a default manual entry.
af900b23 509This guess is based on the text surrounding the cursor."
f655106b 510 (let (word)
1a20f48d 511 (save-excursion
b3435a2f 512 ;; Default man entry title is any word the cursor is on, or if
f655106b
KH
513 ;; cursor not on a word, then nearest preceding word.
514 (setq word (current-word))
515 (if (string-match "[._]+$" word)
516 (setq word (substring word 0 (match-beginning 0))))
b3435a2f 517 ;; If looking at something like ioctl(2) or brc(1M), include the
c448c134 518 ;; section number in the returned value. Remove text properties.
f655106b
KH
519 (forward-word 1)
520 ;; Use `format' here to clear any text props from `word'.
521 (format "%s%s"
522 word
523 (if (looking-at
524 (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
525 (format "(%s)" (Man-match-substring 1))
526 "")))))
b3435a2f 527
effdc6a2
RS
528\f
529;; ======================================================================
b3435a2f 530;; Top level command and background process sentinel
1a20f48d 531
b3435a2f 532;; For compatibility with older versions.
cac0b95d 533;;;###autoload
b3435a2f 534(defalias 'manual-entry 'man)
cac0b95d 535
effdc6a2 536;;;###autoload
98fd7017 537(defun man (man-args)
effdc6a2 538 "Get a Un*x manual page and put it in a buffer.
c3343fcf 539This command is the top-level command in the man package. It runs a Un*x
effdc6a2 540command to retrieve and clean a manpage in the background and places the
c3343fcf 541results in a Man mode (manpage browsing) buffer. See variable
799ac634 542`Man-notify-method' for what happens when the buffer is ready.
4fbee715
EZ
543If a buffer already exists for this man page, it will display immediately.
544
545To specify a man page from a certain section, type SUBJECT(SECTION) or
546SECTION SUBJECT when prompted for a manual entry."
b3435a2f 547 (interactive
98fd7017
FP
548 (list (let* ((default-entry (Man-default-man-entry))
549 (input (read-string
550 (format "Manual entry%s: "
551 (if (string= default-entry "")
552 ""
553 (format " (default %s)" default-entry))))))
554 (if (string= input "")
555 (if (string= default-entry "")
556 (error "No man args given")
557 default-entry)
558 input))))
b3435a2f 559
b3435a2f
FP
560 ;; Possibly translate the "subject(section)" syntax into the
561 ;; "section subject" syntax and possibly downcase the section.
562 (setq man-args (Man-translate-references man-args))
563
98fd7017 564 (Man-getpage-in-background man-args))
b3435a2f 565
e7bf8d10
KH
566;;;###autoload
567(defun man-follow (man-args)
568 "Get a Un*x manual page of the item under point and put it in a buffer."
569 (interactive (list (Man-default-man-entry)))
570 (if (or (not man-args)
571 (string= man-args ""))
572 (error "No item under point")
573 (man man-args)))
aa228418 574
98fd7017 575(defun Man-getpage-in-background (topic)
5bbf0b3c 576 "Use TOPIC to build and fire off the manpage and cleaning command."
e660d0db 577 (let* ((man-args topic)
d0aede3f 578 (bufname (concat "*Man " man-args "*"))
effdc6a2 579 (buffer (get-buffer bufname)))
98fd7017 580 (if buffer
effdc6a2 581 (Man-notify-when-ready buffer)
eaf1946c 582 (require 'env)
b3435a2f 583 (message "Invoking %s %s in the background" manual-program man-args)
effdc6a2 584 (setq buffer (generate-new-buffer bufname))
75db9a64
KH
585 (save-excursion
586 (set-buffer buffer)
b3435a2f
FP
587 (setq Man-original-frame (selected-frame))
588 (setq Man-arguments man-args))
fd5733a9 589 (let ((process-environment (copy-sequence process-environment))
cd3b7f95
RS
590 ;; The following is so Awk script gets \n intact
591 ;; But don't prevent decoding of the outside.
592 (coding-system-for-write 'raw-text-unix)
86293583 593 ;; We must decode the output by a coding system that the
9be031e4 594 ;; system's locale suggests in multibyte mode.
a1c5fe60
KH
595 (coding-system-for-read
596 (if default-enable-multibyte-characters
597 locale-coding-system 'raw-text-unix))
fd5733a9
KH
598 ;; Avoid possible error by using a directory that always exists.
599 (default-directory "/"))
82c9fe8e
RS
600 ;; Prevent any attempt to use display terminal fanciness.
601 (setenv "TERM" "dumb")
0020dbcd
EZ
602 (if (fboundp 'start-process)
603 (set-process-sentinel
604 (start-process manual-program buffer "sh" "-c"
605 (format (Man-build-man-command) man-args))
606 'Man-bgproc-sentinel)
607 (progn
608 (let ((exit-status
609 (call-process shell-file-name nil (list buffer nil) nil "-c"
610 (format (Man-build-man-command) man-args)))
611 (msg ""))
612 (or (and (numberp exit-status)
613 (= exit-status 0))
614 (and (numberp exit-status)
615 (setq msg
616 (format "exited abnormally with code %d"
617 exit-status)))
618 (setq msg exit-status))
619 (Man-bgproc-sentinel bufname msg))))))))
effdc6a2
RS
620
621(defun Man-notify-when-ready (man-buffer)
622 "Notify the user when MAN-BUFFER is ready.
799ac634 623See the variable `Man-notify-method' for the different notification behaviors."
c9bf42f9
RS
624 (let ((saved-frame (save-excursion
625 (set-buffer man-buffer)
626 Man-original-frame)))
627 (cond
799ac634 628 ((eq Man-notify-method 'newframe)
b3435a2f
FP
629 ;; Since we run asynchronously, perhaps while Emacs is waiting
630 ;; for input, we must not leave a different buffer current. We
631 ;; can't rely on the editor command loop to reselect the
632 ;; selected window's buffer.
c9bf42f9 633 (save-excursion
42a9dc84
RS
634 (let ((frame (make-frame Man-frame-parameters)))
635 (set-window-buffer (frame-selected-window frame) man-buffer)
bf55e415
EZ
636 (set-window-dedicated-p (frame-selected-window frame) t)
637 (or (display-multi-frame-p frame)
638 (select-frame frame)))))
799ac634 639 ((eq Man-notify-method 'pushy)
b3435a2f 640 (switch-to-buffer man-buffer))
799ac634 641 ((eq Man-notify-method 'bully)
bf55e415 642 (and (frame-live-p saved-frame)
c9bf42f9
RS
643 (select-frame saved-frame))
644 (pop-to-buffer man-buffer)
645 (delete-other-windows))
799ac634 646 ((eq Man-notify-method 'aggressive)
bf55e415 647 (and (frame-live-p saved-frame)
c9bf42f9
RS
648 (select-frame saved-frame))
649 (pop-to-buffer man-buffer))
799ac634 650 ((eq Man-notify-method 'friendly)
bf55e415 651 (and (frame-live-p saved-frame)
c9bf42f9
RS
652 (select-frame saved-frame))
653 (display-buffer man-buffer 'not-this-window))
799ac634 654 ((eq Man-notify-method 'polite)
c9bf42f9 655 (beep)
b3435a2f 656 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 657 ((eq Man-notify-method 'quiet)
b3435a2f 658 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 659 ((or (eq Man-notify-method 'meek)
c9bf42f9
RS
660 t)
661 (message ""))
662 )))
effdc6a2 663
6cb92c3a 664(defun Man-softhyphen-to-minus ()
9f79084c
DL
665 ;; \255 is some kind of dash in Latin-N. Versions of Debian man, at
666 ;; least, emit it even when not in a Latin-N locale.
667 (unless (eq t (compare-strings "latin-" 0 nil
668 current-language-environment 0 6 t))
669 (goto-char (point-min))
670 (let ((str "\255"))
671 (if enable-multibyte-characters
672 (setq str (string-as-multibyte str)))
673 (while (search-forward str nil t) (replace-match "-")))))
6cb92c3a 674
b3435a2f
FP
675(defun Man-fontify-manpage ()
676 "Convert overstriking and underlining to the correct fonts.
677Same for the ANSI bold and normal escape sequences."
678 (interactive)
679 (message "Please wait: making up the %s man page..." Man-arguments)
c3343fcf 680 (goto-char (point-min))
b3435a2f
FP
681 (while (search-forward "\e[1m" nil t)
682 (delete-backward-char 4)
683 (put-text-property (point)
684 (progn (if (search-forward "\e[0m" nil 'move)
685 (delete-backward-char 4))
686 (point))
6e7e47f6 687 'face Man-overstrike-face))
e1ceff3a
KH
688 (if (< (buffer-size) (position-bytes (point-max)))
689 ;; Multibyte characters exist.
690 (progn
691 (goto-char (point-min))
692 (while (search-forward "__\b\b" nil t)
693 (backward-delete-char 4)
694 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
695 (goto-char (point-min))
696 (while (search-forward "\b\b__" nil t)
697 (backward-delete-char 4)
698 (put-text-property (1- (point)) (point) 'face Man-underline-face))))
b3435a2f
FP
699 (goto-char (point-min))
700 (while (search-forward "_\b" nil t)
701 (backward-delete-char 2)
6e7e47f6 702 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
b3435a2f
FP
703 (goto-char (point-min))
704 (while (search-forward "\b_" nil t)
705 (backward-delete-char 2)
6e7e47f6 706 (put-text-property (1- (point)) (point) 'face Man-underline-face))
b3435a2f 707 (goto-char (point-min))
cb581be7 708 (while (re-search-forward "\\(.\\)\\(\b+\\1\\)+" nil t)
6024daef 709 (replace-match "\\1")
6e7e47f6 710 (put-text-property (1- (point)) (point) 'face Man-overstrike-face))
6024daef 711 (goto-char (point-min))
f90531cc
FP
712 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
713 (replace-match "o")
b3435a2f
FP
714 (put-text-property (1- (point)) (point) 'face 'bold))
715 (goto-char (point-min))
f7046d47 716 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
6024daef 717 (replace-match "+")
b3435a2f 718 (put-text-property (1- (point)) (point) 'face 'bold))
6cb92c3a 719 (Man-softhyphen-to-minus)
b3435a2f
FP
720 (message "%s man page made up" Man-arguments))
721
722(defun Man-cleanup-manpage ()
723 "Remove overstriking and underlining from the current buffer."
724 (interactive)
f7046d47
FP
725 (message "Please wait: cleaning up the %s man page..."
726 Man-arguments)
9931e1ba 727 (if (or (interactive-p) (not Man-sed-script))
f7046d47
FP
728 (progn
729 (goto-char (point-min))
730 (while (search-forward "_\b" nil t) (backward-delete-char 2))
731 (goto-char (point-min))
732 (while (search-forward "\b_" nil t) (backward-delete-char 2))
733 (goto-char (point-min))
734 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
735 (replace-match "\\1"))
736 (goto-char (point-min))
737 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
738 (goto-char (point-min))
f90531cc 739 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
f7046d47 740 ))
6024daef 741 (goto-char (point-min))
f7046d47 742 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
6cb92c3a 743 (Man-softhyphen-to-minus)
b3435a2f 744 (message "%s man page cleaned up" Man-arguments))
c3343fcf 745
effdc6a2 746(defun Man-bgproc-sentinel (process msg)
0020dbcd 747 "Manpage background process sentinel.
5bbf0b3c 748When manpage command is run asynchronously, PROCESS is the process
0020dbcd
EZ
749object for the manpage command; when manpage command is run
750synchronously, PROCESS is the name of the buffer where the manpage
751command is run. Second argument MSG is the exit message of the
752manpage command."
753 (let ((Man-buffer (if (stringp process) (get-buffer process)
754 (process-buffer process)))
effdc6a2 755 (delete-buff nil)
8c79b392 756 (err-mess nil))
b3435a2f 757
effdc6a2 758 (if (null (buffer-name Man-buffer)) ;; deleted buffer
0020dbcd
EZ
759 (or (stringp process)
760 (set-process-buffer process nil))
b3435a2f
FP
761
762 (save-excursion
763 (set-buffer Man-buffer)
1d56cc39
RS
764 (let ((case-fold-search nil))
765 (goto-char (point-min))
766 (cond ((or (looking-at "No \\(manual \\)*entry for")
767 (looking-at "[^\n]*: nothing appropriate$"))
768 (setq err-mess (buffer-substring (point)
769 (progn
770 (end-of-line) (point)))
771 delete-buff t))
0020dbcd
EZ
772 ((or (stringp process)
773 (not (and (eq (process-status process) 'exit)
774 (= (process-exit-status process) 0))))
775 (or (zerop (length msg))
776 (progn
777 (setq err-mess
778 (concat (buffer-name Man-buffer)
779 ": process "
780 (let ((eos (1- (length msg))))
781 (if (= (aref msg eos) ?\n)
782 (substring msg 0 eos) msg))))
783 (goto-char (point-max))
784 (insert (format "\nprocess %s" msg))))
785 ))
1223b6c4
RS
786 (if delete-buff
787 (kill-buffer Man-buffer)
788 (if Man-fontify-manpage-flag
789 (Man-fontify-manpage)
790 (Man-cleanup-manpage))
791 (run-hooks 'Man-cooked-hook)
792 (Man-mode)
793 (set-buffer-modified-p nil)
0020dbcd 794 ))
1d56cc39
RS
795 ;; Restore case-fold-search before calling
796 ;; Man-notify-when-ready because it may switch buffers.
797
798 (if (not delete-buff)
799 (Man-notify-when-ready Man-buffer))
800
801 (if err-mess
802 (error err-mess))
803 ))))
effdc6a2
RS
804
805\f
806;; ======================================================================
807;; set up manual mode in buffer and build alists
808
809(defun Man-mode ()
c3343fcf 810 "A mode for browsing Un*x manual pages.
effdc6a2 811
5bbf0b3c 812The following man commands are available in the buffer. Try
effdc6a2 813\"\\[describe-key] <key> RET\" for more information:
aa228418 814
b3435a2f 815\\[man] Prompt to retrieve a new manpage.
effdc6a2
RS
816\\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
817\\[Man-next-manpage] Jump to next manpage in circular list.
818\\[Man-previous-manpage] Jump to previous manpage in circular list.
819\\[Man-next-section] Jump to next manpage section.
820\\[Man-previous-section] Jump to previous manpage section.
821\\[Man-goto-section] Go to a manpage section.
822\\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
b3435a2f
FP
823\\[Man-quit] Deletes the manpage window, bury its buffer.
824\\[Man-kill] Deletes the manpage window, kill its buffer.
effdc6a2
RS
825\\[describe-mode] Prints this help text.
826
5bbf0b3c 827The following variables may be of some use. Try
effdc6a2
RS
828\"\\[describe-variable] <variable-name> RET\" for more information:
829
5bbf0b3c
DL
830`Man-notify-method' What happens when manpage formatting is done.
831`Man-downcase-section-letters-flag' Force section letters to lower case.
832`Man-circular-pages-flag' Treat multiple manpage list as circular.
5bbf0b3c
DL
833`Man-section-translations-alist' List of section numbers and their Un*x equiv.
834`Man-filter-list' Background manpage filter command.
835`Man-mode-line-format' Mode line format for Man mode buffers.
836`Man-mode-map' Keymap bindings for Man mode buffers.
837`Man-mode-hook' Normal hook run on entry to Man mode.
838`Man-section-regexp' Regexp describing manpage section letters.
839`Man-heading-regexp' Regexp describing section headers.
840`Man-see-also-regexp' Regexp for SEE ALSO section (or your equiv).
841`Man-first-heading-regexp' Regexp for first heading on a manpage.
842`Man-reference-regexp' Regexp matching a references in SEE ALSO.
843`Man-switches' Background `man' command switches.
effdc6a2
RS
844
845The following key bindings are currently in effect in the buffer:
846\\{Man-mode-map}"
847 (interactive)
848 (setq major-mode 'Man-mode
c3343fcf 849 mode-name "Man"
effdc6a2
RS
850 buffer-auto-save-file-name nil
851 mode-line-format Man-mode-line-format
852 truncate-lines t
853 buffer-read-only t)
854 (buffer-disable-undo (current-buffer))
855 (auto-fill-mode -1)
856 (use-local-map Man-mode-map)
f655106b 857 (set-syntax-table man-mode-syntax-table)
effdc6a2 858 (Man-build-page-list)
b3435a2f
FP
859 (Man-strip-page-headers)
860 (Man-unindent)
526504b8
RS
861 (Man-goto-page 1)
862 (run-hooks 'Man-mode-hook))
1a20f48d 863
b3435a2f 864(defsubst Man-build-section-alist ()
effdc6a2
RS
865 "Build the association list of manpage sections."
866 (setq Man-sections-alist nil)
1a20f48d 867 (goto-char (point-min))
2cd4790e
KH
868 (let ((case-fold-search nil))
869 (while (re-search-forward Man-heading-regexp (point-max) t)
b3435a2f 870 (aput 'Man-sections-alist (Man-match-substring 1))
2cd4790e 871 (forward-line 1))))
effdc6a2 872
b3435a2f 873(defsubst Man-build-references-alist ()
effdc6a2
RS
874 "Build the association list of references (in the SEE ALSO section)."
875 (setq Man-refpages-alist nil)
876 (save-excursion
877 (if (Man-find-section Man-see-also-regexp)
878 (let ((start (progn (forward-line 1) (point)))
879 (end (progn
880 (Man-next-section 1)
881 (point)))
882 hyphenated
883 (runningpoint -1))
2cd4790e
KH
884 (save-restriction
885 (narrow-to-region start end)
886 (goto-char (point-min))
887 (back-to-indentation)
888 (while (and (not (eobp)) (/= (point) runningpoint))
889 (setq runningpoint (point))
b3435a2f
FP
890 (if (re-search-forward Man-reference-regexp end t)
891 (let* ((word (Man-match-substring 0))
892 (len (1- (length word))))
893 (if hyphenated
894 (setq word (concat hyphenated word)
895 hyphenated nil))
896 (if (= (aref word len) ?-)
897 (setq hyphenated (substring word 0 len))
898 (aput 'Man-refpages-alist word))))
2cd4790e 899 (skip-chars-forward " \t\n,")))))))
effdc6a2 900
d0aede3f 901(defun Man-build-page-list ()
effdc6a2
RS
902 "Build the list of separate manpages in the buffer."
903 (setq Man-page-list nil)
b3435a2f
FP
904 (let ((page-start (point-min))
905 (page-end (point-max))
906 (header ""))
907 (goto-char page-start)
908 ;; (switch-to-buffer (current-buffer))(debug)
909 (while (not (eobp))
910 (setq header
911 (if (looking-at Man-page-header-regexp)
912 (Man-match-substring 1)
913 nil))
914 ;; Go past both the current and the next Man-first-heading-regexp
915 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
916 (let ((p (progn (beginning-of-line) (point))))
917 ;; We assume that the page header is delimited by blank
918 ;; lines and that it contains at most one blank line. So
919 ;; if we back by three blank lines we will be sure to be
920 ;; before the page header but not before the possible
921 ;; previous page header.
922 (search-backward "\n\n" nil t 3)
923 (if (re-search-forward Man-page-header-regexp p 'move)
924 (beginning-of-line))))
925 (setq page-end (point))
926 (setq Man-page-list (append Man-page-list
927 (list (list (copy-marker page-start)
928 (copy-marker page-end)
929 header))))
930 (setq page-start page-end)
931 )))
932
d0aede3f 933(defun Man-strip-page-headers ()
b3435a2f
FP
934 "Strip all the page headers but the first from the manpage."
935 (let ((buffer-read-only nil)
936 (case-fold-search nil)
937 (page-list Man-page-list)
938 (page ())
939 (header ""))
940 (while page-list
941 (setq page (car page-list))
942 (and (nth 2 page)
943 (goto-char (car page))
944 (re-search-forward Man-first-heading-regexp nil t)
945 (setq header (buffer-substring (car page) (match-beginning 0)))
946 ;; Since the awk script collapses all successive blank
947 ;; lines into one, and since we don't want to get rid of
948 ;; the fast awk script, one must choose between adding
949 ;; spare blank lines between pages when there were none and
950 ;; deleting blank lines at page boundaries when there were
951 ;; some. We choose the first, so we comment the following
952 ;; line.
953 ;; (setq header (concat "\n" header)))
954 (while (search-forward header (nth 1 page) t)
955 (replace-match "")))
956 (setq page-list (cdr page-list)))))
957
d0aede3f 958(defun Man-unindent ()
b3435a2f
FP
959 "Delete the leading spaces that indent the manpage."
960 (let ((buffer-read-only nil)
961 (case-fold-search nil)
962 (page-list Man-page-list))
963 (while page-list
964 (let ((page (car page-list))
965 (indent "")
966 (nindent 0))
967 (narrow-to-region (car page) (car (cdr page)))
968 (if Man-uses-untabify-flag
969 (untabify (point-min) (point-max)))
970 (if (catch 'unindent
971 (goto-char (point-min))
972 (if (not (re-search-forward Man-first-heading-regexp nil t))
973 (throw 'unindent nil))
974 (beginning-of-line)
975 (setq indent (buffer-substring (point)
976 (progn
977 (skip-chars-forward " ")
978 (point))))
979 (setq nindent (length indent))
980 (if (zerop nindent)
981 (throw 'unindent nil))
982 (setq indent (concat indent "\\|$"))
983 (goto-char (point-min))
984 (while (not (eobp))
985 (if (looking-at indent)
986 (forward-line 1)
987 (throw 'unindent nil)))
988 (goto-char (point-min)))
989 (while (not (eobp))
990 (or (eolp)
991 (delete-char nindent))
992 (forward-line 1)))
993 (setq page-list (cdr page-list))
2cd4790e 994 ))))
effdc6a2
RS
995
996\f
997;; ======================================================================
e660d0db 998;; Man mode commands
effdc6a2
RS
999
1000(defun Man-next-section (n)
1001 "Move point to Nth next section (default 1)."
1002 (interactive "p")
2cd4790e
KH
1003 (let ((case-fold-search nil))
1004 (if (looking-at Man-heading-regexp)
1005 (forward-line 1))
1006 (if (re-search-forward Man-heading-regexp (point-max) t n)
1007 (beginning-of-line)
1008 (goto-char (point-max)))))
effdc6a2
RS
1009
1010(defun Man-previous-section (n)
1011 "Move point to Nth previous section (default 1)."
1012 (interactive "p")
2cd4790e
KH
1013 (let ((case-fold-search nil))
1014 (if (looking-at Man-heading-regexp)
1015 (forward-line -1))
1016 (if (re-search-backward Man-heading-regexp (point-min) t n)
1017 (beginning-of-line)
1018 (goto-char (point-min)))))
effdc6a2
RS
1019
1020(defun Man-find-section (section)
1021 "Move point to SECTION if it exists, otherwise don't move point.
1022Returns t if section is found, nil otherwise."
2cd4790e
KH
1023 (let ((curpos (point))
1024 (case-fold-search nil))
effdc6a2 1025 (goto-char (point-min))
b3435a2f 1026 (if (re-search-forward (concat "^" section) (point-max) t)
effdc6a2
RS
1027 (progn (beginning-of-line) t)
1028 (goto-char curpos)
1029 nil)
1030 ))
1031
1032(defun Man-goto-section ()
1033 "Query for section to move point to."
1034 (interactive)
1035 (aput 'Man-sections-alist
1036 (let* ((default (aheadsym Man-sections-alist))
1037 (completion-ignore-case t)
1038 chosen
1039 (prompt (concat "Go to section: (default " default ") ")))
1040 (setq chosen (completing-read prompt Man-sections-alist))
1041 (if (or (not chosen)
1042 (string= chosen ""))
1043 default
1044 chosen)))
1045 (Man-find-section (aheadsym Man-sections-alist)))
1046
1047(defun Man-goto-see-also-section ()
1048 "Move point the the \"SEE ALSO\" section.
c3343fcf 1049Actually the section moved to is described by `Man-see-also-regexp'."
effdc6a2
RS
1050 (interactive)
1051 (if (not (Man-find-section Man-see-also-regexp))
1052 (error (concat "No " Man-see-also-regexp
b3435a2f 1053 " section found in the current manpage"))))
effdc6a2 1054
2151a1cf 1055(defun Man-follow-manual-reference (reference)
effdc6a2 1056 "Get one of the manpages referred to in the \"SEE ALSO\" section.
5bbf0b3c 1057Specify which REFERENCE to use; default is based on word at point."
e660d0db
RS
1058 (interactive
1059 (if (not Man-refpages-alist)
b3435a2f 1060 (error "There are no references in the current man page")
2151a1cf 1061 (list (let* ((default (or
e660d0db
RS
1062 (car (all-completions
1063 (save-excursion
1064 (skip-syntax-backward "w()")
1065 (skip-chars-forward " \t")
1066 (let ((word (current-word)))
1067 ;; strip a trailing '-':
1068 (if (string-match "-$" word)
2cd4790e
KH
1069 (substring word 0
1070 (match-beginning 0))
e660d0db
RS
1071 word)))
1072 Man-refpages-alist))
1073 (aheadsym Man-refpages-alist)))
1074 chosen
1075 (prompt (concat "Refer to: (default " default ") ")))
1076 (setq chosen (completing-read prompt Man-refpages-alist nil t))
1077 (if (or (not chosen)
1078 (string= chosen ""))
1079 default
1080 chosen)))))
effdc6a2 1081 (if (not Man-refpages-alist)
b3435a2f 1082 (error "Can't find any references in the current manpage")
e660d0db 1083 (aput 'Man-refpages-alist reference)
effdc6a2 1084 (Man-getpage-in-background
2151a1cf 1085 (Man-translate-references (aheadsym Man-refpages-alist)))))
effdc6a2 1086
b3435a2f 1087(defun Man-kill ()
effdc6a2
RS
1088 "Kill the buffer containing the manpage."
1089 (interactive)
06cab243 1090 (quit-window t))
b3435a2f
FP
1091
1092(defun Man-quit ()
1093 "Bury the buffer containing the manpage."
1094 (interactive)
06cab243 1095 (quit-window))
effdc6a2
RS
1096
1097(defun Man-goto-page (page)
1098 "Go to the manual page on page PAGE."
1099 (interactive
b3435a2f
FP
1100 (if (not Man-page-list)
1101 (let ((args Man-arguments))
1102 (kill-buffer (current-buffer))
1103 (error "Can't find the %s manpage" args))
1104 (if (= (length Man-page-list) 1)
1105 (error "You're looking at the only manpage in the buffer")
1106 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1107 (length Man-page-list)))))))
1108 (if (not Man-page-list)
1109 (let ((args Man-arguments))
1110 (kill-buffer (current-buffer))
1111 (error "Can't find the %s manpage" args)))
effdc6a2
RS
1112 (if (or (< page 1)
1113 (> page (length Man-page-list)))
1114 (error "No manpage %d found" page))
1115 (let* ((page-range (nth (1- page) Man-page-list))
1116 (page-start (car page-range))
b3435a2f 1117 (page-end (car (cdr page-range))))
effdc6a2 1118 (setq Man-current-page page
b3435a2f 1119 Man-page-mode-string (Man-make-page-mode-string))
effdc6a2
RS
1120 (widen)
1121 (goto-char page-start)
1122 (narrow-to-region page-start page-end)
1123 (Man-build-section-alist)
b3435a2f 1124 (Man-build-references-alist)
effdc6a2
RS
1125 (goto-char (point-min))))
1126
1127
1128(defun Man-next-manpage ()
1129 "Find the next manpage entry in the buffer."
1130 (interactive)
1131 (if (= (length Man-page-list) 1)
9f2863b2 1132 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1133 (if (< Man-current-page (length Man-page-list))
1134 (Man-goto-page (1+ Man-current-page))
b3435a2f 1135 (if Man-circular-pages-flag
effdc6a2 1136 (Man-goto-page 1)
9f2863b2 1137 (error "You're looking at the last manpage in the buffer"))))
effdc6a2
RS
1138
1139(defun Man-previous-manpage ()
1140 "Find the previous manpage entry in the buffer."
1141 (interactive)
1142 (if (= (length Man-page-list) 1)
9f2863b2 1143 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1144 (if (> Man-current-page 1)
1145 (Man-goto-page (1- Man-current-page))
b3435a2f 1146 (if Man-circular-pages-flag
effdc6a2 1147 (Man-goto-page (length Man-page-list))
9f2863b2 1148 (error "You're looking at the first manpage in the buffer"))))
733155db 1149\f
58ffb6ae
RS
1150;; Init the man package variables, if not already done.
1151(Man-init-defvars)
1152
5bbf0b3c
DL
1153(add-to-list 'debug-ignored-errors "^No manpage [0-9]* found$")
1154(add-to-list 'debug-ignored-errors "^Can't find the .* manpage$")
1155
733155db
JB
1156(provide 'man)
1157
6594deb0 1158;;; man.el ends here