Require mm-util.
[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
RS
508 "Make a guess at a default manual entry.
509This guess is based on the text surrounding the cursor, and the
c3343fcf 510default section number is selected from `Man-auto-section-alist'."
f655106b 511 (let (word)
1a20f48d 512 (save-excursion
b3435a2f 513 ;; Default man entry title is any word the cursor is on, or if
f655106b
KH
514 ;; cursor not on a word, then nearest preceding word.
515 (setq word (current-word))
516 (if (string-match "[._]+$" word)
517 (setq word (substring word 0 (match-beginning 0))))
b3435a2f 518 ;; If looking at something like ioctl(2) or brc(1M), include the
c448c134 519 ;; section number in the returned value. Remove text properties.
f655106b
KH
520 (forward-word 1)
521 ;; Use `format' here to clear any text props from `word'.
522 (format "%s%s"
523 word
524 (if (looking-at
525 (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
526 (format "(%s)" (Man-match-substring 1))
527 "")))))
b3435a2f 528
effdc6a2
RS
529\f
530;; ======================================================================
b3435a2f 531;; Top level command and background process sentinel
1a20f48d 532
b3435a2f 533;; For compatibility with older versions.
cac0b95d 534;;;###autoload
b3435a2f 535(defalias 'manual-entry 'man)
cac0b95d 536
effdc6a2 537;;;###autoload
98fd7017 538(defun man (man-args)
effdc6a2 539 "Get a Un*x manual page and put it in a buffer.
c3343fcf 540This command is the top-level command in the man package. It runs a Un*x
effdc6a2 541command to retrieve and clean a manpage in the background and places the
c3343fcf 542results in a Man mode (manpage browsing) buffer. See variable
799ac634 543`Man-notify-method' for what happens when the buffer is ready.
4fbee715
EZ
544If a buffer already exists for this man page, it will display immediately.
545
546To specify a man page from a certain section, type SUBJECT(SECTION) or
547SECTION SUBJECT when prompted for a manual entry."
b3435a2f 548 (interactive
98fd7017
FP
549 (list (let* ((default-entry (Man-default-man-entry))
550 (input (read-string
551 (format "Manual entry%s: "
552 (if (string= default-entry "")
553 ""
554 (format " (default %s)" default-entry))))))
555 (if (string= input "")
556 (if (string= default-entry "")
557 (error "No man args given")
558 default-entry)
559 input))))
b3435a2f 560
b3435a2f
FP
561 ;; Possibly translate the "subject(section)" syntax into the
562 ;; "section subject" syntax and possibly downcase the section.
563 (setq man-args (Man-translate-references man-args))
564
98fd7017 565 (Man-getpage-in-background man-args))
b3435a2f 566
e7bf8d10
KH
567;;;###autoload
568(defun man-follow (man-args)
569 "Get a Un*x manual page of the item under point and put it in a buffer."
570 (interactive (list (Man-default-man-entry)))
571 (if (or (not man-args)
572 (string= man-args ""))
573 (error "No item under point")
574 (man man-args)))
aa228418 575
98fd7017 576(defun Man-getpage-in-background (topic)
5bbf0b3c 577 "Use TOPIC to build and fire off the manpage and cleaning command."
e660d0db 578 (let* ((man-args topic)
d0aede3f 579 (bufname (concat "*Man " man-args "*"))
effdc6a2 580 (buffer (get-buffer bufname)))
98fd7017 581 (if buffer
effdc6a2 582 (Man-notify-when-ready buffer)
eaf1946c 583 (require 'env)
b3435a2f 584 (message "Invoking %s %s in the background" manual-program man-args)
effdc6a2 585 (setq buffer (generate-new-buffer bufname))
75db9a64
KH
586 (save-excursion
587 (set-buffer buffer)
b3435a2f
FP
588 (setq Man-original-frame (selected-frame))
589 (setq Man-arguments man-args))
fd5733a9 590 (let ((process-environment (copy-sequence process-environment))
cd3b7f95
RS
591 ;; The following is so Awk script gets \n intact
592 ;; But don't prevent decoding of the outside.
593 (coding-system-for-write 'raw-text-unix)
86293583 594 ;; We must decode the output by a coding system that the
9be031e4 595 ;; system's locale suggests in multibyte mode.
a1c5fe60
KH
596 (coding-system-for-read
597 (if default-enable-multibyte-characters
598 locale-coding-system 'raw-text-unix))
fd5733a9
KH
599 ;; Avoid possible error by using a directory that always exists.
600 (default-directory "/"))
82c9fe8e
RS
601 ;; Prevent any attempt to use display terminal fanciness.
602 (setenv "TERM" "dumb")
0020dbcd
EZ
603 (if (fboundp 'start-process)
604 (set-process-sentinel
605 (start-process manual-program buffer "sh" "-c"
606 (format (Man-build-man-command) man-args))
607 'Man-bgproc-sentinel)
608 (progn
609 (let ((exit-status
610 (call-process shell-file-name nil (list buffer nil) nil "-c"
611 (format (Man-build-man-command) man-args)))
612 (msg ""))
613 (or (and (numberp exit-status)
614 (= exit-status 0))
615 (and (numberp exit-status)
616 (setq msg
617 (format "exited abnormally with code %d"
618 exit-status)))
619 (setq msg exit-status))
620 (Man-bgproc-sentinel bufname msg))))))))
effdc6a2
RS
621
622(defun Man-notify-when-ready (man-buffer)
623 "Notify the user when MAN-BUFFER is ready.
799ac634 624See the variable `Man-notify-method' for the different notification behaviors."
c9bf42f9
RS
625 (let ((saved-frame (save-excursion
626 (set-buffer man-buffer)
627 Man-original-frame)))
628 (cond
799ac634 629 ((eq Man-notify-method 'newframe)
b3435a2f
FP
630 ;; Since we run asynchronously, perhaps while Emacs is waiting
631 ;; for input, we must not leave a different buffer current. We
632 ;; can't rely on the editor command loop to reselect the
633 ;; selected window's buffer.
c9bf42f9 634 (save-excursion
42a9dc84
RS
635 (let ((frame (make-frame Man-frame-parameters)))
636 (set-window-buffer (frame-selected-window frame) man-buffer)
bf55e415
EZ
637 (set-window-dedicated-p (frame-selected-window frame) t)
638 (or (display-multi-frame-p frame)
639 (select-frame frame)))))
799ac634 640 ((eq Man-notify-method 'pushy)
b3435a2f 641 (switch-to-buffer man-buffer))
799ac634 642 ((eq Man-notify-method 'bully)
bf55e415 643 (and (frame-live-p saved-frame)
c9bf42f9
RS
644 (select-frame saved-frame))
645 (pop-to-buffer man-buffer)
646 (delete-other-windows))
799ac634 647 ((eq Man-notify-method 'aggressive)
bf55e415 648 (and (frame-live-p saved-frame)
c9bf42f9
RS
649 (select-frame saved-frame))
650 (pop-to-buffer man-buffer))
799ac634 651 ((eq Man-notify-method 'friendly)
bf55e415 652 (and (frame-live-p saved-frame)
c9bf42f9
RS
653 (select-frame saved-frame))
654 (display-buffer man-buffer 'not-this-window))
799ac634 655 ((eq Man-notify-method 'polite)
c9bf42f9 656 (beep)
b3435a2f 657 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 658 ((eq Man-notify-method 'quiet)
b3435a2f 659 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 660 ((or (eq Man-notify-method 'meek)
c9bf42f9
RS
661 t)
662 (message ""))
663 )))
effdc6a2 664
6cb92c3a 665(defun Man-softhyphen-to-minus ()
9f79084c
DL
666 ;; \255 is some kind of dash in Latin-N. Versions of Debian man, at
667 ;; least, emit it even when not in a Latin-N locale.
668 (unless (eq t (compare-strings "latin-" 0 nil
669 current-language-environment 0 6 t))
670 (goto-char (point-min))
671 (let ((str "\255"))
672 (if enable-multibyte-characters
673 (setq str (string-as-multibyte str)))
674 (while (search-forward str nil t) (replace-match "-")))))
6cb92c3a 675
b3435a2f
FP
676(defun Man-fontify-manpage ()
677 "Convert overstriking and underlining to the correct fonts.
678Same for the ANSI bold and normal escape sequences."
679 (interactive)
680 (message "Please wait: making up the %s man page..." Man-arguments)
c3343fcf 681 (goto-char (point-min))
b3435a2f
FP
682 (while (search-forward "\e[1m" nil t)
683 (delete-backward-char 4)
684 (put-text-property (point)
685 (progn (if (search-forward "\e[0m" nil 'move)
686 (delete-backward-char 4))
687 (point))
6e7e47f6 688 'face Man-overstrike-face))
e1ceff3a
KH
689 (if (< (buffer-size) (position-bytes (point-max)))
690 ;; Multibyte characters exist.
691 (progn
692 (goto-char (point-min))
693 (while (search-forward "__\b\b" nil t)
694 (backward-delete-char 4)
695 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
696 (goto-char (point-min))
697 (while (search-forward "\b\b__" nil t)
698 (backward-delete-char 4)
699 (put-text-property (1- (point)) (point) 'face Man-underline-face))))
b3435a2f
FP
700 (goto-char (point-min))
701 (while (search-forward "_\b" nil t)
702 (backward-delete-char 2)
6e7e47f6 703 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
b3435a2f
FP
704 (goto-char (point-min))
705 (while (search-forward "\b_" nil t)
706 (backward-delete-char 2)
6e7e47f6 707 (put-text-property (1- (point)) (point) 'face Man-underline-face))
b3435a2f 708 (goto-char (point-min))
cb581be7 709 (while (re-search-forward "\\(.\\)\\(\b+\\1\\)+" nil t)
6024daef 710 (replace-match "\\1")
6e7e47f6 711 (put-text-property (1- (point)) (point) 'face Man-overstrike-face))
6024daef 712 (goto-char (point-min))
f90531cc
FP
713 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
714 (replace-match "o")
b3435a2f
FP
715 (put-text-property (1- (point)) (point) 'face 'bold))
716 (goto-char (point-min))
f7046d47 717 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
6024daef 718 (replace-match "+")
b3435a2f 719 (put-text-property (1- (point)) (point) 'face 'bold))
6cb92c3a 720 (Man-softhyphen-to-minus)
b3435a2f
FP
721 (message "%s man page made up" Man-arguments))
722
723(defun Man-cleanup-manpage ()
724 "Remove overstriking and underlining from the current buffer."
725 (interactive)
f7046d47
FP
726 (message "Please wait: cleaning up the %s man page..."
727 Man-arguments)
9931e1ba 728 (if (or (interactive-p) (not Man-sed-script))
f7046d47
FP
729 (progn
730 (goto-char (point-min))
731 (while (search-forward "_\b" nil t) (backward-delete-char 2))
732 (goto-char (point-min))
733 (while (search-forward "\b_" nil t) (backward-delete-char 2))
734 (goto-char (point-min))
735 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
736 (replace-match "\\1"))
737 (goto-char (point-min))
738 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
739 (goto-char (point-min))
f90531cc 740 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
f7046d47 741 ))
6024daef 742 (goto-char (point-min))
f7046d47 743 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
6cb92c3a 744 (Man-softhyphen-to-minus)
b3435a2f 745 (message "%s man page cleaned up" Man-arguments))
c3343fcf 746
effdc6a2 747(defun Man-bgproc-sentinel (process msg)
0020dbcd 748 "Manpage background process sentinel.
5bbf0b3c 749When manpage command is run asynchronously, PROCESS is the process
0020dbcd
EZ
750object for the manpage command; when manpage command is run
751synchronously, PROCESS is the name of the buffer where the manpage
752command is run. Second argument MSG is the exit message of the
753manpage command."
754 (let ((Man-buffer (if (stringp process) (get-buffer process)
755 (process-buffer process)))
effdc6a2 756 (delete-buff nil)
8c79b392 757 (err-mess nil))
b3435a2f 758
effdc6a2 759 (if (null (buffer-name Man-buffer)) ;; deleted buffer
0020dbcd
EZ
760 (or (stringp process)
761 (set-process-buffer process nil))
b3435a2f
FP
762
763 (save-excursion
764 (set-buffer Man-buffer)
1d56cc39
RS
765 (let ((case-fold-search nil))
766 (goto-char (point-min))
767 (cond ((or (looking-at "No \\(manual \\)*entry for")
768 (looking-at "[^\n]*: nothing appropriate$"))
769 (setq err-mess (buffer-substring (point)
770 (progn
771 (end-of-line) (point)))
772 delete-buff t))
0020dbcd
EZ
773 ((or (stringp process)
774 (not (and (eq (process-status process) 'exit)
775 (= (process-exit-status process) 0))))
776 (or (zerop (length msg))
777 (progn
778 (setq err-mess
779 (concat (buffer-name Man-buffer)
780 ": process "
781 (let ((eos (1- (length msg))))
782 (if (= (aref msg eos) ?\n)
783 (substring msg 0 eos) msg))))
784 (goto-char (point-max))
785 (insert (format "\nprocess %s" msg))))
786 ))
1223b6c4
RS
787 (if delete-buff
788 (kill-buffer Man-buffer)
789 (if Man-fontify-manpage-flag
790 (Man-fontify-manpage)
791 (Man-cleanup-manpage))
792 (run-hooks 'Man-cooked-hook)
793 (Man-mode)
794 (set-buffer-modified-p nil)
0020dbcd 795 ))
1d56cc39
RS
796 ;; Restore case-fold-search before calling
797 ;; Man-notify-when-ready because it may switch buffers.
798
799 (if (not delete-buff)
800 (Man-notify-when-ready Man-buffer))
801
802 (if err-mess
803 (error err-mess))
804 ))))
effdc6a2
RS
805
806\f
807;; ======================================================================
808;; set up manual mode in buffer and build alists
809
810(defun Man-mode ()
c3343fcf 811 "A mode for browsing Un*x manual pages.
effdc6a2 812
5bbf0b3c 813The following man commands are available in the buffer. Try
effdc6a2 814\"\\[describe-key] <key> RET\" for more information:
aa228418 815
b3435a2f 816\\[man] Prompt to retrieve a new manpage.
effdc6a2
RS
817\\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
818\\[Man-next-manpage] Jump to next manpage in circular list.
819\\[Man-previous-manpage] Jump to previous manpage in circular list.
820\\[Man-next-section] Jump to next manpage section.
821\\[Man-previous-section] Jump to previous manpage section.
822\\[Man-goto-section] Go to a manpage section.
823\\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
b3435a2f
FP
824\\[Man-quit] Deletes the manpage window, bury its buffer.
825\\[Man-kill] Deletes the manpage window, kill its buffer.
effdc6a2
RS
826\\[describe-mode] Prints this help text.
827
5bbf0b3c 828The following variables may be of some use. Try
effdc6a2
RS
829\"\\[describe-variable] <variable-name> RET\" for more information:
830
5bbf0b3c
DL
831`Man-notify-method' What happens when manpage formatting is done.
832`Man-downcase-section-letters-flag' Force section letters to lower case.
833`Man-circular-pages-flag' Treat multiple manpage list as circular.
834`Man-auto-section-alist' List of major modes and their section numbers.
835`Man-section-translations-alist' List of section numbers and their Un*x equiv.
836`Man-filter-list' Background manpage filter command.
837`Man-mode-line-format' Mode line format for Man mode buffers.
838`Man-mode-map' Keymap bindings for Man mode buffers.
839`Man-mode-hook' Normal hook run on entry to Man mode.
840`Man-section-regexp' Regexp describing manpage section letters.
841`Man-heading-regexp' Regexp describing section headers.
842`Man-see-also-regexp' Regexp for SEE ALSO section (or your equiv).
843`Man-first-heading-regexp' Regexp for first heading on a manpage.
844`Man-reference-regexp' Regexp matching a references in SEE ALSO.
845`Man-switches' Background `man' command switches.
effdc6a2
RS
846
847The following key bindings are currently in effect in the buffer:
848\\{Man-mode-map}"
849 (interactive)
850 (setq major-mode 'Man-mode
c3343fcf 851 mode-name "Man"
effdc6a2
RS
852 buffer-auto-save-file-name nil
853 mode-line-format Man-mode-line-format
854 truncate-lines t
855 buffer-read-only t)
856 (buffer-disable-undo (current-buffer))
857 (auto-fill-mode -1)
858 (use-local-map Man-mode-map)
f655106b 859 (set-syntax-table man-mode-syntax-table)
effdc6a2 860 (Man-build-page-list)
b3435a2f
FP
861 (Man-strip-page-headers)
862 (Man-unindent)
526504b8
RS
863 (Man-goto-page 1)
864 (run-hooks 'Man-mode-hook))
1a20f48d 865
b3435a2f 866(defsubst Man-build-section-alist ()
effdc6a2
RS
867 "Build the association list of manpage sections."
868 (setq Man-sections-alist nil)
1a20f48d 869 (goto-char (point-min))
2cd4790e
KH
870 (let ((case-fold-search nil))
871 (while (re-search-forward Man-heading-regexp (point-max) t)
b3435a2f 872 (aput 'Man-sections-alist (Man-match-substring 1))
2cd4790e 873 (forward-line 1))))
effdc6a2 874
b3435a2f 875(defsubst Man-build-references-alist ()
effdc6a2
RS
876 "Build the association list of references (in the SEE ALSO section)."
877 (setq Man-refpages-alist nil)
878 (save-excursion
879 (if (Man-find-section Man-see-also-regexp)
880 (let ((start (progn (forward-line 1) (point)))
881 (end (progn
882 (Man-next-section 1)
883 (point)))
884 hyphenated
885 (runningpoint -1))
2cd4790e
KH
886 (save-restriction
887 (narrow-to-region start end)
888 (goto-char (point-min))
889 (back-to-indentation)
890 (while (and (not (eobp)) (/= (point) runningpoint))
891 (setq runningpoint (point))
b3435a2f
FP
892 (if (re-search-forward Man-reference-regexp end t)
893 (let* ((word (Man-match-substring 0))
894 (len (1- (length word))))
895 (if hyphenated
896 (setq word (concat hyphenated word)
897 hyphenated nil))
898 (if (= (aref word len) ?-)
899 (setq hyphenated (substring word 0 len))
900 (aput 'Man-refpages-alist word))))
2cd4790e 901 (skip-chars-forward " \t\n,")))))))
effdc6a2 902
d0aede3f 903(defun Man-build-page-list ()
effdc6a2
RS
904 "Build the list of separate manpages in the buffer."
905 (setq Man-page-list nil)
b3435a2f
FP
906 (let ((page-start (point-min))
907 (page-end (point-max))
908 (header ""))
909 (goto-char page-start)
910 ;; (switch-to-buffer (current-buffer))(debug)
911 (while (not (eobp))
912 (setq header
913 (if (looking-at Man-page-header-regexp)
914 (Man-match-substring 1)
915 nil))
916 ;; Go past both the current and the next Man-first-heading-regexp
917 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
918 (let ((p (progn (beginning-of-line) (point))))
919 ;; We assume that the page header is delimited by blank
920 ;; lines and that it contains at most one blank line. So
921 ;; if we back by three blank lines we will be sure to be
922 ;; before the page header but not before the possible
923 ;; previous page header.
924 (search-backward "\n\n" nil t 3)
925 (if (re-search-forward Man-page-header-regexp p 'move)
926 (beginning-of-line))))
927 (setq page-end (point))
928 (setq Man-page-list (append Man-page-list
929 (list (list (copy-marker page-start)
930 (copy-marker page-end)
931 header))))
932 (setq page-start page-end)
933 )))
934
d0aede3f 935(defun Man-strip-page-headers ()
b3435a2f
FP
936 "Strip all the page headers but the first from the manpage."
937 (let ((buffer-read-only nil)
938 (case-fold-search nil)
939 (page-list Man-page-list)
940 (page ())
941 (header ""))
942 (while page-list
943 (setq page (car page-list))
944 (and (nth 2 page)
945 (goto-char (car page))
946 (re-search-forward Man-first-heading-regexp nil t)
947 (setq header (buffer-substring (car page) (match-beginning 0)))
948 ;; Since the awk script collapses all successive blank
949 ;; lines into one, and since we don't want to get rid of
950 ;; the fast awk script, one must choose between adding
951 ;; spare blank lines between pages when there were none and
952 ;; deleting blank lines at page boundaries when there were
953 ;; some. We choose the first, so we comment the following
954 ;; line.
955 ;; (setq header (concat "\n" header)))
956 (while (search-forward header (nth 1 page) t)
957 (replace-match "")))
958 (setq page-list (cdr page-list)))))
959
d0aede3f 960(defun Man-unindent ()
b3435a2f
FP
961 "Delete the leading spaces that indent the manpage."
962 (let ((buffer-read-only nil)
963 (case-fold-search nil)
964 (page-list Man-page-list))
965 (while page-list
966 (let ((page (car page-list))
967 (indent "")
968 (nindent 0))
969 (narrow-to-region (car page) (car (cdr page)))
970 (if Man-uses-untabify-flag
971 (untabify (point-min) (point-max)))
972 (if (catch 'unindent
973 (goto-char (point-min))
974 (if (not (re-search-forward Man-first-heading-regexp nil t))
975 (throw 'unindent nil))
976 (beginning-of-line)
977 (setq indent (buffer-substring (point)
978 (progn
979 (skip-chars-forward " ")
980 (point))))
981 (setq nindent (length indent))
982 (if (zerop nindent)
983 (throw 'unindent nil))
984 (setq indent (concat indent "\\|$"))
985 (goto-char (point-min))
986 (while (not (eobp))
987 (if (looking-at indent)
988 (forward-line 1)
989 (throw 'unindent nil)))
990 (goto-char (point-min)))
991 (while (not (eobp))
992 (or (eolp)
993 (delete-char nindent))
994 (forward-line 1)))
995 (setq page-list (cdr page-list))
2cd4790e 996 ))))
effdc6a2
RS
997
998\f
999;; ======================================================================
e660d0db 1000;; Man mode commands
effdc6a2
RS
1001
1002(defun Man-next-section (n)
1003 "Move point to Nth next section (default 1)."
1004 (interactive "p")
2cd4790e
KH
1005 (let ((case-fold-search nil))
1006 (if (looking-at Man-heading-regexp)
1007 (forward-line 1))
1008 (if (re-search-forward Man-heading-regexp (point-max) t n)
1009 (beginning-of-line)
1010 (goto-char (point-max)))))
effdc6a2
RS
1011
1012(defun Man-previous-section (n)
1013 "Move point to Nth previous section (default 1)."
1014 (interactive "p")
2cd4790e
KH
1015 (let ((case-fold-search nil))
1016 (if (looking-at Man-heading-regexp)
1017 (forward-line -1))
1018 (if (re-search-backward Man-heading-regexp (point-min) t n)
1019 (beginning-of-line)
1020 (goto-char (point-min)))))
effdc6a2
RS
1021
1022(defun Man-find-section (section)
1023 "Move point to SECTION if it exists, otherwise don't move point.
1024Returns t if section is found, nil otherwise."
2cd4790e
KH
1025 (let ((curpos (point))
1026 (case-fold-search nil))
effdc6a2 1027 (goto-char (point-min))
b3435a2f 1028 (if (re-search-forward (concat "^" section) (point-max) t)
effdc6a2
RS
1029 (progn (beginning-of-line) t)
1030 (goto-char curpos)
1031 nil)
1032 ))
1033
1034(defun Man-goto-section ()
1035 "Query for section to move point to."
1036 (interactive)
1037 (aput 'Man-sections-alist
1038 (let* ((default (aheadsym Man-sections-alist))
1039 (completion-ignore-case t)
1040 chosen
1041 (prompt (concat "Go to section: (default " default ") ")))
1042 (setq chosen (completing-read prompt Man-sections-alist))
1043 (if (or (not chosen)
1044 (string= chosen ""))
1045 default
1046 chosen)))
1047 (Man-find-section (aheadsym Man-sections-alist)))
1048
1049(defun Man-goto-see-also-section ()
1050 "Move point the the \"SEE ALSO\" section.
c3343fcf 1051Actually the section moved to is described by `Man-see-also-regexp'."
effdc6a2
RS
1052 (interactive)
1053 (if (not (Man-find-section Man-see-also-regexp))
1054 (error (concat "No " Man-see-also-regexp
b3435a2f 1055 " section found in the current manpage"))))
effdc6a2 1056
2151a1cf 1057(defun Man-follow-manual-reference (reference)
effdc6a2 1058 "Get one of the manpages referred to in the \"SEE ALSO\" section.
5bbf0b3c 1059Specify which REFERENCE to use; default is based on word at point."
e660d0db
RS
1060 (interactive
1061 (if (not Man-refpages-alist)
b3435a2f 1062 (error "There are no references in the current man page")
2151a1cf 1063 (list (let* ((default (or
e660d0db
RS
1064 (car (all-completions
1065 (save-excursion
1066 (skip-syntax-backward "w()")
1067 (skip-chars-forward " \t")
1068 (let ((word (current-word)))
1069 ;; strip a trailing '-':
1070 (if (string-match "-$" word)
2cd4790e
KH
1071 (substring word 0
1072 (match-beginning 0))
e660d0db
RS
1073 word)))
1074 Man-refpages-alist))
1075 (aheadsym Man-refpages-alist)))
1076 chosen
1077 (prompt (concat "Refer to: (default " default ") ")))
1078 (setq chosen (completing-read prompt Man-refpages-alist nil t))
1079 (if (or (not chosen)
1080 (string= chosen ""))
1081 default
1082 chosen)))))
effdc6a2 1083 (if (not Man-refpages-alist)
b3435a2f 1084 (error "Can't find any references in the current manpage")
e660d0db 1085 (aput 'Man-refpages-alist reference)
effdc6a2 1086 (Man-getpage-in-background
2151a1cf 1087 (Man-translate-references (aheadsym Man-refpages-alist)))))
effdc6a2 1088
b3435a2f 1089(defun Man-kill ()
effdc6a2
RS
1090 "Kill the buffer containing the manpage."
1091 (interactive)
06cab243 1092 (quit-window t))
b3435a2f
FP
1093
1094(defun Man-quit ()
1095 "Bury the buffer containing the manpage."
1096 (interactive)
06cab243 1097 (quit-window))
effdc6a2
RS
1098
1099(defun Man-goto-page (page)
1100 "Go to the manual page on page PAGE."
1101 (interactive
b3435a2f
FP
1102 (if (not Man-page-list)
1103 (let ((args Man-arguments))
1104 (kill-buffer (current-buffer))
1105 (error "Can't find the %s manpage" args))
1106 (if (= (length Man-page-list) 1)
1107 (error "You're looking at the only manpage in the buffer")
1108 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1109 (length Man-page-list)))))))
1110 (if (not Man-page-list)
1111 (let ((args Man-arguments))
1112 (kill-buffer (current-buffer))
1113 (error "Can't find the %s manpage" args)))
effdc6a2
RS
1114 (if (or (< page 1)
1115 (> page (length Man-page-list)))
1116 (error "No manpage %d found" page))
1117 (let* ((page-range (nth (1- page) Man-page-list))
1118 (page-start (car page-range))
b3435a2f 1119 (page-end (car (cdr page-range))))
effdc6a2 1120 (setq Man-current-page page
b3435a2f 1121 Man-page-mode-string (Man-make-page-mode-string))
effdc6a2
RS
1122 (widen)
1123 (goto-char page-start)
1124 (narrow-to-region page-start page-end)
1125 (Man-build-section-alist)
b3435a2f 1126 (Man-build-references-alist)
effdc6a2
RS
1127 (goto-char (point-min))))
1128
1129
1130(defun Man-next-manpage ()
1131 "Find the next manpage entry in the buffer."
1132 (interactive)
1133 (if (= (length Man-page-list) 1)
9f2863b2 1134 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1135 (if (< Man-current-page (length Man-page-list))
1136 (Man-goto-page (1+ Man-current-page))
b3435a2f 1137 (if Man-circular-pages-flag
effdc6a2 1138 (Man-goto-page 1)
9f2863b2 1139 (error "You're looking at the last manpage in the buffer"))))
effdc6a2
RS
1140
1141(defun Man-previous-manpage ()
1142 "Find the previous manpage entry in the buffer."
1143 (interactive)
1144 (if (= (length Man-page-list) 1)
9f2863b2 1145 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1146 (if (> Man-current-page 1)
1147 (Man-goto-page (1- Man-current-page))
b3435a2f 1148 (if Man-circular-pages-flag
effdc6a2 1149 (Man-goto-page (length Man-page-list))
9f2863b2 1150 (error "You're looking at the first manpage in the buffer"))))
733155db 1151\f
58ffb6ae
RS
1152;; Init the man package variables, if not already done.
1153(Man-init-defvars)
1154
5bbf0b3c
DL
1155(add-to-list 'debug-ignored-errors "^No manpage [0-9]* found$")
1156(add-to-list 'debug-ignored-errors "^Can't find the .* manpage$")
1157
733155db
JB
1158(provide 'man)
1159
6594deb0 1160;;; man.el ends here