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