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