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