Commit | Line | Data |
---|---|---|
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 |
104 | This variable contains a list of the following form: |
105 | ||
106 | '((command-string phrase-string*)*) | |
107 | ||
108 | Each phrase-string is concatenated onto the command-string to form a | |
109 | command filter. The (standard) output (and standard error) of the Un*x | |
110 | man command is piped through each command filter in the order the | |
111 | commands appear in the association list. The final output is placed in | |
112 | the 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 |
155 | This variable may have one of the following values, where (sf) means |
156 | that the frames are switched, so the manpage is displayed in the frame | |
157 | where the man command was called from: | |
158 | ||
159 | newframe -- put the manpage in its own frame (see `Man-frame-parameters') | |
160 | pushy -- make the manpage the current buffer in the current window | |
161 | bully -- make the manpage the current buffer and only window (sf) | |
162 | aggressive -- make the manpage the current buffer in the other window (sf) | |
163 | friendly -- display manpage in the other window but don't make current (sf) | |
164 | polite -- don't display manpage, but prints message and beep when ready | |
165 | quiet -- like `polite', but don't beep | |
166 | meek -- make no indication that the manpage is ready | |
167 | ||
168 | Any 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 |
176 | If nil, the width of the window selected at the moment of man |
177 | invocation is used. If non-nil, the width of the frame selected | |
178 | at the moment of man invocation is used. The value also can be a | |
179 | positive 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 |
192 | Some Un*x man commands can't handle uppercase letters in sections, for |
193 | example \"man 2V chmod\", but they are often displayed in the manpage | |
194 | with the upper case letter. When this variable is t, the section | |
195 | letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before | |
196 | being 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 |
213 | Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in |
214 | their references which Un*x `man' does not recognize. This | |
215 | association list is used to translate those sections, when found, to | |
216 | the 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 | 240 | Used 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). | |
298 | This 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. |
305 | This 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). | |
319 | This 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). |
324 | This 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 |
354 | For example, the -a switch lets you see all the manpages for a |
355 | specified 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. | |
368 | Otherwise, 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 |
529 | This 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. | |
650 | Leave it as is if already in that style. Possibly downcase and | |
927c60bd JB |
651 | translate the section (see the `Man-downcase-section-letters-flag' |
652 | and 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. |
686 | Different man programs support this feature in different ways. | |
687 | The default Debian man program (\"man-db\") has a `--local-file' | |
688 | \(or `-l') option for this purpose. The default Red Hat man | |
689 | program has no such option, but interprets any name containing | |
690 | a \"/\" 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. | |
717 | POS 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. | |
816 | The value should be nil if \"man -k ^PREFIX\" may omit some man | |
817 | pages whose names start with PREFIX. | |
818 | ||
819 | Currently, the default value depends on `system-type' and is | |
820 | non-nil where the standard man programs are known to behave | |
821 | properly. Setting the value to nil always gives correct results | |
822 | but 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 | ||
827 | The current buffer should contain the output of a command of the | |
828 | form \"man -k keyword\", which is traditionally also available with | |
829 | apropos(1). | |
830 | ||
831 | While POSIX man(1p) is a bit vague about what to expect here, | |
832 | this function tries to parse some commonly used formats, which | |
833 | can be described in the following informal way, with square brackets | |
834 | indicating optional parts and whitespace being interpreted | |
835 | somewhat loosely. | |
836 | ||
837 | foo[, bar [, ...]] [other stuff] (sec) - description | |
838 | foo(sec)[, bar(sec) [, ...]] [other stuff] - description | |
839 | ||
840 | For more details and some regression tests, please see | |
841 | test/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 |
933 | This command is the top-level command in the man package. It |
934 | runs a Un*x command to retrieve and clean a manpage in the | |
935 | background and places the results in a `Man-mode' browsing | |
936 | buffer. See variable `Man-notify-method' for what happens when | |
937 | the buffer is ready. If a buffer already exists for this man | |
938 | page, it will display immediately. | |
939 | ||
940 | For a manpage from a particular section, use either of the | |
941 | following. \"cat(1)\" is how cross-references appear and is | |
942 | passed to man as \"1 cat\". | |
943 | ||
944 | cat(1) | |
945 | 1 cat | |
946 | ||
947 | To see manpages from all sections related to a subject, use an | |
948 | \"all pages\" option (which might be \"-a\" if it's not the | |
949 | default), then step through with `Man-next-manpage' (\\<Man-mode-map>\\[Man-next-manpage]) etc. | |
950 | Add to `Man-switches' to make this option permanent. | |
951 | ||
952 | -a chmod | |
953 | ||
954 | An explicit filename can be given too. Use -l if it might | |
955 | otherwise look like a page name. | |
956 | ||
957 | /my/file/name.1.gz | |
958 | -l somefile.1 | |
959 | ||
960 | An \"apropos\" query with -k gives a buffer of matching page | |
961 | names 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. |
1050 | Return 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. | |
1117 | See 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. | |
1169 | Same 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 | 1231 | References include items in the SEE ALSO section, |
71726072 EZ |
1232 | header file (#include <foo.h>), and files in FILES. |
1233 | If optional argument XREF-MAN-TYPE is non-nil, it used as the | |
1234 | button type for items in SEE ALSO section. If it is nil, the | |
1235 | default 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. | |
1285 | Normally skip any jobs that should have been done by the sed script, | |
1286 | but when called interactively, do those jobs even if the sed | |
1287 | script 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. | |
1317 | When manpage command is run asynchronously, PROCESS is the process | |
1318 | object for the manpage command; when manpage command is run | |
1319 | synchronously, PROCESS is the name of the buffer where the manpage | |
1320 | command is run. Second argument MSG is the exit message of the | |
1321 | manpage 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 | ||
1414 | The 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 | ||
1429 | The 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 | ||
1446 | The 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. | |
1637 | Returns 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 |
1667 | Actually 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. | |
1675 | If the word starts at the first non-whitespace column, and the | |
1676 | previous line ends with a hyphen, return the last word on the previous | |
1677 | line instead. Thus, if a reference to \"tcgetpgrp(3V)\" is hyphenated | |
1678 | as \"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. | |
1697 | Specify 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. | |
1812 | Uses `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 |