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