Mercurial > hg > xemacs-beta
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) |