simplify cpp usage in wait_reading_process_output
[bpt/emacs.git] / lisp / man.el
CommitLineData
327a6cca 1;;; man.el --- browse UNIX manual pages -*- coding: utf-8 -*-
55535639 2
1d75432d 3;; Copyright (C) 1993-1994, 1996-1997, 2001-2014 Free Software Foundation, Inc.
55535639
PJ
4
5;; Author: Barry A. Warsaw <bwarsaw@cen.com>
34dc21db 6;; Maintainer: emacs-devel@gnu.org
55535639
PJ
7;; Keywords: help
8;; Adapted-By: ESR, pot
9
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
55535639 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
55535639
PJ
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
55535639
PJ
24
25;;; Commentary:
26
27;; This code provides a function, `man', with which you can browse
28;; UNIX manual pages. Formatting is done in background so that you
29;; can continue to use your Emacs while processing is going on.
30;;
31;; The mode also supports hypertext-like following of manual page SEE
32;; ALSO references, and other features. See below or do `?' in a
33;; manual page buffer for details.
34
35;; ========== Credits and History ==========
36;; In mid 1991, several people posted some interesting improvements to
a88459cd 37;; man.el from the standard Emacs 18.57 distribution. I liked many of
55535639
PJ
38;; these, but wanted everything in one single package, so I decided
39;; to incorporate them into a single manual browsing mode. While
40;; much of the code here has been rewritten, and some features added,
41;; these folks deserve lots of credit for providing the initial
42;; excellent packages on which this one is based.
43
44;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice
45;; improvement which retrieved and cleaned the manpages in a
46;; background process, and which correctly deciphered such options as
47;; man -k.
48
49;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which
50;; provided a very nice manual browsing mode.
51
52;; This package was available as `superman.el' from the LCD package
53;; for some time before it was accepted into Emacs 19. The entry
54;; point and some other names have been changed to make it a drop-in
55;; replacement for the old man.el package.
56
8c106d17 57;; Francesco Potortì <pot@cnuce.cnr.it> cleaned it up thoroughly,
55535639
PJ
58;; making it faster, more robust and more tolerant of different
59;; systems' man idiosyncrasies.
60
61;; ========== Features ==========
62;; + Runs "man" in the background and pipes the results through a
63;; series of sed and awk scripts so that all retrieving and cleaning
4cb071a4 64;; is done in the background. The cleaning commands are configurable.
55535639
PJ
65;; + Syntax is the same as Un*x man
66;; + Functionality is the same as Un*x man, including "man -k" and
67;; "man <section>", etc.
68;; + Provides a manual browsing mode with keybindings for traversing
69;; the sections of a manpage, following references in the SEE ALSO
70;; section, and more.
71;; + Multiple manpages created with the same man command are put into
72;; a narrowed buffer circular list.
73
74;; ============= TODO ===========
75;; - Add a command for printing.
fffa137c 76;; - The awk script deletes multiple blank lines. This behavior does
55535639
PJ
77;; not allow to understand if there was indeed a blank line at the
78;; end or beginning of a page (after the header, or before the
79;; footer). A different algorithm should be used. It is easy to
80;; compute how many blank lines there are before and after the page
81;; headers, and after the page footer. But it is possible to compute
72397ff1 82;; the number of blank lines before the page footer by heuristics
55535639
PJ
83;; only. Is it worth doing?
84;; - Allow a user option to mean that all the manpages should go in
85;; the same buffer, where they can be browsed with M-n and M-p.
55535639
PJ
86
87\f
88;;; Code:
89
456e62c2 90(require 'ansi-color)
ca7e59d4 91(require 'cl-lib)
4edd9faf 92(require 'button)
55535639 93
55535639
PJ
94(defgroup man nil
95 "Browse UNIX manual pages."
96 :prefix "Man-"
ff90f4b0 97 :group 'external
55535639
PJ
98 :group 'help)
99
55535639 100(defvar Man-notify)
dee4ef93 101
55535639 102(defcustom Man-filter-list nil
9201cc28 103 "Manpage cleaning filter command phrases.
55535639
PJ
104This variable contains a list of the following form:
105
106'((command-string phrase-string*)*)
107
108Each phrase-string is concatenated onto the command-string to form a
109command filter. The (standard) output (and standard error) of the Un*x
110man command is piped through each command filter in the order the
111commands appear in the association list. The final output is placed in
112the manpage buffer."
113 :type '(repeat (list (string :tag "Command String")
114 (repeat :inline t
115 (string :tag "Phrase String"))))
116 :group 'man)
117
55535639
PJ
118(defvar Man-uses-untabify-flag t
119 "Non-nil means use `untabify' instead of `Man-untabify-command'.")
55535639
PJ
120(defvar Man-sed-script nil
121 "Script for sed to nuke backspaces and ANSI codes from manpages.")
122
55535639 123(defcustom Man-fontify-manpage-flag t
a88459cd 124 "Non-nil means make up the manpage with fonts."
55535639
PJ
125 :type 'boolean
126 :group 'man)
127
456e62c2
WJ
128(defface Man-overstrike
129 '((t (:inherit bold)))
a88459cd 130 "Face to use when fontifying overstrike."
456e62c2 131 :group 'man
2a1e2476 132 :version "24.3")
55535639 133
456e62c2
WJ
134(defface Man-underline
135 '((t (:inherit underline)))
a88459cd 136 "Face to use when fontifying underlining."
456e62c2 137 :group 'man
2a1e2476 138 :version "24.3")
55535639 139
456e62c2
WJ
140(defface Man-reverse
141 '((t (:inherit highlight)))
a88459cd 142 "Face to use when fontifying reverse video."
456e62c2 143 :group 'man
2a1e2476 144 :version "24.3")
456e62c2
WJ
145
146(defvar Man-ansi-color-map (let ((ansi-color-faces-vector
147 [ default Man-overstrike default Man-underline
148 Man-underline default default Man-reverse ]))
149 (ansi-color-make-color-map))
150 "The value used here for `ansi-color-map'.")
079c2d00 151
55535639
PJ
152;; Use the value of the obsolete user option Man-notify, if set.
153(defcustom Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly)
a88459cd 154 "Selects the behavior when manpage is ready.
55535639
PJ
155This variable may have one of the following values, where (sf) means
156that the frames are switched, so the manpage is displayed in the frame
157where the man command was called from:
158
159newframe -- put the manpage in its own frame (see `Man-frame-parameters')
160pushy -- make the manpage the current buffer in the current window
161bully -- make the manpage the current buffer and only window (sf)
162aggressive -- make the manpage the current buffer in the other window (sf)
163friendly -- display manpage in the other window but don't make current (sf)
164polite -- don't display manpage, but prints message and beep when ready
165quiet -- like `polite', but don't beep
166meek -- make no indication that the manpage is ready
167
168Any other value of `Man-notify-method' is equivalent to `meek'."
169 :type '(radio (const newframe) (const pushy) (const bully)
170 (const aggressive) (const friendly)
171 (const polite) (const quiet) (const meek))
172 :group 'man)
173
aec2bd36 174(defcustom Man-width nil
a88459cd 175 "Number of columns for which manual pages should be formatted.
aec2bd36
JL
176If nil, the width of the window selected at the moment of man
177invocation is used. If non-nil, the width of the frame selected
178at the moment of man invocation is used. The value also can be a
179positive integer."
180 :type '(choice (const :tag "Window width" nil)
181 (const :tag "Frame width" t)
182 (integer :tag "Specific width" :value 65))
183 :group 'man)
184
55535639 185(defcustom Man-frame-parameters nil
a88459cd 186 "Frame parameter list for creating a new frame for a manual page."
55535639
PJ
187 :type 'sexp
188 :group 'man)
189
190(defcustom Man-downcase-section-letters-flag t
a88459cd 191 "Non-nil means letters in sections are converted to lower case.
55535639
PJ
192Some Un*x man commands can't handle uppercase letters in sections, for
193example \"man 2V chmod\", but they are often displayed in the manpage
194with the upper case letter. When this variable is t, the section
195letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before
196being sent to the man background process."
197 :type 'boolean
198 :group 'man)
199
200(defcustom Man-circular-pages-flag t
a88459cd 201 "Non-nil means the manpage list is treated as circular for traversal."
55535639
PJ
202 :type 'boolean
203 :group 'man)
204
205(defcustom Man-section-translations-alist
206 (list
207 '("3C++" . "3")
208 ;; Some systems have a real 3x man section, so let's comment this.
209 ;; '("3X" . "3") ; Xlib man pages
210 '("3X11" . "3")
211 '("1-UCB" . ""))
a88459cd 212 "Association list of bogus sections to real section numbers.
55535639
PJ
213Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in
214their references which Un*x `man' does not recognize. This
215association list is used to translate those sections, when found, to
216the associated section number."
217 :type '(repeat (cons (string :tag "Bogus Section")
218 (string :tag "Real Section")))
219 :group 'man)
220
ac2eceee 221;; FIXME see comments at ffap-c-path.
4edd9faf 222(defcustom Man-header-file-path
ac2eceee
GM
223 (let ((arch (with-temp-buffer
224 (when (eq 0 (ignore-errors
225 (call-process "gcc" nil '(t nil) nil
226 "-print-multiarch")))
227 (goto-char (point-min))
228 (buffer-substring (point) (line-end-position)))))
229 (base '("/usr/include" "/usr/local/include")))
230 (if (zerop (length arch))
231 base
232 (append base (list (expand-file-name arch "/usr/include")))))
4edd9faf 233 "C Header file search path used in Man."
ac2eceee 234 :version "24.1" ; add multiarch
4edd9faf
JB
235 :type '(repeat string)
236 :group 'man)
237
398a825b
SM
238(defcustom Man-name-local-regexp (concat "^" (regexp-opt '("NOM" "NAME")) "$")
239 "Regexp that matches the text that precedes the command's name.
45be326a 240Used in `bookmark-set' to get the default bookmark name."
2bed3f04 241 :version "24.1"
45be326a
TV
242 :type 'string :group 'bookmark)
243
dee4ef93
CY
244(defcustom manual-program "man"
245 "Program used by `man' to produce man pages."
246 :type 'string
247 :group 'man)
55535639 248
dee4ef93
CY
249(defcustom Man-untabify-command "pr"
250 "Program used by `man' for untabifying."
251 :type 'string
252 :group 'man)
55535639 253
dee4ef93
CY
254(defcustom Man-untabify-command-args (list "-t" "-e")
255 "List of arguments to be passed to `Man-untabify-command' (which see)."
256 :type '(repeat string)
257 :group 'man)
55535639 258
dee4ef93
CY
259(defcustom Man-sed-command "sed"
260 "Program used by `man' to process sed scripts."
261 :type 'string
262 :group 'man)
55535639 263
dee4ef93
CY
264(defcustom Man-awk-command "awk"
265 "Program used by `man' to process awk scripts."
266 :type 'string
267 :group 'man)
55535639 268
dee4ef93
CY
269(defcustom Man-mode-hook nil
270 "Hook run when Man mode is enabled."
271 :type 'hook
272 :group 'man)
55535639 273
dee4ef93
CY
274(defcustom Man-cooked-hook nil
275 "Hook run after removing backspaces but before `Man-mode' processing."
276 :type 'hook
277 :group 'man)
55535639 278
327a6cca 279(defvar Man-name-regexp "[-a-zA-Z0-9_­+][-a-zA-Z0-9_.:­+]*"
55535639
PJ
280 "Regular expression describing the name of a manpage (without section).")
281
19437ce5 282(defvar Man-section-regexp "[0-9][a-zA-Z0-9+]*\\|[LNln]"
55535639
PJ
283 "Regular expression describing a manpage section within parentheses.")
284
285(defvar Man-page-header-regexp
a1de6c6a 286 (if (string-match "-solaris2\\." system-configuration)
55535639
PJ
287 (concat "^[-A-Za-z0-9_].*[ \t]\\(" Man-name-regexp
288 "(\\(" Man-section-regexp "\\))\\)$")
289 (concat "^[ \t]*\\(" Man-name-regexp
290 "(\\(" Man-section-regexp "\\))\\).*\\1"))
291 "Regular expression describing the heading of a page.")
292
30971bf9 293(defvar Man-heading-regexp "^\\([A-Z][A-Z0-9 /-]+\\)$"
55535639
PJ
294 "Regular expression describing a manpage heading entry.")
295
296(defvar Man-see-also-regexp "SEE ALSO"
297 "Regular expression for SEE ALSO heading (or your equivalent).
298This regexp should not start with a `^' character.")
299
30971bf9
JL
300;; This used to have leading space [ \t]*, but was removed because it
301;; causes false page splits on an occasional NAME with leading space
302;; inside a manpage. And `Man-heading-regexp' doesn't have [ \t]* anyway.
303(defvar Man-first-heading-regexp "^NAME$\\|^[ \t]*No manual entry fo.*$"
55535639
PJ
304 "Regular expression describing first heading on a manpage.
305This regular expression should start with a `^' character.")
306
307(defvar Man-reference-regexp
0dd8b6da
LMI
308 (concat "\\(" Man-name-regexp
309 "\\(\n[ \t]+" Man-name-regexp "\\)*\\)[ \t]*(\\("
310 Man-section-regexp "\\))")
55535639
PJ
311 "Regular expression describing a reference to another manpage.")
312
30abc4f4
MY
313(defvar Man-apropos-regexp
314 (concat "\\\[\\(" Man-name-regexp "\\)\\\][ \t]*(\\(" Man-section-regexp "\\))")
315 "Regular expression describing a reference to manpages in \"man -k output\".")
316
4edd9faf
JB
317(defvar Man-synopsis-regexp "SYNOPSIS"
318 "Regular expression for SYNOPSIS heading (or your equivalent).
319This regexp should not start with a `^' character.")
320
e8defde3
SM
321(defvar Man-files-regexp "FILES\\>"
322 ;; Add \> so as not to match mount(8)'s FILESYSTEM INDEPENDENT MOUNT OPTIONS.
4edd9faf
JB
323 "Regular expression for FILES heading (or your equivalent).
324This regexp should not start with a `^' character.")
325
326(defvar Man-include-regexp "#[ \t]*include[ \t]*"
327 "Regular expression describing the #include (directive of cpp).")
328
13780e21 329(defvar Man-file-name-regexp "[^<>\", \t\n]+"
4edd9faf
JB
330 "Regular expression describing <> in #include line (directive of cpp).")
331
332(defvar Man-normal-file-prefix-regexp "[/~$]"
333 "Regular expression describing a file path appeared in FILES section.")
334
335(defvar Man-header-regexp
336 (concat "\\(" Man-include-regexp "\\)"
337 "[<\"]"
338 "\\(" Man-file-name-regexp "\\)"
339 "[>\"]")
340 "Regular expression describing references to header files.")
341
342(defvar Man-normal-file-regexp
343 (concat Man-normal-file-prefix-regexp Man-file-name-regexp)
344 "Regular expression describing references to normal files.")
345
55535639 346;; This includes the section as an optional part to catch hyphenated
40b1a3a9 347;; references to manpages.
55535639
PJ
348(defvar Man-hyphenated-reference-regexp
349 (concat "\\(" Man-name-regexp "\\)\\((\\(" Man-section-regexp "\\))\\)?")
350 "Regular expression describing a reference in the SEE ALSO section.")
351
dee4ef93 352(defcustom Man-switches ""
7e03f4c8 353 "Switches passed to the man command, as a single string.
dee4ef93
CY
354For example, the -a switch lets you see all the manpages for a
355specified subject, if your `man' program supports it."
356 :type 'string
357 :group 'man)
55535639
PJ
358
359(defvar Man-specified-section-option
360 (if (string-match "-solaris[0-9.]*$" system-configuration)
361 "-s"
362 "")
363 "Option that indicates a specified a manual section name.")
364
aec2bd36
JL
365(defvar Man-support-local-filenames 'auto-detect
366 "Internal cache for the value of the function `Man-support-local-filenames'.
367`auto-detect' means the value is not yet determined.
368Otherwise, the value is whatever the function
369`Man-support-local-filenames' should return.")
370
ca7e59d4
RS
371(defcustom man-imenu-title "Contents"
372 "The title to use if man adds a Contents menu to the menubar."
373 :version "24.4"
374 :type 'string
375 :group 'man)
376
55535639
PJ
377\f
378;; other variables and keymap initializations
a88459cd
SM
379(defvar Man-original-frame)
380(make-variable-buffer-local 'Man-original-frame)
381(defvar Man-arguments)
382(make-variable-buffer-local 'Man-arguments)
383(put 'Man-arguments 'permanent-local t)
384
8b6c19f4
SM
385(defvar Man--sections nil)
386(make-variable-buffer-local 'Man--sections)
387(defvar Man--refpages nil)
388(make-variable-buffer-local 'Man--refpages)
a88459cd 389(defvar Man-page-list nil)
55535639 390(make-variable-buffer-local 'Man-page-list)
a88459cd 391(defvar Man-current-page 0)
55535639 392(make-variable-buffer-local 'Man-current-page)
a88459cd 393(defvar Man-page-mode-string "1 of 1")
55535639 394(make-variable-buffer-local 'Man-page-mode-string)
55535639
PJ
395
396(defconst Man-sysv-sed-script "\
397/\b/ { s/_\b//g
398 s/\b_//g
399 s/o\b+/o/g
400 s/+\bo/o/g
401 :ovstrk
402 s/\\(.\\)\b\\1/\\1/g
403 t ovstrk
404 }
405/\e\\[[0-9][0-9]*m/ s///g"
406 "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.")
407
408(defconst Man-berkeley-sed-script "\
409/\b/ { s/_\b//g\\
410 s/\b_//g\\
411 s/o\b+/o/g\\
412 s/+\bo/o/g\\
413 :ovstrk\\
414 s/\\(.\\)\b\\1/\\1/g\\
415 t ovstrk\\
416 }\\
417/\e\\[[0-9][0-9]*m/ s///g"
418 "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
419
ea1f948d
JL
420(defvar Man-topic-history nil "Topic read history.")
421
1b3b87df 422(defvar Man-mode-syntax-table
55535639
PJ
423 (let ((table (copy-syntax-table (standard-syntax-table))))
424 (modify-syntax-entry ?. "w" table)
425 (modify-syntax-entry ?_ "w" table)
a46f2d6d 426 (modify-syntax-entry ?: "w" table) ; for PDL::Primitive in Perl man pages
55535639
PJ
427 table)
428 "Syntax table used in Man mode buffers.")
429
a88459cd
SM
430(defvar Man-mode-map
431 (let ((map (make-sparse-keymap)))
432 (suppress-keymap map)
433 (set-keymap-parent map button-buffer-map)
434
958614cf 435 (define-key map [?\S-\ ] 'scroll-down-command)
ce3cefcc
CY
436 (define-key map " " 'scroll-up-command)
437 (define-key map "\177" 'scroll-down-command)
a88459cd
SM
438 (define-key map "n" 'Man-next-section)
439 (define-key map "p" 'Man-previous-section)
440 (define-key map "\en" 'Man-next-manpage)
441 (define-key map "\ep" 'Man-previous-manpage)
442 (define-key map ">" 'end-of-buffer)
443 (define-key map "<" 'beginning-of-buffer)
444 (define-key map "." 'beginning-of-buffer)
445 (define-key map "r" 'Man-follow-manual-reference)
446 (define-key map "g" 'Man-goto-section)
447 (define-key map "s" 'Man-goto-see-also-section)
448 (define-key map "k" 'Man-kill)
449 (define-key map "q" 'Man-quit)
daddb3fd 450 (define-key map "u" 'Man-update-manpage)
a88459cd
SM
451 (define-key map "m" 'man)
452 ;; Not all the man references get buttons currently. The text in the
453 ;; manual page can contain references to other man pages
454 (define-key map "\r" 'man-follow)
455 (define-key map "?" 'describe-mode)
ca7e59d4
RS
456
457 (easy-menu-define nil map
458 "`Man-mode' menu."
459 '("Man"
460 ["Next Section" Man-next-section t]
461 ["Previous Section" Man-previous-section t]
462 ["Go To Section..." Man-goto-section t]
463 ["Go To \"SEE ALSO\" Section" Man-goto-see-also-section
464 :active (cl-member Man-see-also-regexp Man--sections
465 :test #'string-match-p)]
466 ["Follow Reference..." Man-follow-manual-reference
467 :active Man--refpages
468 :help "Go to a manpage referred to in the \"SEE ALSO\" section"]
469 "--"
470 ["Next Manpage" Man-next-manpage
471 :active (> (length Man-page-list) 1)]
472 ["Previous Manpage" Man-previous-manpage
473 :active (> (length Man-page-list) 1)]
474 "--"
475 ["Man..." man t]
476 ["Kill Buffer" Man-kill t]
477 ["Quit" Man-quit t]))
a88459cd
SM
478 map)
479 "Keymap for Man mode.")
55535639 480
4edd9faf 481;; buttons
50071f01 482(define-button-type 'Man-abstract-xref-man-page
2bac7f17 483 'follow-link t
50071f01
MY
484 'help-echo "mouse-2, RET: display this man page"
485 'func nil
38363db7
CY
486 'action #'Man-xref-button-action)
487
9201cc28 488(defun Man-xref-button-action (button)
38363db7 489 (let ((target (button-get button 'Man-target-string)))
9201cc28 490 (funcall
38363db7
CY
491 (button-get button 'func)
492 (cond ((null target)
493 (button-label button))
494 ((functionp target)
495 (funcall target (button-start button)))
496 (t target)))))
50071f01 497
9201cc28 498(define-button-type 'Man-xref-man-page
50071f01
MY
499 :supertype 'Man-abstract-xref-man-page
500 'func 'man-follow)
501
4edd9faf
JB
502
503(define-button-type 'Man-xref-header-file
500e05aa
JB
504 'action (lambda (button)
505 (let ((w (button-get button 'Man-target-string)))
506 (unless (Man-view-header-file w)
507 (error "Cannot find header file: %s" w))))
2bac7f17 508 'follow-link t
500e05aa 509 'help-echo "mouse-2: display this header file")
4edd9faf
JB
510
511(define-button-type 'Man-xref-normal-file
512 'action (lambda (button)
513 (let ((f (substitute-in-file-name
514 (button-get button 'Man-target-string))))
515 (if (file-exists-p f)
516 (if (file-readable-p f)
517 (view-file f)
518 (error "Cannot read a file: %s" f))
519 (error "Cannot find a file: %s" f))))
2bac7f17 520 'follow-link t
5bad6053 521 'help-echo "mouse-2: display this file")
4edd9faf 522
55535639
PJ
523\f
524;; ======================================================================
525;; utilities
526
527(defun Man-init-defvars ()
927c60bd 528 "Used for initializing variables based on display's color support.
55535639
PJ
529This is necessary if one wants to dump man.el with Emacs."
530
531 ;; Avoid possible error in call-process by using a directory that must exist.
532 (let ((default-directory "/"))
533 (setq Man-sed-script
534 (cond
535 (Man-fontify-manpage-flag
536 nil)
15502042 537 ((eq 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
55535639 538 Man-sysv-sed-script)
15502042 539 ((eq 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
55535639
PJ
540 Man-berkeley-sed-script)
541 (t
542 nil))))
543
544 (setq Man-filter-list
545 ;; Avoid trailing nil which confuses customize.
546 (apply 'list
547 (cons
548 Man-sed-command
1bf0da02
EZ
549 (if (eq system-type 'windows-nt)
550 ;; Windows needs ".." quoting, not '..'.
551 (list
552 "-e \"/Reformatting page. Wait/d\""
553 "-e \"/Reformatting entry. Wait/d\""
554 "-e \"/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d\""
555 "-e \"/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d\""
556 "-e \"/^Printed[ \t][0-9].*[0-9]$/d\""
557 "-e \"/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d\""
558 "-e \"/^[A-Za-z].*Last[ \t]change:/d\""
559 "-e \"/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d\""
560 "-e \"/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d\"")
561 (list
562 (if Man-sed-script
563 (concat "-e '" Man-sed-script "'")
564 "")
565 "-e '/^[\001-\032][\001-\032]*$/d'"
566 "-e '/\e[789]/s///g'"
567 "-e '/Reformatting page. Wait/d'"
568 "-e '/Reformatting entry. Wait/d'"
569 "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
570 "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
571 "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
572 "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
573 "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
574 "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
575 "-e '/^[A-Za-z].*Last[ \t]change:/d'"
576 "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
577 "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
578 "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
579 )))
580 ;; Windows doesn't support multi-line commands, so don't
581 ;; invoke Awk there.
582 (unless (eq system-type 'windows-nt)
583 (cons
584 Man-awk-command
585 (list
586 "'\n"
587 "BEGIN { blankline=0; anonblank=0; }\n"
588 "/^$/ { if (anonblank==0) next; }\n"
589 "{ anonblank=1; }\n"
590 "/^$/ { blankline++; next; }\n"
591 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
592 "'"
593 )))
55535639
PJ
594 (if (not Man-uses-untabify-flag)
595 ;; The outer list will be stripped off by apply.
596 (list (cons
597 Man-untabify-command
598 Man-untabify-command-args))
599 )))
600)
601
55535639
PJ
602(defsubst Man-make-page-mode-string ()
603 "Formats part of the mode line for Man mode."
604 (format "%s page %d of %d"
605 (or (nth 2 (nth (1- Man-current-page) Man-page-list))
606 "")
607 Man-current-page
608 (length Man-page-list)))
609
610(defsubst Man-build-man-command ()
611 "Builds the entire background manpage and cleaning command."
612 (let ((command (concat manual-program " " Man-switches
aec2bd36
JL
613 (cond
614 ;; Already has %s
615 ((string-match "%s" manual-program) "")
616 ;; Stock MS-DOS shells cannot redirect stderr;
617 ;; `call-process' below sends it to /dev/null,
618 ;; so we don't need `2>' even with DOS shells
619 ;; which do support stderr redirection.
620 ((not (fboundp 'start-process)) " %s")
621 ((concat " %s 2>" null-device)))))
55535639
PJ
622 (flist Man-filter-list))
623 (while (and flist (car flist))
624 (let ((pcom (car (car flist)))
625 (pargs (cdr (car flist))))
626 (setq command
627 (concat command " | " pcom " "
628 (mapconcat (lambda (phrase)
629 (if (not (stringp phrase))
630 (error "Malformed Man-filter-list"))
631 phrase)
632 pargs " ")))
7e734986 633 (setq flist (cdr flist))))
55535639
PJ
634 command))
635
7e734986
JB
636
637(defun Man-translate-cleanup (string)
638 "Strip leading, trailing and middle spaces."
639 (when (stringp string)
640 ;; Strip leading and trailing
641 (if (string-match "^[ \t\f\r\n]*\\(.+[^ \t\f\r\n]\\)" string)
642 (setq string (match-string 1 string)))
643 ;; middle spaces
644 (setq string (replace-regexp-in-string "[\t\r\n]" " " string))
645 (setq string (replace-regexp-in-string " +" " " string))
646 string))
647
55535639
PJ
648(defun Man-translate-references (ref)
649 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
650Leave it as is if already in that style. Possibly downcase and
927c60bd
JB
651translate the section (see the `Man-downcase-section-letters-flag'
652and the `Man-section-translations-alist' variables)."
55535639 653 (let ((name "")
7e734986
JB
654 (section "")
655 (slist Man-section-translations-alist))
656 (setq ref (Man-translate-cleanup ref))
55535639
PJ
657 (cond
658 ;; "chmod(2V)" case ?
659 ((string-match (concat "^" Man-reference-regexp "$") ref)
0dd8b6da
LMI
660 (setq name (replace-regexp-in-string "[\n\t ]" "" (match-string 1 ref))
661 section (match-string 3 ref)))
55535639
PJ
662 ;; "2v chmod" case ?
663 ((string-match (concat "^\\(" Man-section-regexp
664 "\\) +\\(" Man-name-regexp "\\)$") ref)
72397ff1
SM
665 (setq name (match-string 2 ref)
666 section (match-string 1 ref))))
55535639
PJ
667 (if (string= name "")
668 ref ; Return the reference as is
669 (if Man-downcase-section-letters-flag
670 (setq section (downcase section)))
671 (while slist
672 (let ((s1 (car (car slist)))
673 (s2 (cdr (car slist))))
674 (setq slist (cdr slist))
675 (if Man-downcase-section-letters-flag
676 (setq s1 (downcase s1)))
677 (if (not (string= s1 section)) nil
678 (setq section (if Man-downcase-section-letters-flag
679 (downcase s2)
680 s2)
681 slist nil))))
682 (concat Man-specified-section-option section " " name))))
683
aec2bd36 684(defun Man-support-local-filenames ()
3ab7ebb9
GM
685 "Return non-nil if the man command supports local filenames.
686Different man programs support this feature in different ways.
687The default Debian man program (\"man-db\") has a `--local-file'
688\(or `-l') option for this purpose. The default Red Hat man
689program has no such option, but interprets any name containing
690a \"/\" as a local filename. The function returns either `man-db'
691`man', or nil."
692 (if (eq Man-support-local-filenames 'auto-detect)
693 (setq Man-support-local-filenames
694 (with-temp-buffer
695 (let ((default-directory
696 ;; Ensure that `default-directory' exists and is readable.
1d75432d
GM
697 (if (file-accessible-directory-p default-directory)
698 default-directory
3ab7ebb9
GM
699 (expand-file-name "~/"))))
700 (ignore-errors
701 (call-process manual-program nil t nil "--help")))
702 (cond ((search-backward "--local-file" nil 'move)
703 'man-db)
704 ;; This feature seems to be present in at least ver 1.4f,
705 ;; which is about 20 years old.
706 ;; I don't know if this version has an official name?
707 ((looking-at "^man, versione? [1-9]")
708 'man))))
709 Man-support-local-filenames))
aec2bd36 710
55535639
PJ
711\f
712;; ======================================================================
d8b3b1a1 713;; default man entry: get word near point
55535639 714
d8b3b1a1
MR
715(defun Man-default-man-entry (&optional pos)
716 "Guess default manual entry based on the text near position POS.
717POS defaults to `point'."
10c877fe 718 (let (word start column distance)
55535639 719 (save-excursion
d8b3b1a1
MR
720 (when pos (goto-char pos))
721 (setq pos (point))
722 ;; The default title is the nearest entry-like object before or
723 ;; after POS.
724 (if (and (skip-chars-backward " \ta-zA-Z0-9+")
725 (not (zerop (skip-chars-backward "(")))
726 ;; Try to handle the special case where POS is on a
727 ;; section number.
728 (looking-at
729 (concat "([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
730 ;; We skipped a valid section number backwards, look at
731 ;; preceding text.
732 (or (and (skip-chars-backward ",; \t")
733 (not (zerop (skip-chars-backward "-a-zA-Z0-9._+:"))))
734 ;; Not a valid entry, move POS after closing paren.
735 (not (setq pos (match-end 0)))))
736 ;; We have a candidate, make `start' record its starting
737 ;; position.
ccf721a6 738 (setq start (point))
d8b3b1a1
MR
739 ;; Otherwise look at char before POS.
740 (goto-char pos)
ccf721a6 741 (if (not (zerop (skip-chars-backward "-a-zA-Z0-9._+:")))
d8b3b1a1
MR
742 ;; Our candidate is just before or around POS.
743 (setq start (point))
744 ;; Otherwise record the current column and look backwards.
745 (setq column (current-column))
746 (skip-chars-backward ",; \t")
c80e3b4a 747 ;; Record the distance traveled.
d8b3b1a1
MR
748 (setq distance (- column (current-column)))
749 (when (looking-back
750 (concat "([ \t]*\\(?:" Man-section-regexp "\\)[ \t]*)"))
751 ;; Skip section number backwards.
752 (goto-char (match-beginning 0))
753 (skip-chars-backward " \t"))
754 (if (not (zerop (skip-chars-backward "-a-zA-Z0-9._+:")))
755 (progn
756 ;; We have a candidate before POS ...
757 (setq start (point))
758 (goto-char pos)
759 (if (and (skip-chars-forward ",; \t")
760 (< (- (current-column) column) distance)
761 (looking-at "[-a-zA-Z0-9._+:]"))
762 ;; ... but the one after POS is better.
763 (setq start (point))
764 ;; ... and anything after POS is worse.
765 (goto-char start)))
766 ;; No candidate before POS.
767 (goto-char pos)
768 (skip-chars-forward ",; \t")
769 (setq start (point)))))
770 ;; We have found a suitable starting point, try to skip at least
771 ;; one character.
ccf721a6
MR
772 (skip-chars-forward "-a-zA-Z0-9._+:")
773 (setq word (buffer-substring-no-properties start (point)))
774 ;; If there is a continuation at the end of line, check the
775 ;; following line too, eg:
776 ;; see this-
777 ;; command-here(1)
d8b3b1a1 778 ;; Note: This code gets executed iff our entry is after POS.
ccf721a6 779 (when (looking-at "[ \t\r\n]+\\([-a-zA-Z0-9._+:]+\\)([0-9])")
d8b3b1a1
MR
780 (setq word (concat word (match-string-no-properties 1)))
781 ;; Make sure the section number gets included by the code below.
782 (goto-char (match-end 1)))
c1a6c0a4 783 (when (string-match "[-._]+$" word)
ccf721a6 784 (setq word (substring word 0 (match-beginning 0))))
d8b3b1a1
MR
785 ;; The following was commented out since the preceding code
786 ;; should not produce a leading "*" in the first place.
787;;; ;; If looking at something like *strcat(... , remove the '*'
788;;; (when (string-match "^*" word)
789;;; (setq word (substring word 1)))
790 (concat
791 word
792 (and (not (string-equal word ""))
793 ;; If looking at something like ioctl(2) or brc(1M),
794 ;; include the section number in the returned value.
795 (looking-at
796 (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
797 (format "(%s)" (match-string-no-properties 1)))))))
55535639
PJ
798
799\f
800;; ======================================================================
801;; Top level command and background process sentinel
802
803;; For compatibility with older versions.
804;;;###autoload
805(defalias 'manual-entry 'man)
806
e2ec6dd5
SM
807(defvar Man-completion-cache nil
808 ;; On my machine, "man -k" is so fast that a cache makes no sense,
809 ;; but apparently that's not the case in all cases, so let's add a cache.
810 "Cache of completion table of the form (PREFIX . TABLE).")
811
327a6cca
WJ
812(defvar Man-man-k-use-anchor
813 ;; man-db or man-1.*
814 (memq system-type '(gnu gnu/linux gnu/kfreebsd))
815 "If non-nil prepend ^ to the prefix passed to \"man -k\" for completion.
816The value should be nil if \"man -k ^PREFIX\" may omit some man
817pages whose names start with PREFIX.
818
819Currently, the default value depends on `system-type' and is
820non-nil where the standard man programs are known to behave
821properly. Setting the value to nil always gives correct results
822but computing the list of completions may take a bit longer.")
823
824(defun Man-parse-man-k ()
825 "Parse \"man -k\" output and return the list of page names.
826
827The current buffer should contain the output of a command of the
828form \"man -k keyword\", which is traditionally also available with
829apropos(1).
830
831While POSIX man(1p) is a bit vague about what to expect here,
832this function tries to parse some commonly used formats, which
833can be described in the following informal way, with square brackets
834indicating optional parts and whitespace being interpreted
835somewhat loosely.
836
837foo[, bar [, ...]] [other stuff] (sec) - description
838foo(sec)[, bar(sec) [, ...]] [other stuff] - description
839
840For more details and some regression tests, please see
841test/automated/man-tests.el in the emacs bzr repository."
842 (goto-char (point-min))
843 ;; See man-tests for data about which systems use which format (hopefully we
844 ;; will be able to simplify the code if/when some of those formats aren't
845 ;; used any more).
846 (let (table)
847 (while (search-forward-regexp "^\\([^ \t,\n]+\\)\\(.*?\\)\
848\\(?:[ \t]\\(([^ \t,\n]+?)\\)\\)?\\(?:[ \t]+- ?\\(.*\\)\\)?$" nil t)
849 (let ((section (match-string 3))
850 (description (match-string 4))
851 (bound (match-end 2)))
852 (goto-char (match-end 1))
853 (while
854 (progn
855 ;; The first regexp grouping may already match the section
856 ;; tacked on to the name, which is ok since for the formats we
857 ;; claim to support the third (non-shy) grouping does not
858 ;; match in this case, i.e., section is nil.
859 (push (propertize (concat (match-string 1) section)
860 'help-echo description)
861 table)
862 (search-forward-regexp "\\=, *\\([^ \t,]+\\)" bound t)))))
863 (nreverse table)))
864
bb301b9a
SM
865(defun Man-completion-table (string pred action)
866 (cond
9505c3c7
SM
867 ;; This ends up returning t for pretty much any string, and hence leads to
868 ;; spurious "complete but not unique" messages. And since `man' doesn't
869 ;; require-match anyway, there's not point being clever.
870 ;;((eq action 'lambda) (not (string-match "([^)]*\\'" string)))
896114cf
SM
871 ((equal string "-k")
872 ;; Let SPC (minibuffer-complete-word) insert the space.
873 (complete-with-action action '("-k ") string pred))
10c877fe
SM
874 (t
875 (let ((table (cdr Man-completion-cache))
876 (section nil)
877 (prefix string))
878 (when (string-match "\\`\\([[:digit:]].*?\\) " string)
879 (setq section (match-string 1 string))
880 (setq prefix (substring string (match-end 0))))
e2ec6dd5 881 (unless (and Man-completion-cache
10c877fe
SM
882 (string-prefix-p (car Man-completion-cache) prefix))
883 (with-temp-buffer
b58dd707
KR
884 (setq default-directory "/") ;; in case inherited doesn't exist
885 ;; Actually for my `man' the arg is a regexp.
886 ;; POSIX says it must be ERE and "man-db" seems to agree,
10c877fe
SM
887 ;; whereas under MacOSX it seems to be BRE-style and doesn't
888 ;; accept backslashes at all. Let's not bother to
889 ;; quote anything.
890 (let ((process-environment (copy-sequence process-environment)))
891 (setenv "COLUMNS" "999") ;; don't truncate long names
c07ff221
SM
892 ;; manual-program might not even exist. And since it's
893 ;; run differently in Man-getpage-in-background, an error
894 ;; here may not necessarily mean that we'll also get an
895 ;; error later.
327a6cca
WJ
896 (ignore-errors
897 (call-process manual-program nil '(t nil) nil
898 "-k" (concat (when (or Man-man-k-use-anchor
899 (string-equal prefix ""))
900 "^")
901 prefix))))
902 (setq table (Man-parse-man-k)))
903 ;; Cache the table for later reuse.
904 (setq Man-completion-cache (cons prefix table)))
bb301b9a
SM
905 ;; The table may contain false positives since the match is made
906 ;; by "man -k" not just on the manpage's name.
10c877fe
SM
907 (if section
908 (let ((re (concat "(" (regexp-quote section) ")\\'")))
909 (dolist (comp (prog1 table (setq table nil)))
910 (if (string-match re comp)
911 (push (substring comp 0 (match-beginning 0)) table)))
912 (completion-table-with-context (concat section " ") table
913 prefix pred action))
d7117720
SM
914 ;; If the current text looks like a possible section name,
915 ;; then add a completion entry that just adds a space so SPC
916 ;; can be used to insert a space.
917 (if (string-match "\\`[[:digit:]]" string)
918 (push (concat string " ") table))
10c877fe
SM
919 (let ((res (complete-with-action action table string pred)))
920 ;; In case we're completing to a single name that exists in
921 ;; several sections, the longest prefix will look like "foo(".
922 (if (and (stringp res)
923 (string-match "([^(]*\\'" res)
924 ;; In case the paren was already in `prefix', don't
925 ;; remove it.
926 (> (match-beginning 0) (length prefix)))
927 (substring res 0 (match-beginning 0))
928 res)))))))
7e734986 929
55535639
PJ
930;;;###autoload
931(defun man (man-args)
932 "Get a Un*x manual page and put it in a buffer.
91c4831e
KR
933This command is the top-level command in the man package. It
934runs a Un*x command to retrieve and clean a manpage in the
935background and places the results in a `Man-mode' browsing
936buffer. See variable `Man-notify-method' for what happens when
937the buffer is ready. If a buffer already exists for this man
938page, it will display immediately.
939
940For a manpage from a particular section, use either of the
941following. \"cat(1)\" is how cross-references appear and is
942passed to man as \"1 cat\".
943
944 cat(1)
945 1 cat
946
947To see manpages from all sections related to a subject, use an
948\"all pages\" option (which might be \"-a\" if it's not the
949default), then step through with `Man-next-manpage' (\\<Man-mode-map>\\[Man-next-manpage]) etc.
950Add to `Man-switches' to make this option permanent.
951
952 -a chmod
953
954An explicit filename can be given too. Use -l if it might
955otherwise look like a page name.
956
957 /my/file/name.1.gz
958 -l somefile.1
959
960An \"apropos\" query with -k gives a buffer of matching page
961names or descriptions. The pattern argument is usually an
962\"egrep\" style regexp.
963
964 -k pattern"
965
55535639
PJ
966 (interactive
967 (list (let* ((default-entry (Man-default-man-entry))
573f4575
KR
968 ;; ignore case because that's friendly for bizarre
969 ;; caps things like the X11 function names and because
a3827a43 970 ;; "man" itself is case-insensitive on the command line
573f4575
KR
971 ;; so you're accustomed not to bother about the case
972 ;; ("man -k" is case-insensitive similarly, so the
973 ;; table has everything available to complete)
974 (completion-ignore-case t)
327a6cca 975 Man-completion-cache ;Don't cache across calls.
bb301b9a 976 (input (completing-read
5b76833f 977 (format "Manual entry%s"
55535639 978 (if (string= default-entry "")
5b76833f
RF
979 ": "
980 (format " (default %s): " default-entry)))
bb301b9a
SM
981 'Man-completion-table
982 nil nil nil 'Man-topic-history default-entry)))
55535639 983 (if (string= input "")
72397ff1 984 (error "No man args given")
55535639
PJ
985 input))))
986
987 ;; Possibly translate the "subject(section)" syntax into the
988 ;; "section subject" syntax and possibly downcase the section.
989 (setq man-args (Man-translate-references man-args))
990
991 (Man-getpage-in-background man-args))
992
993;;;###autoload
994(defun man-follow (man-args)
995 "Get a Un*x manual page of the item under point and put it in a buffer."
996 (interactive (list (Man-default-man-entry)))
997 (if (or (not man-args)
998 (string= man-args ""))
999 (error "No item under point")
1000 (man man-args)))
1001
daddb3fd
DH
1002(defmacro Man-start-calling (&rest body)
1003 "Start the man command in `body' after setting up the environment"
1004 `(let ((process-environment (copy-sequence process-environment))
1005 ;; The following is so Awk script gets \n intact
1006 ;; But don't prevent decoding of the outside.
1007 (coding-system-for-write 'raw-text-unix)
1008 ;; We must decode the output by a coding system that the
1009 ;; system's locale suggests in multibyte mode.
1010 (coding-system-for-read locale-coding-system)
1011 ;; Avoid possible error by using a directory that always exists.
1012 (default-directory
1013 (if (and (file-directory-p default-directory)
1014 (not (find-file-name-handler default-directory
1015 'file-directory-p)))
1016 default-directory
1017 "/")))
1018 ;; Prevent any attempt to use display terminal fanciness.
1019 (setenv "TERM" "dumb")
1020 ;; In Debian Woody, at least, we get overlong lines under X
1021 ;; unless COLUMNS or MANWIDTH is set. This isn't a problem on
1022 ;; a tty. man(1) says:
1023 ;; MANWIDTH
1024 ;; If $MANWIDTH is set, its value is used as the line
1025 ;; length for which manual pages should be formatted.
1026 ;; If it is not set, manual pages will be formatted
1027 ;; with a line length appropriate to the current ter-
1028 ;; minal (using an ioctl(2) if available, the value of
1029 ;; $COLUMNS, or falling back to 80 characters if nei-
1030 ;; ther is available).
1031 (when (or window-system
1032 (not (or (getenv "MANWIDTH") (getenv "COLUMNS"))))
1033 ;; This isn't strictly correct, since we don't know how
1034 ;; the page will actually be displayed, but it seems
1035 ;; reasonable.
1036 (setenv "COLUMNS" (number-to-string
1037 (cond
1038 ((and (integerp Man-width) (> Man-width 0))
1039 Man-width)
1040 (Man-width (frame-width))
1041 ((window-width))))))
1042 ;; Since man-db 2.4.3-1, man writes plain text with no escape
1043 ;; sequences when stdout is not a tty. In 2.5.0, the following
1044 ;; env-var was added to allow control of this (see Debian Bug#340673).
1045 (setenv "MAN_KEEP_FORMATTING" "1")
1046 ,@body))
1047
55535639 1048(defun Man-getpage-in-background (topic)
398a825b
SM
1049 "Use TOPIC to build and fire off the manpage and cleaning command.
1050Return the buffer in which the manpage will appear."
55535639
PJ
1051 (let* ((man-args topic)
1052 (bufname (concat "*Man " man-args "*"))
1053 (buffer (get-buffer bufname)))
1054 (if buffer
1055 (Man-notify-when-ready buffer)
1056 (require 'env)
1057 (message "Invoking %s %s in the background" manual-program man-args)
1058 (setq buffer (generate-new-buffer bufname))
a88459cd 1059 (with-current-buffer buffer
5a0c1883 1060 (setq buffer-undo-list t)
55535639
PJ
1061 (setq Man-original-frame (selected-frame))
1062 (setq Man-arguments man-args))
daddb3fd
DH
1063 (Man-start-calling
1064 (if (fboundp 'start-process)
55535639 1065 (set-process-sentinel
ac00945e 1066 (start-process manual-program buffer
00170b0d
EZ
1067 (if (memq system-type '(cygwin windows-nt))
1068 shell-file-name
1069 "sh")
353518de 1070 shell-command-switch
55535639
PJ
1071 (format (Man-build-man-command) man-args))
1072 'Man-bgproc-sentinel)
504feff5 1073 (let ((exit-status
ac00945e
EZ
1074 (call-process shell-file-name nil (list buffer nil) nil
1075 shell-command-switch
504feff5
KG
1076 (format (Man-build-man-command) man-args)))
1077 (msg ""))
1078 (or (and (numberp exit-status)
1079 (= exit-status 0))
1080 (and (numberp exit-status)
1081 (setq msg
1082 (format "exited abnormally with code %d"
1083 exit-status)))
1084 (setq msg exit-status))
398a825b 1085 (Man-bgproc-sentinel bufname msg)))))
daddb3fd
DH
1086 buffer))
1087
1088(defun Man-update-manpage ()
1089 "Reformat current manpage by calling the man command again synchronously."
1090 (interactive)
1091 (when (eq Man-arguments nil)
1092 ;;this shouldn't happen unless it is not in a Man buffer."
1093 (error "Man-arguments not initialized"))
1094 (let ((old-pos (point))
1095 (text (current-word))
1096 (old-size (buffer-size))
1097 (inhibit-read-only t)
1098 (buffer-read-only nil))
1099 (erase-buffer)
1100 (Man-start-calling
1101 (call-process shell-file-name nil (list (current-buffer) nil) nil
1102 shell-command-switch
1103 (format (Man-build-man-command) Man-arguments)))
1104 (if Man-fontify-manpage-flag
1105 (Man-fontify-manpage)
1106 (Man-cleanup-manpage))
1107 (goto-char old-pos)
1108 ;;restore the point, not strictly right.
1109 (unless (or (eq text nil) (= old-size (buffer-size)))
1110 (let ((case-fold-search nil))
1111 (if (> old-size (buffer-size))
1112 (search-backward text nil t))
1113 (search-forward text nil t)))))
55535639
PJ
1114
1115(defun Man-notify-when-ready (man-buffer)
1116 "Notify the user when MAN-BUFFER is ready.
1117See the variable `Man-notify-method' for the different notification behaviors."
a88459cd 1118 (let ((saved-frame (with-current-buffer man-buffer
55535639 1119 Man-original-frame)))
a464a6c7
SM
1120 (pcase Man-notify-method
1121 (`newframe
1122 ;; Since we run asynchronously, perhaps while Emacs is waiting
1123 ;; for input, we must not leave a different buffer current. We
1124 ;; can't rely on the editor command loop to reselect the
1125 ;; selected window's buffer.
1126 (save-excursion
1127 (let ((frame (make-frame Man-frame-parameters)))
1128 (set-window-buffer (frame-selected-window frame) man-buffer)
1129 (set-window-dedicated-p (frame-selected-window frame) t)
1130 (or (display-multi-frame-p frame)
1131 (select-frame frame)))))
1132 (`pushy
1133 (switch-to-buffer man-buffer))
1134 (`bully
1135 (and (frame-live-p saved-frame)
1136 (select-frame saved-frame))
1137 (pop-to-buffer man-buffer)
1138 (delete-other-windows))
1139 (`aggressive
1140 (and (frame-live-p saved-frame)
1141 (select-frame saved-frame))
1142 (pop-to-buffer man-buffer))
1143 (`friendly
1144 (and (frame-live-p saved-frame)
1145 (select-frame saved-frame))
1146 (display-buffer man-buffer 'not-this-window))
1147 (`polite
1148 (beep)
1149 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
1150 (`quiet
1151 (message "Manual buffer %s is ready" (buffer-name man-buffer)))
1152 (_ ;; meek
1153 (message ""))
1154 )))
55535639
PJ
1155
1156(defun Man-softhyphen-to-minus ()
9606309f 1157 ;; \255 is SOFT HYPHEN in Latin-N. Versions of Debian man, at
55535639
PJ
1158 ;; least, emit it even when not in a Latin-N locale.
1159 (unless (eq t (compare-strings "latin-" 0 nil
1160 current-language-environment 0 6 t))
1161 (goto-char (point-min))
1162 (let ((str "\255"))
1163 (if enable-multibyte-characters
1164 (setq str (string-as-multibyte str)))
1165 (while (search-forward str nil t) (replace-match "-")))))
1166
1167(defun Man-fontify-manpage ()
1168 "Convert overstriking and underlining to the correct fonts.
1169Same for the ANSI bold and normal escape sequences."
1170 (interactive)
aec2bd36 1171 (message "Please wait: formatting the %s man page..." Man-arguments)
55535639 1172 (goto-char (point-min))
079c2d00 1173 ;; Fontify ANSI escapes.
456e62c2
WJ
1174 (let ((ansi-color-apply-face-function
1175 (lambda (beg end face)
1176 (when face
1177 (put-text-property beg end 'face face))))
1178 (ansi-color-map Man-ansi-color-map))
1179 (ansi-color-apply-on-region (point-min) (point-max)))
079c2d00 1180 ;; Other highlighting.
6bfb8bd6
RS
1181 (let ((buffer-undo-list t))
1182 (if (< (buffer-size) (position-bytes (point-max)))
1183 ;; Multibyte characters exist.
1184 (progn
1185 (goto-char (point-min))
1186 (while (search-forward "__\b\b" nil t)
1187 (backward-delete-char 4)
456e62c2 1188 (put-text-property (point) (1+ (point)) 'face 'Man-underline))
6bfb8bd6
RS
1189 (goto-char (point-min))
1190 (while (search-forward "\b\b__" nil t)
1191 (backward-delete-char 4)
456e62c2 1192 (put-text-property (1- (point)) (point) 'face 'Man-underline))))
6bfb8bd6
RS
1193 (goto-char (point-min))
1194 (while (search-forward "_\b" nil t)
1195 (backward-delete-char 2)
456e62c2 1196 (put-text-property (point) (1+ (point)) 'face 'Man-underline))
6bfb8bd6
RS
1197 (goto-char (point-min))
1198 (while (search-forward "\b_" nil t)
1199 (backward-delete-char 2)
456e62c2 1200 (put-text-property (1- (point)) (point) 'face 'Man-underline))
6bfb8bd6
RS
1201 (goto-char (point-min))
1202 (while (re-search-forward "\\(.\\)\\(\b+\\1\\)+" nil t)
1203 (replace-match "\\1")
456e62c2 1204 (put-text-property (1- (point)) (point) 'face 'Man-overstrike))
6bfb8bd6
RS
1205 (goto-char (point-min))
1206 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t)
1207 (replace-match "o")
1208 (put-text-property (1- (point)) (point) 'face 'bold))
1209 (goto-char (point-min))
1210 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
1211 (replace-match "+")
1212 (put-text-property (1- (point)) (point) 'face 'bold))
91e3333f 1213 ;; When the header is longer than the manpage name, groff tries to
e4769531 1214 ;; condense it to a shorter line interspersed with ^H. Remove ^H with
456e62c2 1215 ;; their preceding chars (but don't put Man-overstrike). (Bug#5566)
91e3333f
JL
1216 (goto-char (point-min))
1217 (while (re-search-forward ".\b" nil t) (backward-delete-char 2))
6bfb8bd6
RS
1218 (goto-char (point-min))
1219 ;; Try to recognize common forms of cross references.
1220 (Man-highlight-references)
1221 (Man-softhyphen-to-minus)
1222 (goto-char (point-min))
1223 (while (re-search-forward Man-heading-regexp nil t)
1224 (put-text-property (match-beginning 0)
1225 (match-end 0)
456e62c2 1226 'face 'Man-overstrike)))
2f5c6024 1227 (message "%s man page formatted" (Man-page-from-arguments Man-arguments)))
55535639 1228
50071f01 1229(defun Man-highlight-references (&optional xref-man-type)
4edd9faf 1230 "Highlight the references on mouse-over.
927c60bd 1231References include items in the SEE ALSO section,
71726072
EZ
1232header file (#include <foo.h>), and files in FILES.
1233If optional argument XREF-MAN-TYPE is non-nil, it used as the
1234button type for items in SEE ALSO section. If it is nil, the
1235default type, `Man-xref-man-page' is used for the buttons."
af8308ec
MY
1236 ;; `Man-highlight-references' is used from woman.el, too.
1237 ;; woman.el doesn't set `Man-arguments'.
1238 (unless Man-arguments
1239 (setq Man-arguments ""))
30abc4f4
MY
1240 (if (string-match "-k " Man-arguments)
1241 (progn
707f55b0
DN
1242 (Man-highlight-references0 nil Man-reference-regexp 1
1243 'Man-default-man-entry
71726072
EZ
1244 (or xref-man-type 'Man-xref-man-page))
1245 (Man-highlight-references0 nil Man-apropos-regexp 1
707f55b0 1246 'Man-default-man-entry
71726072 1247 (or xref-man-type 'Man-xref-man-page)))
9201cc28 1248 (Man-highlight-references0 Man-see-also-regexp Man-reference-regexp 1
707f55b0 1249 'Man-default-man-entry
71726072
EZ
1250 (or xref-man-type 'Man-xref-man-page))
1251 (Man-highlight-references0 Man-synopsis-regexp Man-header-regexp 0 2
1252 'Man-xref-header-file)
1253 (Man-highlight-references0 Man-files-regexp Man-normal-file-regexp 0 0
1254 'Man-xref-normal-file)))
4edd9faf 1255
30abc4f4 1256(defun Man-highlight-references0 (start-section regexp button-pos target type)
4edd9faf 1257 ;; Based on `Man-build-references-alist'
30abc4f4
MY
1258 (when (or (null start-section)
1259 (Man-find-section start-section))
1260 (let ((end (if start-section
1261 (progn
1262 (forward-line 1)
1263 (back-to-indentation)
1264 (save-excursion
1265 (Man-next-section 1)
1266 (point)))
1267 (goto-char (point-min))
a88459cd 1268 nil)))
4edd9faf 1269 (while (re-search-forward regexp end t)
cde7e38b
CY
1270 ;; An overlay button is preferable because the underlying text
1271 ;; may have text property highlights (Bug#7881).
1272 (make-button
4edd9faf
JB
1273 (match-beginning button-pos)
1274 (match-end button-pos)
1275 'type type
30abc4f4 1276 'Man-target-string (cond
9201cc28 1277 ((numberp target)
30abc4f4
MY
1278 (match-string target))
1279 ((functionp target)
707f55b0 1280 target)
30abc4f4 1281 (t nil)))))))
4edd9faf 1282
1d3b75d8
RS
1283(defun Man-cleanup-manpage (&optional interactive)
1284 "Remove overstriking and underlining from the current buffer.
1285Normally skip any jobs that should have been done by the sed script,
1286but when called interactively, do those jobs even if the sed
1287script would have done them."
1288 (interactive "p")
55535639
PJ
1289 (message "Please wait: cleaning up the %s man page..."
1290 Man-arguments)
1d3b75d8 1291 (if (or interactive (not Man-sed-script))
55535639
PJ
1292 (progn
1293 (goto-char (point-min))
1294 (while (search-forward "_\b" nil t) (backward-delete-char 2))
1295 (goto-char (point-min))
1296 (while (search-forward "\b_" nil t) (backward-delete-char 2))
1297 (goto-char (point-min))
1298 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t)
1299 (replace-match "\\1"))
1300 (goto-char (point-min))
1301 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match ""))
1302 (goto-char (point-min))
1303 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o"))
1304 ))
1305 (goto-char (point-min))
1306 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
91e3333f 1307 ;; When the header is longer than the manpage name, groff tries to
e4769531 1308 ;; condense it to a shorter line interspersed with ^H. Remove ^H with
456e62c2 1309 ;; their preceding chars (but don't put Man-overstrike). (Bug#5566)
91e3333f
JL
1310 (goto-char (point-min))
1311 (while (re-search-forward ".\b" nil t) (backward-delete-char 2))
55535639
PJ
1312 (Man-softhyphen-to-minus)
1313 (message "%s man page cleaned up" Man-arguments))
1314
1315(defun Man-bgproc-sentinel (process msg)
1316 "Manpage background process sentinel.
1317When manpage command is run asynchronously, PROCESS is the process
1318object for the manpage command; when manpage command is run
1319synchronously, PROCESS is the name of the buffer where the manpage
1320command is run. Second argument MSG is the exit message of the
1321manpage command."
1322 (let ((Man-buffer (if (stringp process) (get-buffer process)
1323 (process-buffer process)))
1324 (delete-buff nil)
1325 (err-mess nil))
1326
1327 (if (null (buffer-name Man-buffer)) ;; deleted buffer
1328 (or (stringp process)
1329 (set-process-buffer process nil))
1330
a88459cd 1331 (with-current-buffer Man-buffer
55535639
PJ
1332 (let ((case-fold-search nil))
1333 (goto-char (point-min))
1334 (cond ((or (looking-at "No \\(manual \\)*entry for")
1335 (looking-at "[^\n]*: nothing appropriate$"))
1336 (setq err-mess (buffer-substring (point)
1337 (progn
1338 (end-of-line) (point)))
1339 delete-buff t))
69bcb1f3
KR
1340
1341 ;; "-k foo", successful exit, but no output (from man-db)
1342 ;; ENHANCE-ME: share the check for -k with
1343 ;; `Man-highlight-references'. The \\s- bits here are
1344 ;; meant to allow for multiple options with -k among them.
1345 ((and (string-match "\\(\\`\\|\\s-\\)-k\\s-" Man-arguments)
1346 (eq (process-status process) 'exit)
1347 (= (process-exit-status process) 0)
1348 (= (point-min) (point-max)))
1349 (setq err-mess (format "%s: no matches" Man-arguments)
1350 delete-buff t))
1351
55535639
PJ
1352 ((or (stringp process)
1353 (not (and (eq (process-status process) 'exit)
1354 (= (process-exit-status process) 0))))
1355 (or (zerop (length msg))
1356 (progn
1357 (setq err-mess
1358 (concat (buffer-name Man-buffer)
1359 ": process "
1360 (let ((eos (1- (length msg))))
1361 (if (= (aref msg eos) ?\n)
1362 (substring msg 0 eos) msg))))
1363 (goto-char (point-max))
1364 (insert (format "\nprocess %s" msg))))
1365 ))
1366 (if delete-buff
1367 (kill-buffer Man-buffer)
1368 (if Man-fontify-manpage-flag
1369 (Man-fontify-manpage)
1370 (Man-cleanup-manpage))
55fb4ff7 1371
55535639 1372 (run-hooks 'Man-cooked-hook)
55fb4ff7
RS
1373 (Man-mode)
1374
1375 (if (not Man-page-list)
d1583c48 1376 (let ((args Man-arguments))
55fb4ff7 1377 (kill-buffer (current-buffer))
71873e2b
SM
1378 (user-error "Can't find the %s manpage"
1379 (Man-page-from-arguments args)))
d1583c48 1380 (set-buffer-modified-p nil))))
55535639
PJ
1381 ;; Restore case-fold-search before calling
1382 ;; Man-notify-when-ready because it may switch buffers.
1383
1384 (if (not delete-buff)
1385 (Man-notify-when-ready Man-buffer))
1386
1387 (if err-mess
8c16bd8c 1388 (error "%s" err-mess))
55535639
PJ
1389 ))))
1390
2f5c6024
LMI
1391(defun Man-page-from-arguments (args)
1392 ;; Skip arguments and only print the page name.
1393 (mapconcat
1394 'identity
1395 (delete nil
1396 (mapcar
1397 (lambda (elem)
1398 (and (not (string-match "^-" elem))
1399 elem))
1400 (split-string args " ")))
1401 " "))
1402
55535639
PJ
1403\f
1404;; ======================================================================
1405;; set up manual mode in buffer and build alists
1406
398a825b
SM
1407(defvar bookmark-make-record-function)
1408
3a1524ed
LK
1409(put 'Man-mode 'mode-class 'special)
1410
1b3b87df 1411(define-derived-mode Man-mode fundamental-mode "Man"
55535639
PJ
1412 "A mode for browsing Un*x manual pages.
1413
1414The following man commands are available in the buffer. Try
1415\"\\[describe-key] <key> RET\" for more information:
1416
1417\\[man] Prompt to retrieve a new manpage.
1418\\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
1419\\[Man-next-manpage] Jump to next manpage in circular list.
1420\\[Man-previous-manpage] Jump to previous manpage in circular list.
1421\\[Man-next-section] Jump to next manpage section.
1422\\[Man-previous-section] Jump to previous manpage section.
1423\\[Man-goto-section] Go to a manpage section.
1424\\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
1425\\[Man-quit] Deletes the manpage window, bury its buffer.
1426\\[Man-kill] Deletes the manpage window, kill its buffer.
1427\\[describe-mode] Prints this help text.
1428
1429The following variables may be of some use. Try
1430\"\\[describe-variable] <variable-name> RET\" for more information:
1431
1432`Man-notify-method' What happens when manpage formatting is done.
1433`Man-downcase-section-letters-flag' Force section letters to lower case.
1434`Man-circular-pages-flag' Treat multiple manpage list as circular.
1435`Man-section-translations-alist' List of section numbers and their Un*x equiv.
1436`Man-filter-list' Background manpage filter command.
55535639
PJ
1437`Man-mode-map' Keymap bindings for Man mode buffers.
1438`Man-mode-hook' Normal hook run on entry to Man mode.
1439`Man-section-regexp' Regexp describing manpage section letters.
1440`Man-heading-regexp' Regexp describing section headers.
1441`Man-see-also-regexp' Regexp for SEE ALSO section (or your equiv).
1442`Man-first-heading-regexp' Regexp for first heading on a manpage.
1443`Man-reference-regexp' Regexp matching a references in SEE ALSO.
1444`Man-switches' Background `man' command switches.
1445
1446The following key bindings are currently in effect in the buffer:
1447\\{Man-mode-map}"
1b3b87df 1448 (setq buffer-auto-save-file-name nil
c7cbaf4a
MB
1449 mode-line-buffer-identification
1450 (list (default-value 'mode-line-buffer-identification)
1451 " {" 'Man-page-mode-string "}")
55535639
PJ
1452 truncate-lines t
1453 buffer-read-only t)
430663bc 1454 (buffer-disable-undo)
55535639 1455 (auto-fill-mode -1)
aec2bd36 1456 (setq imenu-generic-expression (list (list nil Man-heading-regexp 0)))
ca7e59d4 1457 (imenu-add-to-menubar man-imenu-title)
aec2bd36
JL
1458 (set (make-local-variable 'outline-regexp) Man-heading-regexp)
1459 (set (make-local-variable 'outline-level) (lambda () 1))
45be326a 1460 (set (make-local-variable 'bookmark-make-record-function)
398a825b 1461 'Man-bookmark-make-record)
55535639
PJ
1462 (Man-build-page-list)
1463 (Man-strip-page-headers)
1464 (Man-unindent)
1b3b87df 1465 (Man-goto-page 1 t))
55535639
PJ
1466
1467(defsubst Man-build-section-alist ()
8b6c19f4
SM
1468 "Build the list of manpage sections."
1469 (setq Man--sections nil)
55535639
PJ
1470 (goto-char (point-min))
1471 (let ((case-fold-search nil))
1472 (while (re-search-forward Man-heading-regexp (point-max) t)
8b6c19f4
SM
1473 (let ((section (match-string 1)))
1474 (unless (member section Man--sections)
1475 (push section Man--sections)))
55535639
PJ
1476 (forward-line 1))))
1477
1478(defsubst Man-build-references-alist ()
8b6c19f4
SM
1479 "Build the list of references (in the SEE ALSO section)."
1480 (setq Man--refpages nil)
55535639
PJ
1481 (save-excursion
1482 (if (Man-find-section Man-see-also-regexp)
1483 (let ((start (progn (forward-line 1) (point)))
1484 (end (progn
1485 (Man-next-section 1)
1486 (point)))
1487 hyphenated
1488 (runningpoint -1))
1489 (save-restriction
1490 (narrow-to-region start end)
1491 (goto-char (point-min))
1492 (back-to-indentation)
1493 (while (and (not (eobp)) (/= (point) runningpoint))
1494 (setq runningpoint (point))
1495 (if (re-search-forward Man-hyphenated-reference-regexp end t)
72397ff1 1496 (let* ((word (match-string 0))
55535639
PJ
1497 (len (1- (length word))))
1498 (if hyphenated
1499 (setq word (concat hyphenated word)
1500 hyphenated nil
1501 ;; Update len, in case a reference spans
1502 ;; more than two lines (paranoia).
1503 len (1- (length word))))
327a6cca 1504 (if (memq (aref word len) '(?- ?­))
55535639 1505 (setq hyphenated (substring word 0 len)))
8b6c19f4
SM
1506 (and (string-match Man-reference-regexp word)
1507 (not (member word Man--refpages))
1508 (push word Man--refpages))))
55535639 1509 (skip-chars-forward " \t\n,"))))))
8b6c19f4 1510 (setq Man--refpages (nreverse Man--refpages)))
55535639
PJ
1511
1512(defun Man-build-page-list ()
1513 "Build the list of separate manpages in the buffer."
1514 (setq Man-page-list nil)
1515 (let ((page-start (point-min))
1516 (page-end (point-max))
1517 (header ""))
1518 (goto-char page-start)
1519 ;; (switch-to-buffer (current-buffer))(debug)
1520 (while (not (eobp))
1521 (setq header
1522 (if (looking-at Man-page-header-regexp)
72397ff1 1523 (match-string 1)
55535639
PJ
1524 nil))
1525 ;; Go past both the current and the next Man-first-heading-regexp
1526 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
1527 (let ((p (progn (beginning-of-line) (point))))
1528 ;; We assume that the page header is delimited by blank
1529 ;; lines and that it contains at most one blank line. So
1530 ;; if we back by three blank lines we will be sure to be
1531 ;; before the page header but not before the possible
1532 ;; previous page header.
1533 (search-backward "\n\n" nil t 3)
1534 (if (re-search-forward Man-page-header-regexp p 'move)
1535 (beginning-of-line))))
1536 (setq page-end (point))
1537 (setq Man-page-list (append Man-page-list
1538 (list (list (copy-marker page-start)
1539 (copy-marker page-end)
1540 header))))
1541 (setq page-start page-end)
1542 )))
1543
1544(defun Man-strip-page-headers ()
1545 "Strip all the page headers but the first from the manpage."
a88459cd 1546 (let ((inhibit-read-only t)
55535639 1547 (case-fold-search nil)
55535639 1548 (header ""))
a88459cd 1549 (dolist (page Man-page-list)
55535639
PJ
1550 (and (nth 2 page)
1551 (goto-char (car page))
1552 (re-search-forward Man-first-heading-regexp nil t)
1553 (setq header (buffer-substring (car page) (match-beginning 0)))
1554 ;; Since the awk script collapses all successive blank
1555 ;; lines into one, and since we don't want to get rid of
1556 ;; the fast awk script, one must choose between adding
1557 ;; spare blank lines between pages when there were none and
1558 ;; deleting blank lines at page boundaries when there were
1559 ;; some. We choose the first, so we comment the following
1560 ;; line.
1561 ;; (setq header (concat "\n" header)))
1562 (while (search-forward header (nth 1 page) t)
a88459cd 1563 (replace-match ""))))))
55535639
PJ
1564
1565(defun Man-unindent ()
1566 "Delete the leading spaces that indent the manpage."
a88459cd
SM
1567 (let ((inhibit-read-only t)
1568 (case-fold-search nil))
1569 (dolist (page Man-page-list)
1570 (let ((indent "")
55535639
PJ
1571 (nindent 0))
1572 (narrow-to-region (car page) (car (cdr page)))
1573 (if Man-uses-untabify-flag
ebfe2597
WJ
1574 ;; The space characters inserted by `untabify' inherit
1575 ;; sticky text properties, which is unnecessary and looks
1576 ;; ugly with underlining (Bug#11408).
1577 (let ((text-property-default-nonsticky
1578 (cons '(face . t) text-property-default-nonsticky)))
1579 (untabify (point-min) (point-max))))
55535639
PJ
1580 (if (catch 'unindent
1581 (goto-char (point-min))
1582 (if (not (re-search-forward Man-first-heading-regexp nil t))
1583 (throw 'unindent nil))
1584 (beginning-of-line)
1585 (setq indent (buffer-substring (point)
1586 (progn
1587 (skip-chars-forward " ")
1588 (point))))
1589 (setq nindent (length indent))
1590 (if (zerop nindent)
1591 (throw 'unindent nil))
1592 (setq indent (concat indent "\\|$"))
1593 (goto-char (point-min))
1594 (while (not (eobp))
1595 (if (looking-at indent)
1596 (forward-line 1)
1597 (throw 'unindent nil)))
1598 (goto-char (point-min)))
1599 (while (not (eobp))
1600 (or (eolp)
1601 (delete-char nindent))
1602 (forward-line 1)))
55535639
PJ
1603 ))))
1604
1605\f
1606;; ======================================================================
1607;; Man mode commands
1608
1609(defun Man-next-section (n)
1610 "Move point to Nth next section (default 1)."
1611 (interactive "p")
4cb071a4
SM
1612 (let ((case-fold-search nil)
1613 (start (point)))
55535639
PJ
1614 (if (looking-at Man-heading-regexp)
1615 (forward-line 1))
1616 (if (re-search-forward Man-heading-regexp (point-max) t n)
1617 (beginning-of-line)
65e07682
CY
1618 (goto-char (point-max))
1619 ;; The last line doesn't belong to any section.
4cb071a4
SM
1620 (forward-line -1))
1621 ;; But don't move back from the starting point (can happen if `start'
1622 ;; is somewhere on the last line).
1623 (if (< (point) start) (goto-char start))))
55535639
PJ
1624
1625(defun Man-previous-section (n)
1626 "Move point to Nth previous section (default 1)."
1627 (interactive "p")
1628 (let ((case-fold-search nil))
1629 (if (looking-at Man-heading-regexp)
1630 (forward-line -1))
1631 (if (re-search-backward Man-heading-regexp (point-min) t n)
1632 (beginning-of-line)
1633 (goto-char (point-min)))))
1634
1635(defun Man-find-section (section)
1636 "Move point to SECTION if it exists, otherwise don't move point.
1637Returns t if section is found, nil otherwise."
1638 (let ((curpos (point))
1639 (case-fold-search nil))
1640 (goto-char (point-min))
1641 (if (re-search-forward (concat "^" section) (point-max) t)
1642 (progn (beginning-of-line) t)
1643 (goto-char curpos)
1644 nil)
1645 ))
1646
8b6c19f4
SM
1647(defvar Man--last-section nil)
1648
1649(defun Man-goto-section (section)
1650 "Move point to SECTION."
1651 (interactive
1652 (let* ((default (if (member Man--last-section Man--sections)
1653 Man--last-section
1654 (car Man--sections)))
1655 (completion-ignore-case t)
1656 (prompt (concat "Go to section (default " default "): "))
1657 (chosen (completing-read prompt Man--sections
1658 nil nil nil nil default)))
1659 (list chosen)))
1660 (setq Man--last-section section)
1661 (unless (Man-find-section section)
1662 (error "Section %s not found" section)))
e709e39d 1663
55535639
PJ
1664
1665(defun Man-goto-see-also-section ()
110c171f 1666 "Move point to the \"SEE ALSO\" section.
55535639
PJ
1667Actually the section moved to is described by `Man-see-also-regexp'."
1668 (interactive)
1669 (if (not (Man-find-section Man-see-also-regexp))
8c16bd8c 1670 (error "%s" (concat "No " Man-see-also-regexp
55535639
PJ
1671 " section found in the current manpage"))))
1672
1673(defun Man-possibly-hyphenated-word ()
1674 "Return a possibly hyphenated word at point.
1675If the word starts at the first non-whitespace column, and the
1676previous line ends with a hyphen, return the last word on the previous
1677line instead. Thus, if a reference to \"tcgetpgrp(3V)\" is hyphenated
1678as \"tcgetp-grp(3V)\", and point is at \"grp(3V)\", we return
1679\"tcgetp-\" instead of \"grp\"."
1680 (save-excursion
1681 (skip-syntax-backward "w()")
1682 (skip-chars-forward " \t")
1683 (let ((beg (point))
1684 (word (current-word)))
1685 (when (eq beg (save-excursion
1686 (back-to-indentation)
1687 (point)))
1688 (end-of-line 0)
1689 (if (eq (char-before) ?-)
1690 (setq word (current-word))))
1691 word)))
1692
8b6c19f4
SM
1693(defvar Man--last-refpage nil)
1694
55535639
PJ
1695(defun Man-follow-manual-reference (reference)
1696 "Get one of the manpages referred to in the \"SEE ALSO\" section.
1697Specify which REFERENCE to use; default is based on word at point."
1698 (interactive
8b6c19f4 1699 (if (not Man--refpages)
55535639 1700 (error "There are no references in the current man page")
debe9205
JL
1701 (list
1702 (let* ((default (or
1703 (car (all-completions
1704 (let ((word
1705 (or (Man-possibly-hyphenated-word)
1706 "")))
1707 ;; strip a trailing '-':
1708 (if (string-match "-$" word)
1709 (substring word 0
1710 (match-beginning 0))
1711 word))
8b6c19f4
SM
1712 Man--refpages))
1713 (if (member Man--last-refpage Man--refpages)
1714 Man--last-refpage
1715 (car Man--refpages))))
debe9205
JL
1716 (defaults
1717 (mapcar 'substring-no-properties
8b6c19f4
SM
1718 (cons default Man--refpages)))
1719 (prompt (concat "Refer to (default " default "): "))
1720 (chosen (completing-read prompt Man--refpages
1721 nil nil nil nil defaults)))
1722 chosen))))
1723 (if (not Man--refpages)
55535639 1724 (error "Can't find any references in the current manpage")
8b6c19f4 1725 (setq Man--last-refpage reference)
55535639 1726 (Man-getpage-in-background
8b6c19f4 1727 (Man-translate-references reference))))
55535639
PJ
1728
1729(defun Man-kill ()
1730 "Kill the buffer containing the manpage."
1731 (interactive)
1732 (quit-window t))
1733
1734(defun Man-quit ()
1735 "Bury the buffer containing the manpage."
1736 (interactive)
1737 (quit-window))
1738
3ac3aabd 1739(defun Man-goto-page (page &optional noerror)
55535639
PJ
1740 "Go to the manual page on page PAGE."
1741 (interactive
1742 (if (not Man-page-list)
55fb4ff7 1743 (error "Not a man page buffer")
55535639
PJ
1744 (if (= (length Man-page-list) 1)
1745 (error "You're looking at the only manpage in the buffer")
1746 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1747 (length Man-page-list)))))))
55fb4ff7
RS
1748 (if (and (not Man-page-list) (not noerror))
1749 (error "Not a man page buffer"))
1750 (when Man-page-list
1751 (if (or (< page 1)
1752 (> page (length Man-page-list)))
71873e2b 1753 (user-error "No manpage %d found" page))
55fb4ff7
RS
1754 (let* ((page-range (nth (1- page) Man-page-list))
1755 (page-start (car page-range))
1756 (page-end (car (cdr page-range))))
1757 (setq Man-current-page page
1758 Man-page-mode-string (Man-make-page-mode-string))
1759 (widen)
1760 (goto-char page-start)
1761 (narrow-to-region page-start page-end)
1762 (Man-build-section-alist)
1763 (Man-build-references-alist)
1764 (goto-char (point-min)))))
55535639
PJ
1765
1766
1767(defun Man-next-manpage ()
1768 "Find the next manpage entry in the buffer."
1769 (interactive)
1770 (if (= (length Man-page-list) 1)
1771 (error "This is the only manpage in the buffer"))
1772 (if (< Man-current-page (length Man-page-list))
1773 (Man-goto-page (1+ Man-current-page))
1774 (if Man-circular-pages-flag
1775 (Man-goto-page 1)
1776 (error "You're looking at the last manpage in the buffer"))))
1777
1778(defun Man-previous-manpage ()
1779 "Find the previous manpage entry in the buffer."
1780 (interactive)
1781 (if (= (length Man-page-list) 1)
1782 (error "This is the only manpage in the buffer"))
1783 (if (> Man-current-page 1)
1784 (Man-goto-page (1- Man-current-page))
1785 (if Man-circular-pages-flag
1786 (Man-goto-page (length Man-page-list))
1787 (error "You're looking at the first manpage in the buffer"))))
4edd9faf
JB
1788
1789;; Header file support
1790(defun Man-view-header-file (file)
1791 "View a header file specified by FILE from `Man-header-file-path'."
1792 (let ((path Man-header-file-path)
1793 complete-path)
1794 (while path
a88459cd 1795 (setq complete-path (expand-file-name file (car path))
4edd9faf
JB
1796 path (cdr path))
1797 (if (file-readable-p complete-path)
1798 (progn (view-file complete-path)
1799 (setq path nil))
1800 (setq complete-path nil)))
1801 complete-path))
45be326a
TV
1802
1803;;; Bookmark Man Support
e44fa724
KF
1804(declare-function bookmark-make-record-default
1805 "bookmark" (&optional no-file no-context posn))
398a825b
SM
1806(declare-function bookmark-prop-get "bookmark" (bookmark prop))
1807(declare-function bookmark-default-handler "bookmark" (bmk))
1808(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
1809
1810(defun Man-default-bookmark-title ()
1811 "Default bookmark name for Man or WoMan pages.
1812Uses `Man-name-local-regexp'."
45be326a
TV
1813 (save-excursion
1814 (goto-char (point-min))
398a825b
SM
1815 (when (re-search-forward Man-name-local-regexp nil t)
1816 (skip-chars-forward "\n\t ")
45be326a
TV
1817 (buffer-substring-no-properties (point) (line-end-position)))))
1818
398a825b 1819(defun Man-bookmark-make-record ()
45be326a 1820 "Make a bookmark entry for a Man buffer."
398a825b 1821 `(,(Man-default-bookmark-title)
e44fa724 1822 ,@(bookmark-make-record-default 'no-file)
ebb9641f
SM
1823 (location . ,(concat "man " Man-arguments))
1824 (man-args . ,Man-arguments)
1825 (handler . Man-bookmark-jump)))
45be326a 1826
398a825b
SM
1827;;;###autoload
1828(defun Man-bookmark-jump (bookmark)
45be326a 1829 "Default bookmark handler for Man buffers."
398a825b
SM
1830 (let* ((man-args (bookmark-prop-get bookmark 'man-args))
1831 ;; Let bookmark.el do the window handling.
1832 ;; This let-binding needs to be active during the call to both
1833 ;; Man-getpage-in-background and accept-process-output.
1834 (Man-notify-method 'meek)
1835 (buf (Man-getpage-in-background man-args))
1836 (proc (get-buffer-process buf)))
1837 (while (and proc (eq (process-status proc) 'run))
1838 (accept-process-output proc))
45be326a
TV
1839 (bookmark-default-handler
1840 `("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bookmark)))))
1841
55535639
PJ
1842\f
1843;; Init the man package variables, if not already done.
1844(Man-init-defvars)
1845
55535639
PJ
1846(provide 'man)
1847
1848;;; man.el ends here