comparison lisp/packages/man.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; man.el --- browse UNIX manual pages
2 ;; Keywords: help
3
4 ;; Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc.
5 ;;
6 ;; This file is part of XEmacs.
7
8 ;; XEmacs is free software; you can redistribute it and/or modify it
9 ;; under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
11 ;; any later version.
12
13 ;; XEmacs is distributed in the hope that it will be useful, but
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;; General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with XEmacs; see the file COPYING. If not, write to the Free
20 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 ;;; Synched up with: Not synched with FSF.
23 ;;; ICK! This file is almost completely different from FSF.
24 ;;; Someone clarify please.
25
26 ;; Mostly rewritten by Alan K. Stebbens <aks@hub.ucsb.edu> 11-apr-90.
27 ;;
28 ;; o Match multiple man pages using TOPIC as a simple pattern
29 ;; o Search unformatted pages, even when formatted matches are found
30 ;; o Query the user as to which pages are desired
31 ;; o Use of the prefix arg to toggle/bypass the above features
32 ;; o Buffers named by the first topic in the buffer
33 ;; o Automatic uncompress for compressed man pages (.Z, .z, and .gz)
34 ;; o View the resulting buffer using M-x view mode
35 ;;
36 ;; Modified 16-mar-91 by Jamie Zawinski <jwz@lucid.com> to default the
37 ;; manual topic to the symbol at point, just like find-tag does.
38 ;;
39 ;; Modified 22-mar-93 by jwz to use multiple fonts and follow xrefs with mouse.
40 ;;
41 ;; Modified 16-apr-93 by Dave Gillespie <daveg@synaptics.com> to make
42 ;; apropos work nicely; work correctly when bold or italic is unavailable;
43 ;; reuse old buffer if topic is re-selected (in Manual-topic-buffer mode).
44 ;;
45 ;; Modified 4-apr-94 by jwz: merged in Tibor Polgar's code for manpath.conf.
46 ;;
47 ;; Modified 19-apr-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
48 ;; $PAGER variable to be emacsclient and properly process man pages (assuming
49 ;; the man pages were built by man in /tmp. also fixed bug with man list being
50 ;; backwards.
51 ;;
52 ;; Modified 23-aug-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
53 ;; displaying only one instance of a man page (Manual-unique-man-sections-only)
54 ;; Fixed some more man page ordering bugs, bug with Manual-query-multiple-pages.
55 ;;
56 ;; Modified 29-nov-94 by Ben Wing <wing@spg.amdahl.com>: small fixes
57 ;; that should hopefully make things work under HPUX and IRIX.;
58 ;;
59 ;; Modified 15-jul-95 by Dale Atems <atems@physics.wayne.edu>:
60 ;; some extensive rewriting to make things work right (more or less)
61 ;; under IRIX.
62 ;;
63 ;; Modified 08-mar-96 by Hubert Palme <palme@wrcs3.urz.uni-wuppertal.de>:
64 ;; added /usr/share/catman to the manual directory list for IRIX (5.3)
65 ;;
66 ;; This file defines "manual-entry", and the remaining definitions all
67 ;; begin with "Manual-". This makes the autocompletion on "M-x man" work.
68 ;;
69 ;; Variables of interest:
70 ;;
71 ;; Manual-program
72 ;; Manual-topic-buffer
73 ;; Manual-buffer-view-mode
74 ;; Manual-directory-list
75 ;; Manual-formatted-directory-list
76 ;; Manual-match-topic-exactly
77 ;; Manual-query-multiple-pages
78 ;; Manual-page-history
79 ;; Manual-subdirectory-list
80 ;; Manual-man-page-section-ids
81 ;; Manual-formatted-page-prefix
82 ;; Manual-unformatted-page-prefix
83 ;; Manual-use-full-section-ids
84
85 (defvar Manual-program "man" "\
86 *Name of the program to invoke in order to format the source man pages.")
87
88 (defvar Manual-section-switch (if (eq system-type 'usg-unix-v) "-s" nil)
89 "SysV needs this to work right.")
90
91 (defvar Manual-topic-buffer t "\
92 *Non-nil means \\[Manual-entry] should output the manual entry for TOPIC into
93 a buffer named *man TOPIC*, otherwise, it should name the buffer
94 *Manual Entry*.")
95
96 (defvar Manual-buffer-view-mode t "\
97 *Whether manual buffers should be placed in view-mode.
98 nil means leave the buffer in fundamental-mode in another window.
99 t means use `view-buffer' to display the man page in the current window.
100 Any other value means use `view-buffer-other-window'.")
101
102 (defvar Manual-match-topic-exactly t "\
103 *Non-nil means that \\[manual-entry] will match the given TOPIC exactly, rather
104 apply it as a pattern. When this is nil, and \"Manual-query-multiple-pages\"
105 is non-nil, then \\[manual-entry] will query you for all matching TOPICs.
106 This variable only has affect on the preformatted man pages (the \"cat\" files),
107 since the \"man\" command always does exact topic matches.")
108
109 (defvar Manual-query-multiple-pages nil "\
110 *Non-nil means that \\[manual-entry] will query the user about multiple man
111 pages which match the given topic. The query is done using the function
112 \"y-or-n-p\". If this variable is nil, all man pages with topics matching the
113 topic given to \\[manual-entry] will be inserted into the temporary buffer.
114 See the variable \"Manual-match-topic-exactly\" to control the matching.")
115
116 (defvar Manual-unique-man-sections-only nil
117 "*Only present one man page per section. This variable is useful if the same or
118 up/down level man pages for the same entry are present in mulitple man paths.
119 When set to t, only the first entry found in a section is displayed, the others
120 are ignored without any messages or warnings. Note that duplicates can occur if
121 the system has both formatted and unformatted version of the same page.")
122
123 (defvar Manual-mode-hook nil
124 "Function or functions run on entry to Manual-mode.")
125
126 (defvar Manual-directory-list nil "\
127 *A list of directories used with the \"man\" command, where each directory
128 contains a set of \"man?\" and \"cat?\" subdirectories. If this variable is nil,
129 it is initialized by \\[Manual-directory-list-init].")
130
131 (defvar Manual-formatted-directory-list nil "\
132 A list of directories containing formatted man pages. Initialized by
133 \\[Manual-directory-list-init].")
134
135 (defvar Manual-unformatted-directory-list nil "\
136 A list of directories containing the unformatted (source) man pages.
137 Initialized by \\[Manual-directory-list-init].")
138
139 (defvar Manual-page-history nil "\
140 A list of names of previously visited man page buffers.")
141
142 (defvar Manual-manpath-config-file "/usr/lib/manpath.config"
143 "*Location of the manpath.config file, if any.")
144
145 (defvar Manual-apropos-switch "-k"
146 "*Man apropos switch")
147
148 ;; New variables.
149
150 (defvar Manual-subdirectory-list nil "\
151 A list of all the subdirectories in which man pages may be found.
152 Iniialized by Manual-directory-list-init.")
153
154 ;; This is for SGI systems; don't know what it should be otherwise.
155 (defvar Manual-man-page-section-ids "1nl6823457poD" "\
156 String containing all suffix characters for \"cat\" and \"man\"
157 that identify valid sections of the Un*x manual.")
158
159 (defvar Manual-formatted-page-prefix "cat" "\
160 Prefix for directories where formatted man pages are to be found.
161 Defaults to \"cat\".")
162
163 (defvar Manual-unformatted-page-prefix "man" "\
164 Prefix for directories where unformatted man pages are to be found.
165 Defaults to \"man\".")
166
167 (defvar Manual-leaf-signature "" "\
168 Regexp for identifying \"leaf\" subdirectories in the search path.
169 If empty, initialized by Manual-directory-list-init.")
170
171 (defvar Manual-use-full-section-ids t "\
172 If non-nil, pass full section ids to Manual-program, otherwise pass
173 only the first character. Defaults to 't'.")
174
175 (defvar Manual-use-subdirectory-list (eq system-type 'irix) "\
176 This makes manual-entry work correctly on SGI machines but it
177 imposes a large startup cost which is why it is not simply on by
178 default on all systems.")
179
180 (defvar Manual-use-rosetta-man (not (null (locate-file "rman" exec-path))) "\
181 If non-nil, use RosettaMan (rman) to filter man pages.
182 This makes man-page cleanup virtually instantaneous, instead of
183 potentially taking a long time.
184
185 Here is information on RosettaMan, from Neal.Becker@comsat.com (Neal Becker):
186
187 RosettaMan is a filter for UNIX manual pages. It takes as input man
188 pages formatted for a variety of UNIX flavors (not [tn]roff source)
189 and produces as output a variety of file formats. Currently
190 RosettaMan accepts man pages as formatted by the following flavors of
191 UNIX: Hewlett-Packard HP-UX, AT&T System V, SunOS, Sun Solaris, OSF/1,
192 DEC Ultrix, SGI IRIX, Linux, SCO; and produces output for the following
193 formats: printable ASCII only (stripping page headers and footers),
194 section and subsection headers only, TkMan, [tn]roff, Ensemble, RTF,
195 SGML (soon--I finally found a DTD), HTML, MIME, LaTeX, LaTeX 2e, Perl 5's pod.
196
197 RosettaMan improves on other man page filters in several ways: (1) its
198 analysis recognizes the structural pieces of man pages, enabling high
199 quality output, (2) its modular structure permits easy augmentation of
200 output formats, (3) it accepts man pages formatted with the varient
201 macros of many different flavors of UNIX, and (4) it doesn't require
202 modification or cooperation with any other program.
203
204 RosettaMan is a rewrite of TkMan's man page filter, called bs2tk. (If
205 you haven't heard about TkMan, a hypertext man page browser, you
206 should grab it via anonymous ftp from ftp.cs.berkeley.edu:
207 /ucb/people/phelps/tkman.tar.Z.) Whereas bs2tk generated output only for
208 TkMan, RosettaMan generalizes the process so that the analysis can be
209 leveraged to new output formats. A single analysis engine recognizes
210 section heads, subsection heads, body text, lists, references to other
211 man pages, boldface, italics, bold italics, special characters (like
212 bullets), tables (to a degree) and strips out page headers and
213 footers. The engine sends signals to the selected output functions so
214 that an enhancement in the engine improves the quality of output of
215 all of them. Output format functions are easy to add, and thus far
216 average about about 75 lines of C code each.
217
218
219
220 *** NOTES ON CURRENT VERSION ***
221
222 Help! I'm looking for people to help with the following projects.
223 \(1) Better RTF output format. The current one works, but could be
224 made better. (2) Roff macros that produce text that is easily
225 parsable. RosettaMan handles a great variety, but some things, like
226 H-P's tables, are intractable. If you write an output format or
227 otherwise improve RosettaMan, please send in your code so that I may
228 share the wealth in future releases.
229
230 This version can try to identify tables (turn this on with the -T
231 switch) by looking for lines with a large amount of interword spacing,
232 reasoning that this is space between columns of a table. This
233 heuristic doesn't always work and sometimes misidentifies ordinary
234 text as tables. In general I think it is impossible to perfectly
235 identify tables from nroff formatted text. However, I do think the
236 heuristics can be tuned, so if you have a collection of manual pages
237 with unrecognized tables, send me the lot, in formatted form (i.e.,
238 after formatting with nroff -man), and uuencode them to preserve the
239 control characters. Better, if you can think of heuristics that
240 distinguish tables from ordinary text, I'd like to hear them.
241
242
243 Notes for HTML consumers: This filter does real (heuristic)
244 parsing--no <PRE>! Man page references are turned into hypertext links.")
245
246 (make-face 'man-italic)
247 (or (face-differs-from-default-p 'man-italic)
248 (copy-face 'italic 'man-italic))
249 ;; XEmacs (from Darrell Kindred): underlining is annoying due to
250 ;; large blank spaces in this face.
251 ;; (or (face-differs-from-default-p 'man-italic)
252 ;; (set-face-underline-p 'man-italic t))
253
254 (make-face 'man-bold)
255 (or (face-differs-from-default-p 'man-bold)
256 (copy-face 'bold 'man-bold))
257 (or (face-differs-from-default-p 'man-bold)
258 (copy-face 'man-italic 'man-bold))
259
260 (make-face 'man-heading)
261 (or (face-differs-from-default-p 'man-heading)
262 (copy-face 'man-bold 'man-heading))
263
264 (make-face 'man-xref)
265 (or (face-differs-from-default-p 'man-xref)
266 (set-face-underline-p 'man-xref t))
267
268 ;; Manual-directory-list-init
269 ;; Initialize the directory lists.
270
271 (defun Manual-directory-list-init (&optional arg)
272 "Initialize the Manual-directory-list variable from $MANPATH
273 if it is not already set, or if a prefix argument is provided."
274 (interactive "P")
275 (if arg (setq Manual-directory-list nil))
276 (if (null Manual-directory-list)
277 (let ((manpath (getenv "MANPATH"))
278 (global (Manual-manpath-config-contents))
279 (dirlist nil)
280 dir)
281 (cond ((and manpath global)
282 (setq manpath (concat manpath ":" global)))
283 (global
284 (setq manpath global))
285 ((not manpath)
286 ;; XEmacs - (bpw/stig) Unix-specifix hack for lusers w/ no manpath
287 (setq manpath "/usr/local/man:/usr/share/man:/usr/share/catman:/usr/contrib/man:/usr/X11/man:/usr/man:/usr/catman")))
288 ;; Make sure that any changes we've made internally are seen by man.
289 (setenv "MANPATH" manpath)
290 (while (string-match "\\`:*\\([^:]+\\)" manpath)
291 (setq dir (substring manpath (match-beginning 1) (match-end 1)))
292 (and (not (member dir dirlist))
293 (setq dirlist (cons dir dirlist)))
294 (setq manpath (substring manpath (match-end 0))))
295 (setq dirlist (nreverse dirlist))
296 (setq Manual-directory-list dirlist)
297 (setq Manual-subdirectory-list nil)
298 (setq Manual-formatted-directory-list nil)
299 (setq Manual-unformatted-directory-list nil)))
300 (if (string-equal Manual-leaf-signature "")
301 (setq Manual-leaf-signature
302 (concat "/\\("
303 Manual-formatted-page-prefix
304 "\\|" Manual-unformatted-page-prefix
305 "\\)"
306 "[" Manual-man-page-section-ids
307 "].?/.")))
308 (if Manual-use-subdirectory-list
309 (progn
310 (if (null Manual-subdirectory-list)
311 (setq Manual-subdirectory-list
312 (Manual-all-subdirectories Manual-directory-list
313 Manual-leaf-signature nil)))
314 (if (null Manual-formatted-directory-list)
315 (setq Manual-formatted-directory-list
316 (Manual-filter-subdirectories Manual-subdirectory-list
317 Manual-formatted-page-prefix)))
318 (if (null Manual-unformatted-directory-list)
319 (setq Manual-unformatted-directory-list
320 (Manual-filter-subdirectories Manual-subdirectory-list
321 Manual-unformatted-page-prefix))))
322 (if (null Manual-formatted-directory-list)
323 (setq Manual-formatted-directory-list
324 (Manual-select-subdirectories Manual-directory-list
325 Manual-formatted-page-prefix)))
326 (if (null Manual-unformatted-directory-list)
327 (setq Manual-unformatted-directory-list
328 (Manual-select-subdirectories Manual-directory-list
329 Manual-unformatted-page-prefix)))))
330
331
332 (defun Manual-manpath-config-contents ()
333 "Parse the `Manual-manpath-config-file' file, if any.
334 Returns a string like in $MANPATH."
335 (if (and Manual-manpath-config-file
336 (file-readable-p Manual-manpath-config-file))
337 (let ((buf (get-buffer-create " *Manual-config*"))
338 path)
339 (set-buffer buf)
340 (buffer-disable-undo buf)
341 (erase-buffer)
342 (insert-file-contents Manual-manpath-config-file)
343 (while (re-search-forward "^\\(MANDATORY_MANPATH\\|MANPATH_MAP\\)"
344 nil t)
345 (and (re-search-forward "\\(/[^ \t\n]+\\)[ \t]*$")
346 (setq path (concat path (buffer-substring (match-beginning 1)
347 (match-end 1))
348 ":"))))
349 (kill-buffer buf)
350 path)))
351 ;;
352 ;; manual-entry -- The "main" user function
353 ;;
354
355 ;;;###autoload
356 (defun manual-entry (topic &optional arg silent)
357 "Display the Unix manual entry (or entries) for TOPIC.
358 If prefix arg is given, modify the search according to the value:
359 2 = complement default exact matching of the TOPIC name;
360 exact matching default is specified by `Manual-match-topic-exactly'
361 3 = force a search of the unformatted man directories
362 4 = both 2 and 3
363 The manual entries are searched according to the variable
364 Manual-directory-list, which should be a list of directories. If
365 Manual-directory-list is nil, \\[Manual-directory-list-init] is
366 invoked to create this list from the MANPATH environment variable.
367 See the variable Manual-topic-buffer which controls how the buffer
368 is named. See also the variables Manual-match-topic-exactly,
369 Manual-query-multiple-pages, and Manual-buffer-view-mode."
370 (interactive
371 (list (let* ((fmh "-A-Za-z0-9_.")
372 (default (save-excursion
373 (buffer-substring
374 (progn
375 (re-search-backward "\\sw" nil t)
376 (skip-chars-backward fmh) (point))
377 (progn (skip-chars-forward fmh) (point)))))
378 (thing (read-string
379 (if (equal default "") "Manual entry: "
380 (concat "Manual entry: (default " default ") ")))))
381 (if (equal thing "") default thing))
382 (prefix-numeric-value current-prefix-arg)))
383 ;;(interactive "sManual entry (topic): \np")
384 (or arg (setq arg 1))
385 (Manual-directory-list-init nil)
386 (let ((exact (if (or (= arg 2) (= arg 4))
387 (not Manual-match-topic-exactly)
388 Manual-match-topic-exactly))
389 (force (if (>= arg 3)
390 t
391 nil))
392 section fmtlist manlist apropos-mode)
393 (let ((case-fold-search nil))
394 (if (and (null section)
395 (string-match
396 "\\`[ \t]*\\([^( \t]+\\)[ \t]*(\\(.+\\))[ \t]*\\'" topic))
397 (setq section (substring topic (match-beginning 2)
398 (match-end 2))
399 topic (substring topic (match-beginning 1)
400 (match-end 1)))
401 (if (string-match "\\`[ \t]*-k[ \t]+\\([^ \t]+\\)\\'" topic)
402 (setq section "-k"
403 topic (substring topic (match-beginning 1))))))
404 (if (equal section "-k")
405 (setq apropos-mode t)
406 (or silent
407 (message "Looking for formatted entry for %s%s..."
408 topic (if section (concat "(" section ")") "")))
409 (setq fmtlist (Manual-select-man-pages
410 Manual-formatted-directory-list
411 topic section exact '()))
412 (if (or force (not section) (null fmtlist))
413 (progn
414 (or silent
415 (message "%sooking for unformatted entry for %s%s..."
416 (if fmtlist "L" "No formatted entry, l")
417 topic (if section (concat "(" section ")") "")))
418 (setq manlist (Manual-select-man-pages
419 Manual-unformatted-directory-list
420 topic section exact (if force '() fmtlist))))))
421
422 ;; Delete duplicate man pages (a file of the same name in multiple
423 ;; directories.)
424 (or nil ;force
425 (let ((rest (append fmtlist manlist)))
426 (while rest
427 (let ((rest2 (cdr rest)))
428 (while rest2
429 (if (equal (file-name-nondirectory (car rest))
430 (file-name-nondirectory (car rest2)))
431 (setq fmtlist (delq (car rest2) fmtlist)
432 manlist (delq (car rest2) manlist)))
433 (setq rest2 (cdr rest2))))
434 (setq rest (cdr rest)))))
435
436 (if (not (or fmtlist manlist apropos-mode))
437 (progn
438 (message "No entries found for %s%s" topic
439 (if section (concat "(" section ")") ""))
440 nil)
441 (let ((bufname (cond ((not Manual-topic-buffer)
442 ;; What's the point of retaining this?
443 (if apropos-mode
444 "*Manual Apropos*"
445 "*Manual Entry*"))
446 (apropos-mode
447 (concat "*man apropos " topic "*"))
448 (t
449 (concat "*man "
450 (cond (exact
451 (if section
452 (concat topic "." section)
453 topic))
454 ((or (cdr fmtlist) (cdr manlist)
455 (and fmtlist manlist))
456 ;; more than one entry found
457 (concat topic "..."))
458 (t
459 (file-name-nondirectory
460 (car (or fmtlist manlist)))))
461 "*"))))
462 (temp-buffer-show-function
463 (cond ((eq 't Manual-buffer-view-mode) 'view-buffer)
464 ((eq 'nil Manual-buffer-view-mode)
465 temp-buffer-show-function)
466 (t 'view-buffer-other-window))))
467
468 (if apropos-mode
469 (setq manlist (list (format "%s.%s" topic section))))
470
471 (cond
472 ((and Manual-topic-buffer (get-buffer bufname))
473 ;; reselect an old man page buffer if it exists already.
474 (save-excursion
475 (set-buffer (get-buffer bufname))
476 (Manual-mode))
477 (if temp-buffer-show-function
478 (funcall temp-buffer-show-function (get-buffer bufname))
479 (display-buffer bufname)))
480 (t
481 (with-output-to-temp-buffer bufname
482 (buffer-disable-undo standard-output)
483 (save-excursion
484 (set-buffer standard-output)
485 (setq buffer-read-only nil)
486 (erase-buffer)
487 (Manual-insert-pages fmtlist manlist apropos-mode)
488 (set-buffer-modified-p nil)
489 (Manual-mode)
490 ))))
491 (setq Manual-page-history
492 (cons (buffer-name)
493 (delete (buffer-name) Manual-page-history)))
494 (message nil)
495 t))))
496
497 (defun Manpage-apropos (topic &optional arg silent)
498 "Apropos on Unix manual pages for TOPIC.
499 It calls the function `manual-entry'. Look at this function for
500 further description. Look also at the variable `Manual-apropos-switch',
501 if this function doesn't work on your system."
502 (interactive
503 (list (let* ((fmh "-A-Za-z0-9_.")
504 (default (save-excursion
505 (buffer-substring
506 (progn
507 (re-search-backward "\\sw" nil t)
508 (skip-chars-backward fmh) (point))
509 (progn (skip-chars-forward fmh) (point)))))
510 (thing (read-string
511 (if (equal default "") "Manual entry: "
512 (concat "Manual entry: (default " default ") ")))))
513 (if (equal thing "") default thing))
514 (prefix-numeric-value current-prefix-arg)))
515 (manual-entry (concat Manual-apropos-switch " " topic) arg silent))
516
517 (defun Manual-insert-pages (fmtlist manlist apropos-mode)
518 (let ((sep (make-string 65 ?-))
519 name start end topic section)
520 (while fmtlist ; insert any formatted files
521 (setq name (car fmtlist))
522 (goto-char (point-max))
523 (setq start (point))
524 ;; In case the file can't be read or uncompressed or
525 ;; something like that.
526 (condition-case ()
527 (Manual-insert-man-file name)
528 (file-error nil))
529 (goto-char (point-max))
530 (setq end (point))
531 (save-excursion
532 (save-restriction
533 (message "Cleaning manual entry for %s..."
534 (file-name-nondirectory name))
535 (narrow-to-region start end)
536 (Manual-nuke-nroff-bs)
537 (goto-char (point-min))
538 (insert "File: " name "\n")
539 (goto-char (point-max))
540 ))
541 (if (or (cdr fmtlist) manlist)
542 (insert "\n\n" sep "\n"))
543 (setq fmtlist (cdr fmtlist)))
544
545 (while manlist ; process any unformatted files
546 (setq name (car manlist))
547 (or (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\(\\.gz\\'\\)" name)
548 (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\'" name))
549 (setq topic (substring name (match-beginning 1) (match-end 1)))
550 (setq section (substring name (match-beginning 2) (match-end 2)))
551 ;; This won't work under IRIX, because SGI man accepts only the
552 ;; "main" (one-character) section id, not full section ids
553 ;; like 1M, 3X, etc. Put (setq Manual-use-full-section-ids nil)
554 ;; in your .emacs to work around this problem.
555 (if (not (or Manual-use-full-section-ids (string-equal section "")))
556 (setq section (substring section 0 1)))
557 (message "Invoking man %s%s %s..."
558 (if Manual-section-switch
559 (concat Manual-section-switch " ")
560 "")
561 section topic)
562 (setq start (point))
563 (Manual-run-formatter name topic section)
564 (setq end (point))
565 (save-excursion
566 (save-restriction
567 (message "Cleaning manual entry for %s(%s)..." topic section)
568 (narrow-to-region start end)
569 (Manual-nuke-nroff-bs apropos-mode)
570 (goto-char (point-min))
571 (insert "File: " name "\n")
572 (goto-char (point-max))
573 ))
574 (if (cdr manlist)
575 (insert "\n\n" sep "\n"))
576 (setq manlist (cdr manlist))))
577 (if (< (buffer-size) 200)
578 (progn
579 (goto-char (point-min))
580 (if (looking-at "^File: ")
581 (forward-line 1))
582 (error (buffer-substring (point) (progn (end-of-line) (point))))))
583 nil)
584
585
586 (defun Manual-run-formatter (name topic section)
587 (cond
588 ((string-match "roff\\'" Manual-program)
589 ;; kludge kludge
590 (call-process Manual-program nil t nil "-Tman" "-man" name))
591
592 (t
593 (call-process Manual-program nil t nil
594 (concat Manual-section-switch section) topic))))
595
596 ;(Manual-use-rosetta-man
597 ; (call-process "/bin/sh" nil t nil "-c"
598 ; (format "man %s %s | rman" section topic)))
599
600
601 (defvar Manual-mode-map
602 (let ((m (make-sparse-keymap)))
603 (set-keymap-name m 'Manual-mode-map)
604 (define-key m "l" 'Manual-last-page)
605 (define-key m 'button2 'Manual-follow-xref)
606 (define-key m 'button3 'Manual-popup-menu)
607 m))
608
609 (defun Manual-mode ()
610 (kill-all-local-variables)
611 (setq buffer-read-only t)
612 (use-local-map Manual-mode-map)
613 (setq major-mode 'Manual-mode
614 mode-name "Manual")
615 ;; man pages with long lines are buggy!
616 ;; This looks slightly better if they only
617 ;; overran by a couple of chars.
618 (setq truncate-lines t)
619 ;; turn off horizontal scrollbars in this buffer
620 (set-specifier scrollbar-height (cons (current-buffer) 0))
621 (run-hooks 'Manual-mode-hook))
622
623 (defun Manual-last-page ()
624 (interactive)
625 (while (or (not (get-buffer (car (or Manual-page-history
626 (error "No more history.")))))
627 (eq (get-buffer (car Manual-page-history)) (current-buffer)))
628 (setq Manual-page-history (cdr Manual-page-history)))
629 (switch-to-buffer (car Manual-page-history)))
630
631
632 ;; Manual-select-subdirectories
633 ;; Given a DIRLIST and a SUBDIR name, return all subdirectories of the former which
634 ;; match the latter.
635
636 (defun Manual-select-subdirectories (dirlist subdir)
637 (let ((dirs '())
638 (case-fold-search nil)
639 (match (concat "\\`" (regexp-quote subdir)))
640 d)
641 (while dirlist
642 (setq d (car dirlist) dirlist (cdr dirlist))
643 (if (file-directory-p d)
644 (let ((files (directory-files d t match nil 'dirs-only))
645 (dir-temp '()))
646 (while files
647 (if (file-executable-p (car files))
648 (setq dir-temp (cons (file-name-as-directory (car files))
649 dir-temp)))
650 (setq files (cdr files)))
651 (and dir-temp
652 (setq dirs (append dirs (nreverse dir-temp)))))))
653 dirs))
654
655
656 ;; Manual-filter-subdirectories
657 ;; Given a DIRLIST and a SUBDIR name, return all members of the former
658 ;; which match the latter.
659
660 (defun Manual-filter-subdirectories (dirlist subdir)
661 (let ((match (concat
662 "/"
663 (regexp-quote subdir)
664 "[" Manual-man-page-section-ids "]"))
665 slist dir)
666 (while dirlist
667 (setq dir (car dirlist) dirlist (cdr dirlist))
668 (if (and (file-executable-p dir) (string-match match dir))
669 (setq slist (cons dir slist))))
670 (nreverse slist)))
671
672
673 (defun Manual-all-subdirectories (dirlist leaf-signature dirs &optional silent) "\
674 Given a DIRLIST, return a backward-sorted list of all subdirectories
675 thereof, prepended to DIRS if non-nil. This function calls itself
676 recursively until subdirectories matching LEAF-SIGNATURE are reached,
677 or the hierarchy has been thoroughly searched. This code is a modified
678 version of a function written by Tim Bradshaw (tfb@ed.ac.uk)."
679 (Manual-all-subdirectories-noloop dirlist leaf-signature dirs nil silent))
680
681 (defun Manual-all-subdirectories-noloop (dirlist leaf-signature dirs been &optional silent) "\
682 Does the job of manual-all-subdirectories and keeps track of where it
683 has been to avoid loops."
684 (let (dir)
685 (while dirlist
686 (setq dir (car dirlist) dirlist (cdr dirlist))
687 (if (file-directory-p dir)
688 (let ((dir-temp (cons (file-name-as-directory dir) dirs)))
689 ;; Without feedback the user might wonder about the delay!
690 (or silent (message
691 "Building list of search directories... %s"
692 (car dir-temp)))
693 (if (member (file-truename dir) been)
694 () ; Ignore. We have been here before
695 (setq been (cons (file-truename dir) been))
696 (setq dirs
697 (if (string-match leaf-signature dir)
698 dir-temp
699 (Manual-all-subdirectories-noloop
700 (directory-files dir t "[^.]$" nil 'dirs-only)
701 leaf-signature dir-temp been silent))))))))
702 dirs)
703
704
705 (defvar Manual-bogus-file-pattern "\\.\\(lpr\\|ps\\|PS\\)\\'"
706 "Some systems have files in the man/man*/ directories which aren't man pages.
707 This pattern is used to prune those files.")
708
709 ;; Manual-select-man-pages
710 ;;
711 ;; Given a DIRLIST, discover all filenames which complete given the TOPIC
712 ;; and SECTION.
713
714 ;; ## Note: BSD man looks for .../man1/foo.1 and .../man1/$MACHINE/foo.1
715
716 ;; ## Fixed for SGI IRIX 5.x on Sat Jul 15 1995 by Dale Atems
717 ;; (atems@physics.wayne.edu).
718
719 (defun Manual-select-man-pages (dirlist topic section exact shadow)
720 (let ((case-fold-search nil))
721 (and section
722 (let ((l '())
723 ;;(match (concat (substring section 0 1) "/?\\'"))
724 ;; ^^^
725 ;; We'll lose any pages inside subdirectories of the "standard"
726 ;; ones if we insist on this! The following regexp should
727 ;; match any directory ending with the full section id or
728 ;; its first character, or any direct subdirectory thereof:
729 (match (concat "\\("
730 (regexp-quote section)
731 "\\|"
732 (substring section 0 1)
733 "\\)/?"))
734 d)
735 (while dirlist
736 (setq d (car dirlist) dirlist (cdr dirlist))
737 (if (string-match match d)
738 (setq l (cons d l))))
739 (setq dirlist l)))
740 (if shadow
741 (setq shadow (concat "/\\("
742 (mapconcat #'(lambda (n)
743 (regexp-quote
744 (file-name-nondirectory n)))
745 shadow
746 "\\|")
747 "\\)\\'")))
748 (let ((manlist '())
749 (match (concat "\\`"
750 (regexp-quote topic)
751 ;; **Note: on IRIX the preformatted pages
752 ;; are packed, so they end with ".z". This
753 ;; way you miss them if you specify a
754 ;; section. I don't see any point to it here
755 ;; even on BSD systems since we're looking
756 ;; one level down already, but I can't test
757 ;; this. More thought needed (???)
758
759 (cond ((and section
760 (not Manual-use-subdirectory-list))
761 (concat "\\." (regexp-quote section)))
762 (exact
763 ;; If Manual-match-topic-exactly is
764 ;; set, then we must make sure the
765 ;; completions are exact, except for
766 ;; trailing weird characters after
767 ;; the section.
768 "\\.")
769 (t
770 ""))))
771 dir)
772 (while dirlist
773 (setq dir (car dirlist) dirlist (cdr dirlist))
774 (if (not (file-directory-p dir))
775 (progn
776 (message "warning: %s is not a directory" dir)
777 ;;(sit-for 1)
778 )
779 (let ((files (directory-files dir t match nil t))
780 f)
781 (while files
782 (setq f (car files) files (cdr files))
783 (cond ((string-match Manual-bogus-file-pattern f)
784 ;(message "Bogus fule %s" f) (sit-for 2)
785 )
786 ((and shadow (string-match shadow f))
787 ;(message "Shadowed %s" f) (sit-for 2)
788 )
789 ((not (file-readable-p f))
790 ;(message "Losing with %s" f) (sit-for 2)
791 )
792 (t
793 (setq manlist (cons f manlist))))))))
794 (setq manlist (nreverse manlist))
795 (and Manual-unique-man-sections-only
796 (setq manlist (Manual-clean-to-unique-pages-only manlist)))
797 (if (and manlist Manual-query-multiple-pages)
798 (apply #'append
799 (mapcar #'(lambda (page)
800 (and page
801 (y-or-n-p (format "Read %s? " page))
802 (list page)))
803 manlist))
804 manlist))))
805
806 (defun Manual-clean-to-unique-pages-only (manlist)
807 "Prune the current list of pages down to a unique set."
808 (let (page-name unique-pages)
809 (apply 'append
810 (mapcar '(lambda (page)
811 (cond (page
812 (and (string-match ".*/\\(.*\\)" page)
813 (setq page-name (substring page (match-beginning 1)
814 (match-end 1)))
815 ;; try to clip off .Z, .gz suffixes
816 (and (string-match "\\(.*\\)\\.\\(.+\\)\\.\\(.+\\)"
817 page-name)
818 (setq page-name
819 (substring page-name (match-beginning 1)
820 (match-end 2)))))
821 ;; add Manual-unique-pages if it isn't there
822 ;; and return file
823 (if (and unique-pages
824 page-name
825 (string-match (concat "\\b" page-name "\\b")
826 unique-pages))
827 nil
828 (setq unique-pages (concat unique-pages
829 page-name
830 " "))
831 (list page)))))
832 manlist))))
833
834
835
836 (defun Manual-insert-man-file (name)
837 ;; Insert manual file (unpacked as necessary) into buffer
838 (cond ((equal (substring name -3) ".gz")
839 (call-process "gunzip" nil t nil "--stdout" name))
840 ((or (equal (substring name -2) ".Z")
841 ;; HPUX uses directory names that end in .Z and compressed
842 ;; files that don't. How gratuitously random.
843 (let ((case-fold-search nil))
844 (string-match "\\.Z/" name)))
845 (call-process "zcat" name t nil)) ;; XEmacs change for HPUX
846 ((equal (substring name -2) ".z")
847 (call-process "pcat" nil t nil name))
848 (t
849 (insert-file-contents name))))
850
851 (defmacro Manual-delete-char (n)
852 ;; in v19, delete-char is compiled as a function call, but delete-region
853 ;; is byte-coded, so it's much faster.
854 ;; (We were spending 40% of our time in delete-char alone.)
855 (list 'delete-region '(point) (list '+ '(point) n)))
856
857 ;; Hint: BS stands for more things than "back space"
858 (defun Manual-nuke-nroff-bs (&optional apropos-mode)
859 (interactive "*")
860 (if Manual-use-rosetta-man
861 (call-process-region (point-min) (point-max) "rman" t t nil)
862 ;;
863 ;; turn underlining into italics
864 ;;
865 (goto-char (point-min))
866 (while (search-forward "_\b" nil t)
867 ;; searching for underscore-backspace and then comparing the following
868 ;; chars until the sequence ends turns out to be much faster than searching
869 ;; for a regexp which matches the whole sequence.
870 (let ((s (match-beginning 0)))
871 (goto-char s)
872 (while (and (= (following-char) ?_)
873 (= (char-after (1+ (point))) ?\b))
874 (Manual-delete-char 2)
875 (forward-char 1))
876 (set-extent-face (make-extent s (point)) 'man-italic)))
877 ;;
878 ;; turn overstriking into bold
879 ;;
880 (goto-char (point-min))
881 (while (re-search-forward "\\([^\n]\\)\\(\b\\1\\)" nil t)
882 ;; Surprisingly, searching for the above regexp is faster than searching
883 ;; for a backspace and then comparing the preceding and following chars,
884 ;; I presume because there are many false matches, meaning more funcalls
885 ;; to re-search-forward.
886 (let ((s (match-beginning 0)))
887 (goto-char s)
888 ;; Some systems (SGI) overstrike multiple times, eg, "M\bM\bM\bM".
889 (while (looking-at "\\([^\n]\\)\\(\b\\1\\)+")
890 (delete-region (+ (point) 1) (match-end 0))
891 (forward-char 1))
892 (set-extent-face (make-extent s (point)) 'man-bold)))
893 ;;
894 ;; hack bullets: o^H+ --> +
895 (goto-char (point-min))
896 (while (search-forward "\b" nil t)
897 (Manual-delete-char -2))
898
899 (if (> (buffer-size) 100) ; minor kludge
900 (Manual-nuke-nroff-bs-footers))
901 ) ;; not Manual-use-rosetta-man
902 ;;
903 ;; turn subsection header lines into bold
904 ;;
905 (goto-char (point-min))
906 (if apropos-mode
907 (while (re-search-forward "[a-zA-Z0-9] ([0-9]" nil t)
908 (forward-char -2)
909 (delete-backward-char 1))
910
911 ;; (while (re-search-forward "^[^ \t\n]" nil t)
912 ;; (set-extent-face (make-extent (match-beginning 0)
913 ;; (progn (end-of-line) (point)))
914 ;; 'man-heading))
915
916 ;; boldface the first line
917 (if (looking-at "[^ \t\n].*$")
918 (set-extent-face (make-extent (match-beginning 0) (match-end 0))
919 'man-bold))
920
921 ;; boldface subsequent title lines
922 ;; Regexp to match section headers changed to match a non-indented
923 ;; line preceded by a blank line and followed by an indented line.
924 ;; This seems to work ok for manual pages but gives better results
925 ;; with other nroff'd files
926 (while (re-search-forward "\n\n\\([^ \t\n].*\\)\n[ \t]+[^ \t\n]" nil t)
927 (goto-char (match-end 1))
928 (set-extent-face (make-extent (match-beginning 1) (match-end 1))
929 'man-heading)
930 (forward-line 1))
931 )
932
933 (if Manual-use-rosetta-man
934 nil
935 ;; Zap ESC7, ESC8, and ESC9
936 ;; This is for Sun man pages like "man 1 csh"
937 (goto-char (point-min))
938 (while (re-search-forward "\e[789]" nil t)
939 (replace-match "")))
940
941 ;; Nuke blanks lines at start.
942 ;; (goto-char (point-min))
943 ;; (skip-chars-forward "\n")
944 ;; (delete-region (point-min) (point))
945
946 (Manual-mouseify-xrefs)
947 )
948
949 (fset 'nuke-nroff-bs 'Manual-nuke-nroff-bs) ; use old name
950
951
952 (defun Manual-nuke-nroff-bs-footers ()
953 ;; Nuke headers and footers.
954 ;;
955 ;; nroff assumes pages are 66 lines high. We assume that, and that the
956 ;; first and last line on each page is expendible. There is no way to
957 ;; tell the difference between a page break in the middle of a paragraph
958 ;; and a page break between paragraphs (the amount of extra whitespace
959 ;; that nroff inserts is the same in both cases) so this might strip out
960 ;; a blank line were one should remain. I think that's better than
961 ;; leaving in a blank line where there shouldn't be one. (Need I say
962 ;; it: FMH.)
963 ;;
964 ;; Note that if nroff spits out error messages, pages will be more than
965 ;; 66 lines high, and we'll lose badly. That's ok because standard
966 ;; nroff doesn't do any diagnostics, and the "gnroff" wrapper for groff
967 ;; turns off error messages for compatibility. (At least, it's supposed
968 ;; to.)
969 ;;
970 (goto-char (point-min))
971 ;; first lose the status output
972 (let ((case-fold-search t))
973 (if (and (not (looking-at "[^\n]*warning"))
974 (looking-at "Reformatting.*\n"))
975 (delete-region (match-beginning 0) (match-end 0))))
976
977 ;; kludge around a groff bug where it won't keep quiet about some
978 ;; warnings even with -Wall or -Ww.
979 (cond ((looking-at "grotty:")
980 (while (looking-at "grotty:")
981 (delete-region (point) (progn (forward-line 1) (point))))
982 (if (looking-at " *done\n")
983 (delete-region (point) (match-end 0)))))
984
985 (let ((pages '())
986 p)
987 ;; collect the page boundary markers before we start deleting, to make
988 ;; it easier to strip things out without changing the page sizes.
989 (while (not (eobp))
990 (forward-line 66)
991 (setq pages (cons (point-marker) pages)))
992 (setq pages (nreverse pages))
993 (while pages
994 (goto-char (car pages))
995 (set-marker (car pages) nil)
996 ;;
997 ;; The lines are: 3 blank; footer; 6 blank; header; 3 blank.
998 ;; We're in between the previous footer and the following header,
999 ;;
1000 ;; First lose 3 blank lines, the header, and then 3 more.
1001 ;;
1002 (setq p (point))
1003 (skip-chars-forward "\n")
1004 (delete-region p (point))
1005 (and (looking-at "[^\n]+\n\n?\n?\n?")
1006 (delete-region (match-beginning 0) (match-end 0)))
1007 ;;
1008 ;; Next lose the footer, and the 3 blank lines after, and before it.
1009 ;; But don't lose the last footer of the manual entry; that contains
1010 ;; the "last change" date, so it's not completely uninteresting.
1011 ;; (Actually lose all blank lines before it; sh(1) needs this.)
1012 ;;
1013 (skip-chars-backward "\n")
1014 (beginning-of-line)
1015 (if (null (cdr pages))
1016 nil
1017 (and (looking-at "[^\n]+\n\n?\n?\n?")
1018 (delete-region (match-beginning 0) (match-end 0))))
1019 (setq p (point))
1020 (skip-chars-backward "\n")
1021 (if (> (- p (point)) 4)
1022 (delete-region (+ 2 (point)) p)
1023 (delete-region (1+ (point)) p))
1024 ; (and (looking-at "\n\n?\n?")
1025 ; (delete-region (match-beginning 0) (match-end 0)))
1026
1027 (setq pages (cdr pages)))
1028 ;;
1029 ;; Now nuke the extra blank lines at the beginning and end.
1030 (goto-char (point-min))
1031 (if (looking-at "\n+")
1032 (delete-region (match-beginning 0) (match-end 0)))
1033 (forward-line 1)
1034 (if (looking-at "\n\n+")
1035 (delete-region (1+ (match-beginning 0)) (match-end 0)))
1036 (goto-char (point-max))
1037 (skip-chars-backward "\n")
1038 (delete-region (point) (point-max))
1039 (beginning-of-line)
1040 (forward-char -1)
1041 (setq p (point))
1042 (skip-chars-backward "\n")
1043 (if (= ?\n (following-char)) (forward-char 1))
1044 (if (> (point) (1+ p))
1045 (delete-region (point) p))
1046 ))
1047
1048 ;(defun Manual-nuke-nroff-bs-footers ()
1049 ; ;; Nuke headers: "MORE(1) UNIX Programmer's Manual MORE(1)"
1050 ; (goto-char (point-min))
1051 ; (while (re-search-forward "^ *\\([A-Za-z][-_A-Za-z0-9]*([0-9A-Za-z]+)\\).*\\1$" nil t)
1052 ; (replace-match ""))
1053 ;
1054 ; ;;
1055 ; ;; it would appear that we have a choice between sometimes introducing
1056 ; ;; an extra blank line when a paragraph was broken by a footer, and
1057 ; ;; sometimes not putting in a blank line between two paragraphs when
1058 ; ;; a footer appeared right between them. FMH; I choose the latter.
1059 ; ;;
1060 ;
1061 ; ;; Nuke footers: "Printed 12/3/85 27 April 1981 1"
1062 ; ;; Sun appear to be on drugz:
1063 ; ;; "Sun Release 3.0B Last change: 1 February 1985 1"
1064 ; ;; HP are even worse!
1065 ; ;; " Hewlett-Packard -1- (printed 12/31/99)" FMHWA12ID!!
1066 ; ;; System V (well WICATs anyway):
1067 ; ;; "Page 1 (printed 7/24/85)"
1068 ; ;; Who is administering PCP to these corporate bozos?
1069 ; (goto-char (point-min))
1070 ; (while (re-search-forward
1071 ; (cond
1072 ; ((eq system-type 'hpux)
1073 ; "\n\n?[ \t]*Hewlett-Packard\\(\\| Company\\)[ \t]*- [0-9]* -.*\n")
1074 ; ((eq system-type 'dgux-unix)
1075 ; "\n\n?[ \t]*Licensed material--.*Page [0-9]*\n")
1076 ; ((eq system-type 'usg-unix-v)
1077 ; "\n\n? *Page [0-9]*.*(printed [0-9/]*)\n")
1078 ; (t
1079 ; "\n\n?\\(Printed\\|Sun Release\\) [0-9].*[0-9]\n"))
1080 ; nil t)
1081 ; (replace-match ""))
1082 ;
1083 ; ;; Also, hack X footers:
1084 ; ;; "X Version 11 Last change: Release 5 1"
1085 ; (goto-char (point-min))
1086 ; (while (re-search-forward "\n\n?X Version [^\n]+\n" nil t)
1087 ; (replace-match ""))
1088 ;
1089 ; ;; Crunch blank lines
1090 ; (goto-char (point-min))
1091 ; (while (re-search-forward "\n\n\n\n*" nil t)
1092 ; (replace-match "\n\n"))
1093 ; )
1094
1095 (defun Manual-mouseify-xrefs ()
1096 (goto-char (point-min))
1097 (forward-line 1)
1098 (let ((case-fold-search nil)
1099 s e name extent)
1100 ;; possibly it would be faster to rewrite this expression to search for
1101 ;; a less common sequence first (like "([0-9]") and then back up to see
1102 ;; if it's really a match. This function is 15% of the total time, 13%
1103 ;; of which is this call to re-search-forward.
1104 (while (re-search-forward "[a-zA-Z_][-a-zA-Z0-9_.]*([0-9][a-zA-Z0-9]*)"
1105 nil t)
1106 (setq s (match-beginning 0)
1107 e (match-end 0)
1108 name (buffer-substring s e))
1109 (goto-char s)
1110 (skip-chars-backward " \t")
1111 (if (and (bolp)
1112 (progn (backward-char 1) (= (preceding-char) ?-)))
1113 (progn
1114 (setq s (point))
1115 (skip-chars-backward "-a-zA-Z0-9_.")
1116 (setq name (concat (buffer-substring (point) (1- s)) name))
1117 (setq s (point))))
1118 ;; if there are upper case letters in the section, downcase them.
1119 (if (string-match "(.*[A-Z]+.*)$" name)
1120 (setq name (concat (substring name 0 (match-beginning 0))
1121 (downcase (substring name (match-beginning 0))))))
1122 ;; (setq already-fontified (extent-at s))
1123 (setq extent (make-extent s e))
1124 (set-extent-property extent 'man (list 'Manual-follow-xref name))
1125 (set-extent-property extent 'highlight t)
1126 ;; (if (not already-fontified)...
1127 (set-extent-face extent 'man-xref)
1128 (goto-char e))))
1129
1130 (defun Manual-follow-xref (&optional name-or-event)
1131 "Invoke `manual-entry' on the cross-reference under the mouse.
1132 When invoked noninteractively, the arg may be an xref string to parse instead."
1133 (interactive "e")
1134 (if (eventp name-or-event)
1135 (let* ((p (event-point name-or-event))
1136 (extent (and p (extent-at p
1137 (event-buffer name-or-event)
1138 'highlight)))
1139 (data (and extent (extent-property extent 'man))))
1140 (if (eq (car-safe data) 'Manual-follow-xref)
1141 (eval data)
1142 (error "no manual cross-reference there.")))
1143 (let ((Manual-match-topic-exactly t)
1144 (Manual-query-multiple-pages nil))
1145 (or (manual-entry name-or-event)
1146 ;; If that didn't work, maybe it's in a different section than the
1147 ;; man page writer expected. For example, man pages tend assume
1148 ;; that all user programs are in section 1, but X tends to generate
1149 ;; makefiles that put things in section "n" instead...
1150 (and (string-match "[ \t]*([^)]+)\\'" name-or-event)
1151 (progn
1152 (message "No entries found for %s; checking other sections..."
1153 name-or-event)
1154 (manual-entry
1155 (substring name-or-event 0 (match-beginning 0))
1156 nil t)))))))
1157
1158 (defun Manual-popup-menu (&optional event)
1159 "Pops up a menu of cross-references in this manual page.
1160 If there is a cross-reference under the mouse button which invoked this
1161 command, it will be the first item on the menu. Otherwise, they are
1162 on the menu in the order in which they appear in the buffer."
1163 (interactive "e")
1164 (let ((buffer (current-buffer))
1165 (sep "---")
1166 (prefix "Show Manual Page for ")
1167 xref items)
1168 (cond (event
1169 (setq buffer (event-buffer event))
1170 (let* ((p (event-point event))
1171 (extent (and p (extent-at p buffer 'highlight)))
1172 (data (and extent (extent-property extent 'man))))
1173 (if (eq (car-safe data) 'Manual-follow-xref)
1174 (setq xref (nth 1 data))))))
1175 (if xref (setq items (list sep xref)))
1176 (map-extents #'(lambda (extent ignore)
1177 (let ((data (extent-property extent 'man)))
1178 (if (and (eq (car-safe data) 'Manual-follow-xref)
1179 (not (member (nth 1 data) items)))
1180 (setq items (cons (nth 1 data) items)))
1181 nil))
1182 buffer)
1183 (if (eq sep (car items)) (setq items (cdr items)))
1184 (let ((popup-menu-titles nil))
1185 (popup-menu
1186 (cons "Manual Entry"
1187 (mapcar #'(lambda (item)
1188 (if (eq item sep)
1189 item
1190 (vector (concat prefix item)
1191 (list 'Manual-follow-xref item) t)))
1192 (nreverse items)))))))
1193
1194 (defun pager-cleanup-hook ()
1195 "cleanup man page if called via $PAGER"
1196 (let ((buf-name (or buffer-file-name (buffer-name))))
1197 (if (and (or (string-match "^/tmp/man[0-9]+" buf-name)
1198 (string-match ".*/man/\\(man\\|cat\\)[1-9a-z]/" buf-name))
1199 (not (string-match Manual-bogus-file-pattern buf-name)))
1200 (let (buffer manpage)
1201 (require 'man)
1202 (goto-char (point-min))
1203 (setq buffer-read-only nil)
1204 (Manual-nuke-nroff-bs)
1205 (goto-char (point-min))
1206 (if (re-search-forward "[^ \t]")
1207 (goto-char (- (point) 1)))
1208 (if (looking-at "\\([a-zA-Z0-9]+\\)[ \t]*(")
1209 (setq manpage (buffer-substring (match-beginning 1) (match-end 1)))
1210 (setq manpage "???"))
1211 (setq buffer
1212 (rename-buffer
1213 (generate-new-buffer-name (concat "*man " manpage "*"))))
1214 (setq buffer-file-name nil)
1215 (goto-char (point-min))
1216 (insert (format "%s\n" buf-name))
1217 (goto-char (point-min))
1218 (buffer-disable-undo buffer)
1219 (set-buffer-modified-p nil)
1220 (Manual-mode)
1221 ))))
1222
1223 (add-hook 'server-visit-hook 'pager-cleanup-hook)
1224 (provide 'man)