*** empty log message ***
[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 "\\))")
fb925bd8
EZ
279 "Regular expression describing a reference to another manpage.")
280
281;; This includes the section as an optional part to catch hyphenated
282;; refernces to manpages.
283(defvar Man-hyphenated-reference-regexp
284 (concat "\\(" Man-name-regexp "\\)\\((\\(" Man-section-regexp "\\))\\)?")
6e7e47f6 285 "Regular expression describing a reference in the SEE ALSO section.")
effdc6a2 286
733155db 287(defvar Man-switches ""
6e7e47f6 288 "Switches passed to the man command, as a single string.")
effdc6a2 289
e660d0db
RS
290(defvar Man-specified-section-option
291 (if (string-match "-solaris[0-9.]*$" system-configuration)
292 "-s"
293 "")
6e7e47f6 294 "Option that indicates a specified a manual section name.")
9de0760c 295
effdc6a2
RS
296;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
297;; end user variables
effdc6a2
RS
298\f
299;; other variables and keymap initializations
300(make-variable-buffer-local 'Man-sections-alist)
301(make-variable-buffer-local 'Man-refpages-alist)
302(make-variable-buffer-local 'Man-page-list)
303(make-variable-buffer-local 'Man-current-page)
304(make-variable-buffer-local 'Man-page-mode-string)
75db9a64 305(make-variable-buffer-local 'Man-original-frame)
b3435a2f 306(make-variable-buffer-local 'Man-arguments)
effdc6a2
RS
307
308(setq-default Man-sections-alist nil)
309(setq-default Man-refpages-alist nil)
310(setq-default Man-page-list nil)
311(setq-default Man-current-page 0)
b3435a2f 312(setq-default Man-page-mode-string "1 of 1")
effdc6a2 313
6e7e47f6
FP
314(defconst Man-sysv-sed-script "\
315/\b/ { s/_\b//g
316 s/\b_//g
317 s/o\b+/o/g
f90531cc 318 s/+\bo/o/g
6e7e47f6
FP
319 :ovstrk
320 s/\\(.\\)\b\\1/\\1/g
321 t ovstrk
322 }
323/\e\\[[0-9][0-9]*m/ s///g"
324 "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.")
325
326(defconst Man-berkeley-sed-script "\
327/\b/ { s/_\b//g\\
328 s/\b_//g\\
329 s/o\b+/o/g\\
f90531cc 330 s/+\bo/o/g\\
6e7e47f6
FP
331 :ovstrk\\
332 s/\\(.\\)\b\\1/\\1/g\\
333 t ovstrk\\
334 }\\
335/\e\\[[0-9][0-9]*m/ s///g"
336 "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
337
f655106b
KH
338(defvar man-mode-syntax-table
339 (let ((table (copy-syntax-table (standard-syntax-table))))
340 (modify-syntax-entry ?. "w" table)
341 (modify-syntax-entry ?_ "w" table)
342 table)
343 "Syntax table used in Man mode buffers.")
344
effdc6a2
RS
345(if Man-mode-map
346 nil
347 (setq Man-mode-map (make-keymap))
348 (suppress-keymap Man-mode-map)
349 (define-key Man-mode-map " " 'scroll-up)
350 (define-key Man-mode-map "\177" 'scroll-down)
351 (define-key Man-mode-map "n" 'Man-next-section)
352 (define-key Man-mode-map "p" 'Man-previous-section)
353 (define-key Man-mode-map "\en" 'Man-next-manpage)
354 (define-key Man-mode-map "\ep" 'Man-previous-manpage)
b3435a2f
FP
355 (define-key Man-mode-map ">" 'end-of-buffer)
356 (define-key Man-mode-map "<" 'beginning-of-buffer)
357 (define-key Man-mode-map "." 'beginning-of-buffer)
effdc6a2 358 (define-key Man-mode-map "r" 'Man-follow-manual-reference)
effdc6a2
RS
359 (define-key Man-mode-map "g" 'Man-goto-section)
360 (define-key Man-mode-map "s" 'Man-goto-see-also-section)
b3435a2f 361 (define-key Man-mode-map "k" 'Man-kill)
effdc6a2 362 (define-key Man-mode-map "q" 'Man-quit)
b3435a2f 363 (define-key Man-mode-map "m" 'man)
e7bf8d10 364 (define-key Man-mode-map "\r" 'man-follow)
effdc6a2
RS
365 (define-key Man-mode-map "?" 'describe-mode)
366 )
367
368\f
369;; ======================================================================
370;; utilities
371
58ffb6ae 372(defun Man-init-defvars ()
bf55e415 373 "Used for initialising variables based on display's color support.
5bbf0b3c 374This is necessary if one wants to dump man.el with Emacs."
b3435a2f 375
fd5733a9
KH
376 ;; Avoid possible error in call-process by using a directory that must exist.
377 (let ((default-directory "/"))
378 (setq Man-sed-script
379 (cond
380 (Man-fontify-manpage-flag
381 nil)
382 ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
383 Man-sysv-sed-script)
384 ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
385 Man-berkeley-sed-script)
386 (t
387 nil))))
58ffb6ae
RS
388
389 (setq Man-filter-list
1ac26bf5
AS
390 ;; Avoid trailing nil which confuses customize.
391 (apply 'list
b3435a2f 392 (cons
58ffb6ae
RS
393 Man-sed-command
394 (list
395 (if Man-sed-script
396 (concat "-e '" Man-sed-script "'")
397 "")
398 "-e '/^[\001-\032][\001-\032]*$/d'"
399 "-e '/\e[789]/s///g'"
400 "-e '/Reformatting page. Wait/d'"
401 "-e '/Reformatting entry. Wait/d'"
402 "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
403 "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
404 "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
405 "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
406 "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
407 "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
008d825a 408 "-e '/^[A-Za-z].*Last[ \t]change:/d'"
58ffb6ae
RS
409 "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
410 "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
411 "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
412 ))
413 (cons
414 Man-awk-command
415 (list
416 "'\n"
417 "BEGIN { blankline=0; anonblank=0; }\n"
418 "/^$/ { if (anonblank==0) next; }\n"
419 "{ anonblank=1; }\n"
420 "/^$/ { blankline++; next; }\n"
421 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
422 "'"
423 ))
424 (if (not Man-uses-untabify-flag)
1ac26bf5
AS
425 ;; The outer list will be stripped off by apply.
426 (list (cons
427 Man-untabify-command
428 Man-untabify-command-args))
58ffb6ae 429 )))
b3435a2f 430)
effdc6a2 431
d0aede3f
FP
432(defsubst Man-match-substring (&optional n string)
433 "Return the substring matched by the last search.
434Optional arg N means return the substring matched by the Nth paren
435grouping. Optional second arg STRING means return a substring from
436that string instead of from the current buffer."
437 (if (null n) (setq n 0))
438 (if string
439 (substring string (match-beginning n) (match-end n))
440 (buffer-substring (match-beginning n) (match-end n))))
441
b3435a2f
FP
442(defsubst Man-make-page-mode-string ()
443 "Formats part of the mode line for Man mode."
444 (format "%s page %d of %d"
445 (or (nth 2 (nth (1- Man-current-page) Man-page-list))
446 "")
447 Man-current-page
448 (length Man-page-list)))
449
450(defsubst Man-build-man-command ()
effdc6a2 451 "Builds the entire background manpage and cleaning command."
0020dbcd
EZ
452 (let ((command (concat manual-program " " Man-switches
453 ; Stock MS-DOS shells cannot redirect stderr;
454 ; `call-process' below sends it to /dev/null,
455 ; so we don't need `2>' even with DOS shells
456 ; which do support stderr redirection.
457 (if (not (fboundp 'start-process))
458 " %s"
3945a18a 459 (concat " %s 2>" null-device))))
effdc6a2 460 (flist Man-filter-list))
b3435a2f 461 (while (and flist (car flist))
effdc6a2 462 (let ((pcom (car (car flist)))
b3435a2f
FP
463 (pargs (cdr (car flist))))
464 (setq command
465 (concat command " | " pcom " "
d6373ed5
SM
466 (mapconcat (lambda (phrase)
467 (if (not (stringp phrase))
468 (error "Malformed Man-filter-list"))
469 phrase)
b3435a2f
FP
470 pargs " ")))
471 (setq flist (cdr flist))))
effdc6a2
RS
472 command))
473
effdc6a2 474(defun Man-translate-references (ref)
b3435a2f
FP
475 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
476Leave it as is if already in that style. Possibly downcase and
477translate the section (see the Man-downcase-section-letters-flag
2f2228c0 478and the Man-section-translations-alist variables)."
b3435a2f
FP
479 (let ((name "")
480 (section "")
481 (slist Man-section-translations-alist))
effdc6a2 482 (cond
b3435a2f 483 ;; "chmod(2V)" case ?
2f2228c0 484 ((string-match (concat "^" Man-reference-regexp "$") ref)
b3435a2f
FP
485 (setq name (Man-match-substring 1 ref)
486 section (Man-match-substring 2 ref)))
487 ;; "2v chmod" case ?
2f2228c0 488 ((string-match (concat "^\\(" Man-section-regexp
b3435a2f
FP
489 "\\) +\\(" Man-name-regexp "\\)$") ref)
490 (setq name (Man-match-substring 2 ref)
491 section (Man-match-substring 1 ref))))
492 (if (string= name "")
493 ref ; Return the reference as is
494 (if Man-downcase-section-letters-flag
495 (setq section (downcase section)))
496 (while slist
497 (let ((s1 (car (car slist)))
498 (s2 (cdr (car slist))))
499 (setq slist (cdr slist))
500 (if Man-downcase-section-letters-flag
501 (setq s1 (downcase s1)))
502 (if (not (string= s1 section)) nil
503 (setq section (if Man-downcase-section-letters-flag
504 (downcase s2)
505 s2)
506 slist nil))))
507 (concat Man-specified-section-option section " " name))))
508
effdc6a2
RS
509\f
510;; ======================================================================
b3435a2f 511;; default man entry: get word under point
effdc6a2 512
b3435a2f 513(defsubst Man-default-man-entry ()
effdc6a2 514 "Make a guess at a default manual entry.
af900b23 515This guess is based on the text surrounding the cursor."
f655106b 516 (let (word)
1a20f48d 517 (save-excursion
b3435a2f 518 ;; Default man entry title is any word the cursor is on, or if
f655106b
KH
519 ;; cursor not on a word, then nearest preceding word.
520 (setq word (current-word))
521 (if (string-match "[._]+$" word)
522 (setq word (substring word 0 (match-beginning 0))))
b3435a2f 523 ;; If looking at something like ioctl(2) or brc(1M), include the
c448c134 524 ;; section number in the returned value. Remove text properties.
f655106b
KH
525 (forward-word 1)
526 ;; Use `format' here to clear any text props from `word'.
527 (format "%s%s"
528 word
529 (if (looking-at
530 (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
531 (format "(%s)" (Man-match-substring 1))
532 "")))))
b3435a2f 533
effdc6a2
RS
534\f
535;; ======================================================================
b3435a2f 536;; Top level command and background process sentinel
1a20f48d 537
b3435a2f 538;; For compatibility with older versions.
cac0b95d 539;;;###autoload
b3435a2f 540(defalias 'manual-entry 'man)
cac0b95d 541
effdc6a2 542;;;###autoload
98fd7017 543(defun man (man-args)
effdc6a2 544 "Get a Un*x manual page and put it in a buffer.
c3343fcf 545This command is the top-level command in the man package. It runs a Un*x
effdc6a2 546command to retrieve and clean a manpage in the background and places the
c3343fcf 547results in a Man mode (manpage browsing) buffer. See variable
799ac634 548`Man-notify-method' for what happens when the buffer is ready.
4fbee715
EZ
549If a buffer already exists for this man page, it will display immediately.
550
551To specify a man page from a certain section, type SUBJECT(SECTION) or
552SECTION SUBJECT when prompted for a manual entry."
b3435a2f 553 (interactive
98fd7017
FP
554 (list (let* ((default-entry (Man-default-man-entry))
555 (input (read-string
556 (format "Manual entry%s: "
557 (if (string= default-entry "")
558 ""
559 (format " (default %s)" default-entry))))))
560 (if (string= input "")
561 (if (string= default-entry "")
562 (error "No man args given")
563 default-entry)
564 input))))
b3435a2f 565
b3435a2f
FP
566 ;; Possibly translate the "subject(section)" syntax into the
567 ;; "section subject" syntax and possibly downcase the section.
568 (setq man-args (Man-translate-references man-args))
569
98fd7017 570 (Man-getpage-in-background man-args))
b3435a2f 571
e7bf8d10
KH
572;;;###autoload
573(defun man-follow (man-args)
574 "Get a Un*x manual page of the item under point and put it in a buffer."
575 (interactive (list (Man-default-man-entry)))
576 (if (or (not man-args)
577 (string= man-args ""))
578 (error "No item under point")
579 (man man-args)))
aa228418 580
98fd7017 581(defun Man-getpage-in-background (topic)
5bbf0b3c 582 "Use TOPIC to build and fire off the manpage and cleaning command."
e660d0db 583 (let* ((man-args topic)
d0aede3f 584 (bufname (concat "*Man " man-args "*"))
effdc6a2 585 (buffer (get-buffer bufname)))
98fd7017 586 (if buffer
effdc6a2 587 (Man-notify-when-ready buffer)
eaf1946c 588 (require 'env)
b3435a2f 589 (message "Invoking %s %s in the background" manual-program man-args)
effdc6a2 590 (setq buffer (generate-new-buffer bufname))
75db9a64
KH
591 (save-excursion
592 (set-buffer buffer)
b3435a2f
FP
593 (setq Man-original-frame (selected-frame))
594 (setq Man-arguments man-args))
fd5733a9 595 (let ((process-environment (copy-sequence process-environment))
cd3b7f95
RS
596 ;; The following is so Awk script gets \n intact
597 ;; But don't prevent decoding of the outside.
598 (coding-system-for-write 'raw-text-unix)
86293583 599 ;; We must decode the output by a coding system that the
9be031e4 600 ;; system's locale suggests in multibyte mode.
a1c5fe60
KH
601 (coding-system-for-read
602 (if default-enable-multibyte-characters
603 locale-coding-system 'raw-text-unix))
fd5733a9
KH
604 ;; Avoid possible error by using a directory that always exists.
605 (default-directory "/"))
82c9fe8e
RS
606 ;; Prevent any attempt to use display terminal fanciness.
607 (setenv "TERM" "dumb")
0020dbcd
EZ
608 (if (fboundp 'start-process)
609 (set-process-sentinel
610 (start-process manual-program buffer "sh" "-c"
611 (format (Man-build-man-command) man-args))
612 'Man-bgproc-sentinel)
613 (progn
614 (let ((exit-status
615 (call-process shell-file-name nil (list buffer nil) nil "-c"
616 (format (Man-build-man-command) man-args)))
617 (msg ""))
618 (or (and (numberp exit-status)
619 (= exit-status 0))
620 (and (numberp exit-status)
621 (setq msg
622 (format "exited abnormally with code %d"
623 exit-status)))
624 (setq msg exit-status))
625 (Man-bgproc-sentinel bufname msg))))))))
effdc6a2
RS
626
627(defun Man-notify-when-ready (man-buffer)
628 "Notify the user when MAN-BUFFER is ready.
799ac634 629See the variable `Man-notify-method' for the different notification behaviors."
c9bf42f9
RS
630 (let ((saved-frame (save-excursion
631 (set-buffer man-buffer)
632 Man-original-frame)))
633 (cond
799ac634 634 ((eq Man-notify-method 'newframe)
b3435a2f
FP
635 ;; Since we run asynchronously, perhaps while Emacs is waiting
636 ;; for input, we must not leave a different buffer current. We
637 ;; can't rely on the editor command loop to reselect the
638 ;; selected window's buffer.
c9bf42f9 639 (save-excursion
42a9dc84
RS
640 (let ((frame (make-frame Man-frame-parameters)))
641 (set-window-buffer (frame-selected-window frame) man-buffer)
bf55e415
EZ
642 (set-window-dedicated-p (frame-selected-window frame) t)
643 (or (display-multi-frame-p frame)
644 (select-frame frame)))))
799ac634 645 ((eq Man-notify-method 'pushy)
b3435a2f 646 (switch-to-buffer man-buffer))
799ac634 647 ((eq Man-notify-method 'bully)
bf55e415 648 (and (frame-live-p saved-frame)
c9bf42f9
RS
649 (select-frame saved-frame))
650 (pop-to-buffer man-buffer)
651 (delete-other-windows))
799ac634 652 ((eq Man-notify-method 'aggressive)
bf55e415 653 (and (frame-live-p saved-frame)
c9bf42f9
RS
654 (select-frame saved-frame))
655 (pop-to-buffer man-buffer))
799ac634 656 ((eq Man-notify-method 'friendly)
bf55e415 657 (and (frame-live-p saved-frame)
c9bf42f9
RS
658 (select-frame saved-frame))
659 (display-buffer man-buffer 'not-this-window))
799ac634 660 ((eq Man-notify-method 'polite)
c9bf42f9 661 (beep)
b3435a2f 662 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 663 ((eq Man-notify-method 'quiet)
b3435a2f 664 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
799ac634 665 ((or (eq Man-notify-method 'meek)
c9bf42f9
RS
666 t)
667 (message ""))
668 )))
effdc6a2 669
6cb92c3a 670(defun Man-softhyphen-to-minus ()
9f79084c
DL
671 ;; \255 is some kind of dash in Latin-N. Versions of Debian man, at
672 ;; least, emit it even when not in a Latin-N locale.
673 (unless (eq t (compare-strings "latin-" 0 nil
674 current-language-environment 0 6 t))
675 (goto-char (point-min))
676 (let ((str "\255"))
677 (if enable-multibyte-characters
678 (setq str (string-as-multibyte str)))
679 (while (search-forward str nil t) (replace-match "-")))))
6cb92c3a 680
b3435a2f
FP
681(defun Man-fontify-manpage ()
682 "Convert overstriking and underlining to the correct fonts.
683Same for the ANSI bold and normal escape sequences."
684 (interactive)
685 (message "Please wait: making up the %s man page..." Man-arguments)
c3343fcf 686 (goto-char (point-min))
b3435a2f
FP
687 (while (search-forward "\e[1m" nil t)
688 (delete-backward-char 4)
689 (put-text-property (point)
690 (progn (if (search-forward "\e[0m" nil 'move)
691 (delete-backward-char 4))
692 (point))
6e7e47f6 693 'face Man-overstrike-face))
e1ceff3a
KH
694 (if (< (buffer-size) (position-bytes (point-max)))
695 ;; Multibyte characters exist.
696 (progn
697 (goto-char (point-min))
698 (while (search-forward "__\b\b" nil t)
699 (backward-delete-char 4)
700 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
701 (goto-char (point-min))
702 (while (search-forward "\b\b__" nil t)
703 (backward-delete-char 4)
704 (put-text-property (1- (point)) (point) 'face Man-underline-face))))
b3435a2f
FP
705 (goto-char (point-min))
706 (while (search-forward "_\b" nil t)
707 (backward-delete-char 2)
6e7e47f6 708 (put-text-property (point) (1+ (point)) 'face Man-underline-face))
b3435a2f
FP
709 (goto-char (point-min))
710 (while (search-forward "\b_" nil t)
711 (backward-delete-char 2)
6e7e47f6 712 (put-text-property (1- (point)) (point) 'face Man-underline-face))
b3435a2f 713 (goto-char (point-min))
cb581be7 714 (while (re-search-forward "\\(.\\)\\(\b+\\1\\)+" nil t)
6024daef 715 (replace-match "\\1")
6e7e47f6 716 (put-text-property (1- (point)) (point) 'face Man-overstrike-face))
6024daef 717 (goto-char (point-min))
f90531cc
FP
718 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
719 (replace-match "o")
b3435a2f
FP
720 (put-text-property (1- (point)) (point) 'face 'bold))
721 (goto-char (point-min))
f7046d47 722 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
6024daef 723 (replace-match "+")
b3435a2f 724 (put-text-property (1- (point)) (point) 'face 'bold))
6cb92c3a 725 (Man-softhyphen-to-minus)
b3435a2f
FP
726 (message "%s man page made up" Man-arguments))
727
728(defun Man-cleanup-manpage ()
729 "Remove overstriking and underlining from the current buffer."
730 (interactive)
f7046d47
FP
731 (message "Please wait: cleaning up the %s man page..."
732 Man-arguments)
9931e1ba 733 (if (or (interactive-p) (not Man-sed-script))
f7046d47
FP
734 (progn
735 (goto-char (point-min))
736 (while (search-forward "_\b" nil t) (backward-delete-char 2))
737 (goto-char (point-min))
738 (while (search-forward "\b_" nil t) (backward-delete-char 2))
739 (goto-char (point-min))
740 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
741 (replace-match "\\1"))
742 (goto-char (point-min))
743 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
744 (goto-char (point-min))
f90531cc 745 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
f7046d47 746 ))
6024daef 747 (goto-char (point-min))
f7046d47 748 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
6cb92c3a 749 (Man-softhyphen-to-minus)
b3435a2f 750 (message "%s man page cleaned up" Man-arguments))
c3343fcf 751
effdc6a2 752(defun Man-bgproc-sentinel (process msg)
0020dbcd 753 "Manpage background process sentinel.
5bbf0b3c 754When manpage command is run asynchronously, PROCESS is the process
0020dbcd
EZ
755object for the manpage command; when manpage command is run
756synchronously, PROCESS is the name of the buffer where the manpage
757command is run. Second argument MSG is the exit message of the
758manpage command."
759 (let ((Man-buffer (if (stringp process) (get-buffer process)
760 (process-buffer process)))
effdc6a2 761 (delete-buff nil)
8c79b392 762 (err-mess nil))
b3435a2f 763
effdc6a2 764 (if (null (buffer-name Man-buffer)) ;; deleted buffer
0020dbcd
EZ
765 (or (stringp process)
766 (set-process-buffer process nil))
b3435a2f
FP
767
768 (save-excursion
769 (set-buffer Man-buffer)
1d56cc39
RS
770 (let ((case-fold-search nil))
771 (goto-char (point-min))
772 (cond ((or (looking-at "No \\(manual \\)*entry for")
773 (looking-at "[^\n]*: nothing appropriate$"))
774 (setq err-mess (buffer-substring (point)
775 (progn
776 (end-of-line) (point)))
777 delete-buff t))
0020dbcd
EZ
778 ((or (stringp process)
779 (not (and (eq (process-status process) 'exit)
780 (= (process-exit-status process) 0))))
781 (or (zerop (length msg))
782 (progn
783 (setq err-mess
784 (concat (buffer-name Man-buffer)
785 ": process "
786 (let ((eos (1- (length msg))))
787 (if (= (aref msg eos) ?\n)
788 (substring msg 0 eos) msg))))
789 (goto-char (point-max))
790 (insert (format "\nprocess %s" msg))))
791 ))
1223b6c4
RS
792 (if delete-buff
793 (kill-buffer Man-buffer)
794 (if Man-fontify-manpage-flag
795 (Man-fontify-manpage)
796 (Man-cleanup-manpage))
797 (run-hooks 'Man-cooked-hook)
798 (Man-mode)
799 (set-buffer-modified-p nil)
0020dbcd 800 ))
1d56cc39
RS
801 ;; Restore case-fold-search before calling
802 ;; Man-notify-when-ready because it may switch buffers.
803
804 (if (not delete-buff)
805 (Man-notify-when-ready Man-buffer))
806
807 (if err-mess
808 (error err-mess))
809 ))))
effdc6a2
RS
810
811\f
812;; ======================================================================
813;; set up manual mode in buffer and build alists
814
815(defun Man-mode ()
c3343fcf 816 "A mode for browsing Un*x manual pages.
effdc6a2 817
5bbf0b3c 818The following man commands are available in the buffer. Try
effdc6a2 819\"\\[describe-key] <key> RET\" for more information:
aa228418 820
b3435a2f 821\\[man] Prompt to retrieve a new manpage.
effdc6a2
RS
822\\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
823\\[Man-next-manpage] Jump to next manpage in circular list.
824\\[Man-previous-manpage] Jump to previous manpage in circular list.
825\\[Man-next-section] Jump to next manpage section.
826\\[Man-previous-section] Jump to previous manpage section.
827\\[Man-goto-section] Go to a manpage section.
828\\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
b3435a2f
FP
829\\[Man-quit] Deletes the manpage window, bury its buffer.
830\\[Man-kill] Deletes the manpage window, kill its buffer.
effdc6a2
RS
831\\[describe-mode] Prints this help text.
832
5bbf0b3c 833The following variables may be of some use. Try
effdc6a2
RS
834\"\\[describe-variable] <variable-name> RET\" for more information:
835
5bbf0b3c
DL
836`Man-notify-method' What happens when manpage formatting is done.
837`Man-downcase-section-letters-flag' Force section letters to lower case.
838`Man-circular-pages-flag' Treat multiple manpage list as circular.
5bbf0b3c
DL
839`Man-section-translations-alist' List of section numbers and their Un*x equiv.
840`Man-filter-list' Background manpage filter command.
841`Man-mode-line-format' Mode line format for Man mode buffers.
842`Man-mode-map' Keymap bindings for Man mode buffers.
843`Man-mode-hook' Normal hook run on entry to Man mode.
844`Man-section-regexp' Regexp describing manpage section letters.
845`Man-heading-regexp' Regexp describing section headers.
846`Man-see-also-regexp' Regexp for SEE ALSO section (or your equiv).
847`Man-first-heading-regexp' Regexp for first heading on a manpage.
848`Man-reference-regexp' Regexp matching a references in SEE ALSO.
849`Man-switches' Background `man' command switches.
effdc6a2
RS
850
851The following key bindings are currently in effect in the buffer:
852\\{Man-mode-map}"
853 (interactive)
854 (setq major-mode 'Man-mode
c3343fcf 855 mode-name "Man"
effdc6a2
RS
856 buffer-auto-save-file-name nil
857 mode-line-format Man-mode-line-format
858 truncate-lines t
859 buffer-read-only t)
860 (buffer-disable-undo (current-buffer))
861 (auto-fill-mode -1)
862 (use-local-map Man-mode-map)
f655106b 863 (set-syntax-table man-mode-syntax-table)
effdc6a2 864 (Man-build-page-list)
b3435a2f
FP
865 (Man-strip-page-headers)
866 (Man-unindent)
526504b8
RS
867 (Man-goto-page 1)
868 (run-hooks 'Man-mode-hook))
1a20f48d 869
b3435a2f 870(defsubst Man-build-section-alist ()
effdc6a2
RS
871 "Build the association list of manpage sections."
872 (setq Man-sections-alist nil)
1a20f48d 873 (goto-char (point-min))
2cd4790e
KH
874 (let ((case-fold-search nil))
875 (while (re-search-forward Man-heading-regexp (point-max) t)
b3435a2f 876 (aput 'Man-sections-alist (Man-match-substring 1))
2cd4790e 877 (forward-line 1))))
effdc6a2 878
b3435a2f 879(defsubst Man-build-references-alist ()
effdc6a2
RS
880 "Build the association list of references (in the SEE ALSO section)."
881 (setq Man-refpages-alist nil)
882 (save-excursion
883 (if (Man-find-section Man-see-also-regexp)
884 (let ((start (progn (forward-line 1) (point)))
885 (end (progn
886 (Man-next-section 1)
887 (point)))
888 hyphenated
889 (runningpoint -1))
2cd4790e
KH
890 (save-restriction
891 (narrow-to-region start end)
892 (goto-char (point-min))
893 (back-to-indentation)
894 (while (and (not (eobp)) (/= (point) runningpoint))
895 (setq runningpoint (point))
fb925bd8 896 (if (re-search-forward Man-hyphenated-reference-regexp end t)
b3435a2f
FP
897 (let* ((word (Man-match-substring 0))
898 (len (1- (length word))))
899 (if hyphenated
900 (setq word (concat hyphenated word)
fb925bd8
EZ
901 hyphenated nil
902 ;; Update len, in case a reference spans
903 ;; more than two lines (paranoia).
904 len (1- (length word))))
b3435a2f 905 (if (= (aref word len) ?-)
fb925bd8
EZ
906 (setq hyphenated (substring word 0 len)))
907 (if (string-match Man-reference-regexp word)
908 (aput 'Man-refpages-alist word))))
909 (skip-chars-forward " \t\n,"))))))
910 (setq Man-refpages-alist (nreverse Man-refpages-alist)))
effdc6a2 911
d0aede3f 912(defun Man-build-page-list ()
effdc6a2
RS
913 "Build the list of separate manpages in the buffer."
914 (setq Man-page-list nil)
b3435a2f
FP
915 (let ((page-start (point-min))
916 (page-end (point-max))
917 (header ""))
918 (goto-char page-start)
919 ;; (switch-to-buffer (current-buffer))(debug)
920 (while (not (eobp))
921 (setq header
922 (if (looking-at Man-page-header-regexp)
923 (Man-match-substring 1)
924 nil))
925 ;; Go past both the current and the next Man-first-heading-regexp
926 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
927 (let ((p (progn (beginning-of-line) (point))))
928 ;; We assume that the page header is delimited by blank
929 ;; lines and that it contains at most one blank line. So
930 ;; if we back by three blank lines we will be sure to be
931 ;; before the page header but not before the possible
932 ;; previous page header.
933 (search-backward "\n\n" nil t 3)
934 (if (re-search-forward Man-page-header-regexp p 'move)
935 (beginning-of-line))))
936 (setq page-end (point))
937 (setq Man-page-list (append Man-page-list
938 (list (list (copy-marker page-start)
939 (copy-marker page-end)
940 header))))
941 (setq page-start page-end)
942 )))
943
d0aede3f 944(defun Man-strip-page-headers ()
b3435a2f
FP
945 "Strip all the page headers but the first from the manpage."
946 (let ((buffer-read-only nil)
947 (case-fold-search nil)
948 (page-list Man-page-list)
949 (page ())
950 (header ""))
951 (while page-list
952 (setq page (car page-list))
953 (and (nth 2 page)
954 (goto-char (car page))
955 (re-search-forward Man-first-heading-regexp nil t)
956 (setq header (buffer-substring (car page) (match-beginning 0)))
957 ;; Since the awk script collapses all successive blank
958 ;; lines into one, and since we don't want to get rid of
959 ;; the fast awk script, one must choose between adding
960 ;; spare blank lines between pages when there were none and
961 ;; deleting blank lines at page boundaries when there were
962 ;; some. We choose the first, so we comment the following
963 ;; line.
964 ;; (setq header (concat "\n" header)))
965 (while (search-forward header (nth 1 page) t)
966 (replace-match "")))
967 (setq page-list (cdr page-list)))))
968
d0aede3f 969(defun Man-unindent ()
b3435a2f
FP
970 "Delete the leading spaces that indent the manpage."
971 (let ((buffer-read-only nil)
972 (case-fold-search nil)
973 (page-list Man-page-list))
974 (while page-list
975 (let ((page (car page-list))
976 (indent "")
977 (nindent 0))
978 (narrow-to-region (car page) (car (cdr page)))
979 (if Man-uses-untabify-flag
980 (untabify (point-min) (point-max)))
981 (if (catch 'unindent
982 (goto-char (point-min))
983 (if (not (re-search-forward Man-first-heading-regexp nil t))
984 (throw 'unindent nil))
985 (beginning-of-line)
986 (setq indent (buffer-substring (point)
987 (progn
988 (skip-chars-forward " ")
989 (point))))
990 (setq nindent (length indent))
991 (if (zerop nindent)
992 (throw 'unindent nil))
993 (setq indent (concat indent "\\|$"))
994 (goto-char (point-min))
995 (while (not (eobp))
996 (if (looking-at indent)
997 (forward-line 1)
998 (throw 'unindent nil)))
999 (goto-char (point-min)))
1000 (while (not (eobp))
1001 (or (eolp)
1002 (delete-char nindent))
1003 (forward-line 1)))
1004 (setq page-list (cdr page-list))
2cd4790e 1005 ))))
effdc6a2
RS
1006
1007\f
1008;; ======================================================================
e660d0db 1009;; Man mode commands
effdc6a2
RS
1010
1011(defun Man-next-section (n)
1012 "Move point to Nth next section (default 1)."
1013 (interactive "p")
2cd4790e
KH
1014 (let ((case-fold-search nil))
1015 (if (looking-at Man-heading-regexp)
1016 (forward-line 1))
1017 (if (re-search-forward Man-heading-regexp (point-max) t n)
1018 (beginning-of-line)
1019 (goto-char (point-max)))))
effdc6a2
RS
1020
1021(defun Man-previous-section (n)
1022 "Move point to Nth previous section (default 1)."
1023 (interactive "p")
2cd4790e
KH
1024 (let ((case-fold-search nil))
1025 (if (looking-at Man-heading-regexp)
1026 (forward-line -1))
1027 (if (re-search-backward Man-heading-regexp (point-min) t n)
1028 (beginning-of-line)
1029 (goto-char (point-min)))))
effdc6a2
RS
1030
1031(defun Man-find-section (section)
1032 "Move point to SECTION if it exists, otherwise don't move point.
1033Returns t if section is found, nil otherwise."
2cd4790e
KH
1034 (let ((curpos (point))
1035 (case-fold-search nil))
effdc6a2 1036 (goto-char (point-min))
b3435a2f 1037 (if (re-search-forward (concat "^" section) (point-max) t)
effdc6a2
RS
1038 (progn (beginning-of-line) t)
1039 (goto-char curpos)
1040 nil)
1041 ))
1042
1043(defun Man-goto-section ()
1044 "Query for section to move point to."
1045 (interactive)
1046 (aput 'Man-sections-alist
1047 (let* ((default (aheadsym Man-sections-alist))
1048 (completion-ignore-case t)
1049 chosen
1050 (prompt (concat "Go to section: (default " default ") ")))
1051 (setq chosen (completing-read prompt Man-sections-alist))
1052 (if (or (not chosen)
1053 (string= chosen ""))
1054 default
1055 chosen)))
1056 (Man-find-section (aheadsym Man-sections-alist)))
1057
1058(defun Man-goto-see-also-section ()
1059 "Move point the the \"SEE ALSO\" section.
c3343fcf 1060Actually the section moved to is described by `Man-see-also-regexp'."
effdc6a2
RS
1061 (interactive)
1062 (if (not (Man-find-section Man-see-also-regexp))
1063 (error (concat "No " Man-see-also-regexp
b3435a2f 1064 " section found in the current manpage"))))
effdc6a2 1065
fb925bd8
EZ
1066(defun Man-possibly-hyphenated-word ()
1067 "Return a possibly hyphenated word at point.
1068If the word starts at the first non-whitespace column, and the
1069previous line ends with a hyphen, return the last word on the previous
1070line instead. Thus, if a reference to \"tcgetpgrp(3V)\" is hyphenated
1071as \"tcgetp-grp(3V)\", and point is at \"grp(3V)\", we return
1072\"tcgetp-\" instead of \"grp\"."
1073 (save-excursion
1074 (skip-syntax-backward "w()")
1075 (skip-chars-forward " \t")
1076 (let ((beg (point))
1077 (word (current-word)))
1078 (when (eq beg (save-excursion
1079 (back-to-indentation)
1080 (point)))
1081 (end-of-line 0)
1082 (if (eq (char-before) ?-)
1083 (setq word (current-word))))
1084 word)))
1085
2151a1cf 1086(defun Man-follow-manual-reference (reference)
effdc6a2 1087 "Get one of the manpages referred to in the \"SEE ALSO\" section.
5bbf0b3c 1088Specify which REFERENCE to use; default is based on word at point."
e660d0db
RS
1089 (interactive
1090 (if (not Man-refpages-alist)
b3435a2f 1091 (error "There are no references in the current man page")
2151a1cf 1092 (list (let* ((default (or
fb925bd8
EZ
1093 (car (all-completions
1094 (let ((word (Man-possibly-hyphenated-word)))
1095 ;; strip a trailing '-':
1096 (if (string-match "-$" word)
1097 (substring word 0
1098 (match-beginning 0))
1099 word))
1100 Man-refpages-alist))
1101 (aheadsym Man-refpages-alist)))
e660d0db
RS
1102 chosen
1103 (prompt (concat "Refer to: (default " default ") ")))
1104 (setq chosen (completing-read prompt Man-refpages-alist nil t))
1105 (if (or (not chosen)
1106 (string= chosen ""))
1107 default
1108 chosen)))))
effdc6a2 1109 (if (not Man-refpages-alist)
b3435a2f 1110 (error "Can't find any references in the current manpage")
e660d0db 1111 (aput 'Man-refpages-alist reference)
effdc6a2 1112 (Man-getpage-in-background
2151a1cf 1113 (Man-translate-references (aheadsym Man-refpages-alist)))))
effdc6a2 1114
b3435a2f 1115(defun Man-kill ()
effdc6a2
RS
1116 "Kill the buffer containing the manpage."
1117 (interactive)
06cab243 1118 (quit-window t))
b3435a2f
FP
1119
1120(defun Man-quit ()
1121 "Bury the buffer containing the manpage."
1122 (interactive)
06cab243 1123 (quit-window))
effdc6a2
RS
1124
1125(defun Man-goto-page (page)
1126 "Go to the manual page on page PAGE."
1127 (interactive
b3435a2f
FP
1128 (if (not Man-page-list)
1129 (let ((args Man-arguments))
1130 (kill-buffer (current-buffer))
1131 (error "Can't find the %s manpage" args))
1132 (if (= (length Man-page-list) 1)
1133 (error "You're looking at the only manpage in the buffer")
1134 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1135 (length Man-page-list)))))))
1136 (if (not Man-page-list)
1137 (let ((args Man-arguments))
1138 (kill-buffer (current-buffer))
1139 (error "Can't find the %s manpage" args)))
effdc6a2
RS
1140 (if (or (< page 1)
1141 (> page (length Man-page-list)))
1142 (error "No manpage %d found" page))
1143 (let* ((page-range (nth (1- page) Man-page-list))
1144 (page-start (car page-range))
b3435a2f 1145 (page-end (car (cdr page-range))))
effdc6a2 1146 (setq Man-current-page page
b3435a2f 1147 Man-page-mode-string (Man-make-page-mode-string))
effdc6a2
RS
1148 (widen)
1149 (goto-char page-start)
1150 (narrow-to-region page-start page-end)
1151 (Man-build-section-alist)
b3435a2f 1152 (Man-build-references-alist)
effdc6a2
RS
1153 (goto-char (point-min))))
1154
1155
1156(defun Man-next-manpage ()
1157 "Find the next manpage entry in the buffer."
1158 (interactive)
1159 (if (= (length Man-page-list) 1)
9f2863b2 1160 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1161 (if (< Man-current-page (length Man-page-list))
1162 (Man-goto-page (1+ Man-current-page))
b3435a2f 1163 (if Man-circular-pages-flag
effdc6a2 1164 (Man-goto-page 1)
9f2863b2 1165 (error "You're looking at the last manpage in the buffer"))))
effdc6a2
RS
1166
1167(defun Man-previous-manpage ()
1168 "Find the previous manpage entry in the buffer."
1169 (interactive)
1170 (if (= (length Man-page-list) 1)
9f2863b2 1171 (error "This is the only manpage in the buffer"))
effdc6a2
RS
1172 (if (> Man-current-page 1)
1173 (Man-goto-page (1- Man-current-page))
b3435a2f 1174 (if Man-circular-pages-flag
effdc6a2 1175 (Man-goto-page (length Man-page-list))
9f2863b2 1176 (error "You're looking at the first manpage in the buffer"))))
733155db 1177\f
58ffb6ae
RS
1178;; Init the man package variables, if not already done.
1179(Man-init-defvars)
1180
5bbf0b3c
DL
1181(add-to-list 'debug-ignored-errors "^No manpage [0-9]* found$")
1182(add-to-list 'debug-ignored-errors "^Can't find the .* manpage$")
1183
733155db
JB
1184(provide 'man)
1185
6594deb0 1186;;; man.el ends here