comparison lisp/packages/man.el @ 8:4b173ad71786 r19-15b5

Import from CVS: tag r19-15b5
author cvs
date Mon, 13 Aug 2007 08:47:35 +0200
parents b82b59fe008d
children 49a24b4fd526
comparison
equal deleted inserted replaced
7:c153ca296910 8:4b173ad71786
1 ;;; man.el --- browse UNIX manual pages 1 ;;; man.el --- browse UNIX manual pages
2 2 ;; Keywords: help
3 ;; Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. 3
4 4 ;; Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc.
5 ;; Author: Barry A. Warsaw <bwarsaw@cen.com> 5 ;;
6 ;; Keywords: help
7 ;; Adapted-By: ESR, pot
8
9 ;; This file is part of XEmacs. 6 ;; This file is part of XEmacs.
10 7
11 ;; XEmacs is free software; you can redistribute it and/or modify it 8 ;; XEmacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by 9 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option) 10 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details. 16 ;; General Public License for more details.
20 17
21 ;; You should have received a copy of the GNU General Public License 18 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free 19 ;; along with XEmacs; see the file COPYING. If not, write to the Free
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 ;; 02111-1307, USA. 21
25 22 ;; Mostly rewritten by Alan K. Stebbens <aks@hub.ucsb.edu> 11-apr-90.
26 ;;; Synched up with: FSF 19.34. 23 ;;
27 24 ;; o Match multiple man pages using TOPIC as a simple pattern
28 ;;; Commentary: 25 ;; o Search unformatted pages, even when formatted matches are found
29 26 ;; o Query the user as to which pages are desired
30 ;; This code provides a function, `man', with which you can browse 27 ;; o Use of the prefix arg to toggle/bypass the above features
31 ;; UNIX manual pages. Formatting is done in background so that you 28 ;; o Buffers named by the first topic in the buffer
32 ;; can continue to use your Emacs while processing is going on. 29 ;; o Automatic uncompress for compressed man pages (.Z, .z, and .gz)
33 ;; 30 ;; o View the resulting buffer using M-x view mode
34 ;; The mode also supports hypertext-like following of manual page SEE 31 ;;
35 ;; ALSO references, and other features. See below or do `?' in a 32 ;; Modified 16-mar-91 by Jamie Zawinski <jwz@lucid.com> to default the
36 ;; manual page buffer for details. 33 ;; manual topic to the symbol at point, just like find-tag does.
37 34 ;;
38 ;; ========== Credits and History ========== 35 ;; Modified 22-mar-93 by jwz to use multiple fonts and follow xrefs with mouse.
39 ;; In mid 1991, several people posted some interesting improvements to 36 ;;
40 ;; man.el from the standard emacs 18.57 distribution. I liked many of 37 ;; Modified 16-apr-93 by Dave Gillespie <daveg@synaptics.com> to make
41 ;; these, but wanted everything in one single package, so I decided 38 ;; apropos work nicely; work correctly when bold or italic is unavailable;
42 ;; to incorporate them into a single manual browsing mode. While 39 ;; reuse old buffer if topic is re-selected (in Manual-topic-buffer mode).
43 ;; much of the code here has been rewritten, and some features added, 40 ;;
44 ;; these folks deserve lots of credit for providing the initial 41 ;; Modified 4-apr-94 by jwz: merged in Tibor Polgar's code for manpath.conf.
45 ;; excellent packages on which this one is based. 42 ;;
46 43 ;; Modified 19-apr-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
47 ;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice 44 ;; $PAGER variable to be emacsclient and properly process man pages (assuming
48 ;; improvement which retrieved and cleaned the manpages in a 45 ;; the man pages were built by man in /tmp. also fixed bug with man list being
49 ;; background process, and which correctly deciphered such options as 46 ;; backwards.
50 ;; man -k. 47 ;;
51 48 ;; Modified 23-aug-94 by Tibor Polgar <tlp00@spg.amdahl.com> to add support for
52 ;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which 49 ;; displaying only one instance of a man page (Manual-unique-man-sections-only)
53 ;; provided a very nice manual browsing mode. 50 ;; Fixed some more man page ordering bugs, bug with Manual-query-multiple-pages.
54 51 ;;
55 ;; This package was available as `superman.el' from the LCD package 52 ;; Modified 29-nov-94 by Ben Wing <wing@spg.amdahl.com>: small fixes
56 ;; for some time before it was accepted into Emacs 19. The entry 53 ;; that should hopefully make things work under HPUX and IRIX.;
57 ;; point and some other names have been changed to make it a drop-in 54 ;;
58 ;; replacement for the old man.el package. 55 ;; Modified 15-jul-95 by Dale Atems <atems@physics.wayne.edu>:
59 56 ;; some extensive rewriting to make things work right (more or less)
60 ;; Francesco Potorti` <pot@cnuce.cnr.it> cleaned it up thoroughly, 57 ;; under IRIX.
61 ;; making it faster, more robust and more tolerant of different 58 ;;
62 ;; systems' man idiosyncrasies. 59 ;; This file defines "manual-entry", and the remaining definitions all
63 60 ;; begin with "Manual-". This makes the autocompletion on "M-x man" work.
64 ;; ========== Features ========== 61 ;;
65 ;; + Runs "man" in the background and pipes the results through a 62 ;; Variables of interest:
66 ;; series of sed and awk scripts so that all retrieving and cleaning 63 ;;
67 ;; is done in the background. The cleaning commands are configurable. 64 ;; Manual-program
68 ;; + Syntax is the same as Un*x man 65 ;; Manual-topic-buffer
69 ;; + Functionality is the same as Un*x man, including "man -k" and 66 ;; Manual-buffer-view-mode
70 ;; "man <section>", etc. 67 ;; Manual-directory-list
71 ;; + Provides a manual browsing mode with keybindings for traversing 68 ;; Manual-formatted-directory-list
72 ;; the sections of a manpage, following references in the SEE ALSO 69 ;; Manual-match-topic-exactly
73 ;; section, and more. 70 ;; Manual-query-multiple-pages
74 ;; + Multiple manpages created with the same man command are put into 71 ;; Manual-page-history
75 ;; a narrowed buffer circular list. 72 ;; Manual-subdirectory-list
76 73 ;; Manual-man-page-section-ids
77 ;; ============= TODO =========== 74 ;; Manual-formatted-page-prefix
78 ;; - Add a command for printing. 75 ;; Manual-unformatted-page-prefix
79 ;; - The awk script deletes multiple blank lines. This behaviour does 76 ;; Manual-use-full-section-ids
80 ;; not allow to understand if there was indeed a blank line at the 77
81 ;; end or beginning of a page (after the header, or before the 78 (defvar Manual-program "man" "\
82 ;; footer). A different algorithm should be used. It is easy to 79 *Name of the program to invoke in order to format the source man pages.")
83 ;; compute how many blank lines there are before and after the page 80
84 ;; headers, and after the page footer. But it is possible to compute 81 (defvar Manual-section-switch (if (eq system-type 'usg-unix-v) "-s" nil)
85 ;; the number of blank lines before the page footer by euristhics 82 "SysV needs this to work right.")
86 ;; only. Is it worth doing? 83
87 ;; - Allow a user option to mean that all the manpages should go in 84 (defvar Manual-topic-buffer t "\
88 ;; the same buffer, where they can be browsed with M-n and M-p. 85 *Non-nil means \\[Manual-entry] should output the manual entry for TOPIC into
89 ;; - Allow completion on the manpage name when calling man. This 86 a buffer named *man TOPIC*, otherwise, it should name the buffer
90 ;; requires a reliable list of places where manpages can be found. The 87 *Manual Entry*.")
91 ;; drawback would be that if the list is not complete, the user might 88
92 ;; be led to believe that the manpages in the missing directories do 89 (defvar Manual-buffer-view-mode t "\
93 ;; not exist. 90 *Whether manual buffers should be placed in view-mode.
94 91 nil means leave the buffer in fundamental-mode in another window.
95 92 t means use `view-buffer' to display the man page in the current window.
96 ;;; Code: 93 Any other value means use `view-buffer-other-window'.")
97 94
98 (require 'assoc) 95 (defvar Manual-match-topic-exactly t "\
99 96 *Non-nil means that \\[manual-entry] will match the given TOPIC exactly, rather
100 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 97 apply it as a pattern. When this is nil, and \"Manual-query-multiple-pages\"
101 ;; empty defvars (keep the compiler quiet) 98 is non-nil, then \\[manual-entry] will query you for all matching TOPICs.
102 99 This variable only has affect on the preformatted man pages (the \"cat\" files),
103 (defvar Man-notify) 100 since the \"man\" command always does exact topic matches.")
104 (defvar Man-current-page) 101
105 (defvar Man-page-list) 102 (defvar Manual-query-multiple-pages nil "\
106 (defvar Man-filter-list nil 103 *Non-nil means that \\[manual-entry] will query the user about multiple man
107 "*Manpage cleaning filter command phrases. 104 pages which match the given topic. The query is done using the function
108 This variable contains a list of the following form: 105 \"y-or-n-p\". If this variable is nil, all man pages with topics matching the
109 106 topic given to \\[manual-entry] will be inserted into the temporary buffer.
110 '((command-string phrase-string*)*) 107 See the variable \"Manual-match-topic-exactly\" to control the matching.")
111 108
112 Each phrase-string is concatenated onto the command-string to form a 109 (defvar Manual-unique-man-sections-only nil
113 command filter. The (standard) output (and standard error) of the Un*x 110 "*Only present one man page per section. This variable is useful if the same or
114 man command is piped through each command filter in the order the 111 up/down level man pages for the same entry are present in mulitple man paths.
115 commands appear in the association list. The final output is placed in 112 When set to t, only the first entry found in a section is displayed, the others
116 the manpage buffer.") 113 are ignored without any messages or warnings. Note that duplicates can occur if
117 114 the system has both formatted and unformatted version of the same page.")
118 (defvar Man-original-frame) 115
119 (defvar Man-arguments) 116 (defvar Manual-mode-hook nil
120 (defvar Man-sections-alist) 117 "Function or functions run on entry to Manual-mode.")
121 (defvar Man-refpages-alist) 118
122 (defvar Man-uses-untabify-flag t 119 (defvar Manual-directory-list nil "\
123 "When non-nil use `untabify' instead of Man-untabify-command.") 120 *A list of directories used with the \"man\" command, where each directory
124 (defvar Man-page-mode-string) 121 contains a set of \"man?\" and \"cat?\" subdirectories. If this variable is nil,
125 (defvar Man-sed-script nil 122 it is initialized by \\[Manual-directory-list-init].")
126 "Script for sed to nuke backspaces and ANSI codes from manpages.") 123
127 124 (defvar Manual-formatted-directory-list nil "\
128 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 125 A list of directories containing formatted man pages. Initialized by
129 ;; user variables 126 \\[Manual-directory-list-init].")
130 127
131 (defvar Man-fontify-manpage-flag t 128 (defvar Manual-unformatted-directory-list nil "\
132 "*Make up the manpage with fonts.") 129 A list of directories containing the unformatted (source) man pages.
133 130 Initialized by \\[Manual-directory-list-init].")
134 (defvar Man-overstrike-face 'bold 131
135 "*Face to use when fontifying overstrike.") 132 (defvar Manual-page-history nil "\
136 133 A list of names of previously visited man page buffers.")
137 (defvar Man-underline-face 'underline 134
138 "*Face to use when fontifying underlining.") 135 (defvar Manual-manpath-config-file "/usr/lib/manpath.config"
139 136 "*Location of the manpath.config file, if any.")
140 ;; Use the value of the obsolete user option Man-notify, if set. 137
141 (defvar Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly) 138 (defvar Manual-apropos-switch "-k"
142 "*Selects the behavior when manpage is ready. 139 "*Man apropos switch")
143 This variable may have one of the following values, where (sf) means 140
144 that the frames are switched, so the manpage is displayed in the frame 141 ;; New variables.
145 where the man command was called from: 142
146 143 (defvar Manual-subdirectory-list nil "\
147 newframe -- put the manpage in its own frame (see `Man-frame-parameters') 144 A list of all the subdirectories in which man pages may be found.
148 pushy -- make the manpage the current buffer in the current window 145 Iniialized by Manual-directory-list-init.")
149 bully -- make the manpage the current buffer and only window (sf) 146
150 aggressive -- make the manpage the current buffer in the other window (sf) 147 ;; This is for SGI systems; don't know what it should be otherwise.
151 friendly -- display manpage in the other window but don't make current (sf) 148 (defvar Manual-man-page-section-ids "1nl6823457poD" "\
152 polite -- don't display manpage, but prints message and beep when ready 149 String containing all suffix characters for \"cat\" and \"man\"
153 quiet -- like `polite', but don't beep 150 that identify valid sections of the Un*x manual.")
154 meek -- make no indication that the manpage is ready 151
155 152 (defvar Manual-formatted-page-prefix "cat" "\
156 Any other value of `Man-notify-method' is equivalent to `meek'.") 153 Prefix for directories where formatted man pages are to be found.
157 154 Defaults to \"cat\".")
158 (defvar Man-frame-parameters nil 155
159 "*Frame parameter list for creating a new frame for a manual page.") 156 (defvar Manual-unformatted-page-prefix "man" "\
160 157 Prefix for directories where unformatted man pages are to be found.
161 (defvar Man-downcase-section-letters-flag t 158 Defaults to \"man\".")
162 "*Letters in sections are converted to lower case. 159
163 Some Un*x man commands can't handle uppercase letters in sections, for 160 (defvar Manual-leaf-signature "" "\
164 example \"man 2V chmod\", but they are often displayed in the manpage 161 Regexp for identifying \"leaf\" subdirectories in the search path.
165 with the upper case letter. When this variable is t, the section 162 If empty, initialized by Manual-directory-list-init.")
166 letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before 163
167 being sent to the man background process.") 164 (defvar Manual-use-full-section-ids t "\
168 165 If non-nil, pass full section ids to Manual-program, otherwise pass
169 (defvar Man-circular-pages-flag t 166 only the first character. Defaults to 't'.")
170 "*If t, the manpage list is treated as circular for traversal.") 167
171 168 (defvar Manual-use-subdirectory-list (eq system-type 'irix) "\
172 (defvar Man-section-translations-alist 169 This makes manual-entry work correctly on SGI machines but it
173 (list 170 imposes a large startup cost which is why it is not simply on by
174 '("3C++" . "3") 171 default on all systems.")
175 ;; Some systems have a real 3x man section, so let's comment this. 172
176 ;; '("3X" . "3") ; Xlib man pages 173 (make-face 'man-italic)
177 '("3X11" . "3") 174 (or (face-differs-from-default-p 'man-italic)
178 '("1-UCB" . "")) 175 (copy-face 'italic 'man-italic))
179 "*Association list of bogus sections to real section numbers. 176 ;; XEmacs (from Darrell Kindred): underlining is annoying due to
180 Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in 177 ;; large blank spaces in this face.
181 their references which Un*x `man' does not recognize. This 178 ;; (or (face-differs-from-default-p 'man-italic)
182 association list is used to translate those sections, when found, to 179 ;; (set-face-underline-p 'man-italic t))
183 the associated section number.") 180
184 181 (make-face 'man-bold)
185 (defvar manual-program "man" 182 (or (face-differs-from-default-p 'man-bold)
186 "The name of the program that produces man pages.") 183 (copy-face 'bold 'man-bold))
187 184 (or (face-differs-from-default-p 'man-bold)
188 (defvar Man-untabify-command "pr" 185 (copy-face 'man-italic 'man-bold))
189 "Command used for untabifying.") 186
190 187 (make-face 'man-heading)
191 (defvar Man-untabify-command-args (list "-t" "-e") 188 (or (face-differs-from-default-p 'man-heading)
192 "List of arguments to be passed to Man-untabify-command (which see).") 189 (copy-face 'man-bold 'man-heading))
193 190
194 (defvar Man-sed-command "sed" 191 (make-face 'man-xref)
195 "Command used for processing sed scripts.") 192 (or (face-differs-from-default-p 'man-xref)
196 193 (set-face-underline-p 'man-xref t))
197 (defvar Man-awk-command "awk" 194
198 "Command used for processing awk scripts.") 195 ;; Manual-directory-list-init
199 196 ;; Initialize the directory lists.
200 (defvar Man-mode-line-format 197
201 '("" mode-line-modified 198 (defun Manual-directory-list-init (&optional arg)
202 mode-line-buffer-identification " " 199 "Initialize the Manual-directory-list variable from $MANPATH
203 global-mode-string 200 if it is not already set, or if a prefix argument is provided."
204 " " Man-page-mode-string 201 (interactive "P")
205 " %[(" mode-name mode-line-process minor-mode-alist ")%]----" 202 (if arg (setq Manual-directory-list nil))
206 (-3 . "%p") "-%-") 203 (if (null Manual-directory-list)
207 "Mode line format for manual mode buffer.") 204 (let ((manpath (getenv "MANPATH"))
208 205 (global (Manual-manpath-config-contents))
209 (defvar Man-mode-map nil 206 (dirlist nil)
210 "Keymap for Man mode.") 207 dir)
211 208 (cond ((and manpath global)
212 (defvar Man-mode-hook nil 209 (setq manpath (concat manpath ":" global)))
213 "Hook run when Man mode is enabled.") 210 (global
214 211 (setq manpath global))
215 (defvar Man-cooked-hook nil 212 ((not manpath)
216 "Hook run after removing backspaces but before Man-mode processing.") 213 ;; XEmacs - (bpw/stig) Unix-specifix hack for lusers w/ no manpath
217 214 (setq manpath "/usr/local/man:/usr/share/man:/usr/contrib/man:/usr/X11/man:/usr/man:/usr/catman")))
218 (defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*" 215 ;; Make sure that any changes we've made internally are seen by man.
219 "Regular expression describing the name of a manpage (without section).") 216 (setenv "MANPATH" manpath)
220 217 (while (string-match "\\`:*\\([^:]+\\)" manpath)
221 (defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]" 218 (setq dir (substring manpath (match-beginning 1) (match-end 1)))
222 "Regular expression describing a manpage section within parentheses.") 219 (and (not (member dir dirlist))
223 220 (setq dirlist (cons dir dirlist)))
224 (defvar Man-page-header-regexp 221 (setq manpath (substring manpath (match-end 0))))
225 (concat "^[ \t]*\\(" Man-name-regexp 222 (setq dirlist (nreverse dirlist))
226 "(\\(" Man-section-regexp "\\))\\).*\\1") 223 (setq Manual-directory-list dirlist)
227 "Regular expression describing the heading of a page.") 224 (setq Manual-subdirectory-list nil)
228 225 (setq Manual-formatted-directory-list nil)
229 (defvar Man-heading-regexp "^\\([A-Z][A-Z ]+\\)$" 226 (setq Manual-unformatted-directory-list nil)))
230 "Regular expression describing a manpage heading entry.") 227 (if (string-equal Manual-leaf-signature "")
231 228 (setq Manual-leaf-signature
232 (defvar Man-see-also-regexp "SEE ALSO" 229 (concat "/\\("
233 "Regular expression for SEE ALSO heading (or your equivalent). 230 Manual-formatted-page-prefix
234 This regexp should not start with a `^' character.") 231 "\\|" Manual-unformatted-page-prefix
235 232 "\\)"
236 (defvar Man-first-heading-regexp "^[ \t]*NAME$\\|^[ \t]*No manual entry fo.*$" 233 "[" Manual-man-page-section-ids
237 "Regular expression describing first heading on a manpage. 234 "].?/.")))
238 This regular expression should start with a `^' character.") 235 (if Manual-use-subdirectory-list
239 236 (progn
240 (defvar Man-reference-regexp 237 (if (null Manual-subdirectory-list)
241 (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))") 238 (setq Manual-subdirectory-list
242 "Regular expression describing a reference in the SEE ALSO section.") 239 (Manual-all-subdirectories Manual-directory-list
243 240 Manual-leaf-signature nil)))
244 (defvar Man-switches "" 241 (if (null Manual-formatted-directory-list)
245 "Switches passed to the man command, as a single string.") 242 (setq Manual-formatted-directory-list
246 243 (Manual-filter-subdirectories Manual-subdirectory-list
247 (defvar Man-specified-section-option 244 Manual-formatted-page-prefix)))
248 (if (string-match "-solaris[0-9.]*$" system-configuration) 245 (if (null Manual-unformatted-directory-list)
249 "-s" 246 (setq Manual-unformatted-directory-list
250 "") 247 (Manual-filter-subdirectories Manual-subdirectory-list
251 "Option that indicates a specified a manual section name.") 248 Manual-unformatted-page-prefix))))
252 249 (if (null Manual-formatted-directory-list)
253 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 250 (setq Manual-formatted-directory-list
254 ;; end user variables 251 (Manual-select-subdirectories Manual-directory-list
255 252 Manual-formatted-page-prefix)))
256 ;; other variables and keymap initializations 253 (if (null Manual-unformatted-directory-list)
257 (make-variable-buffer-local 'Man-sections-alist) 254 (setq Manual-unformatted-directory-list
258 (make-variable-buffer-local 'Man-refpages-alist) 255 (Manual-select-subdirectories Manual-directory-list
259 (make-variable-buffer-local 'Man-page-list) 256 Manual-unformatted-page-prefix)))))
260 (make-variable-buffer-local 'Man-current-page) 257
261 (make-variable-buffer-local 'Man-page-mode-string) 258
262 (make-variable-buffer-local 'Man-original-frame) 259 (defun Manual-manpath-config-contents ()
263 (make-variable-buffer-local 'Man-arguments) 260 "Parse the `Manual-manpath-config-file' file, if any.
264 261 Returns a string like in $MANPATH."
265 (setq-default Man-sections-alist nil) 262 (if (and Manual-manpath-config-file
266 (setq-default Man-refpages-alist nil) 263 (file-readable-p Manual-manpath-config-file))
267 (setq-default Man-page-list nil) 264 (let ((buf (get-buffer-create " *Manual-config*"))
268 (setq-default Man-current-page 0) 265 path)
269 (setq-default Man-page-mode-string "1 of 1") 266 (set-buffer buf)
270 267 (buffer-disable-undo buf)
271 (defconst Man-sysv-sed-script "\ 268 (erase-buffer)
272 /\b/ { s/_\b//g 269 (insert-file-contents Manual-manpath-config-file)
273 s/\b_//g 270 (while (re-search-forward "^\\(MANDATORY_MANPATH\\|MANPATH_MAP\\)"
274 s/o\b+/o/g 271 nil t)
275 s/+\bo/o/g 272 (and (re-search-forward "\\(/[^ \t\n]+\\)[ \t]*$")
276 :ovstrk 273 (setq path (concat path (buffer-substring (match-beginning 1)
277 s/\\(.\\)\b\\1/\\1/g 274 (match-end 1))
278 t ovstrk 275 ":"))))
279 } 276 (kill-buffer buf)
280 /\e\\[[0-9][0-9]*m/ s///g" 277 path)))
281 "Script for sysV-like sed to nuke backspaces and ANSI codes from manpages.") 278 ;;
282 279 ;; manual-entry -- The "main" user function
283 (defconst Man-berkeley-sed-script "\ 280 ;;
284 /\b/ { s/_\b//g\\ 281
285 s/\b_//g\\
286 s/o\b+/o/g\\
287 s/+\bo/o/g\\
288 :ovstrk\\
289 s/\\(.\\)\b\\1/\\1/g\\
290 t ovstrk\\
291 }\\
292 /\e\\[[0-9][0-9]*m/ s///g"
293 "Script for berkeley-like sed to nuke backspaces and ANSI codes from manpages.")
294
295 (if Man-mode-map
296 nil
297 (setq Man-mode-map (make-keymap))
298 (suppress-keymap Man-mode-map)
299 (define-key Man-mode-map " " 'scroll-up)
300 (define-key Man-mode-map "\177" 'scroll-down)
301 (define-key Man-mode-map "n" 'Man-next-section)
302 (define-key Man-mode-map "p" 'Man-previous-section)
303 (define-key Man-mode-map "\en" 'Man-next-manpage)
304 (define-key Man-mode-map "\ep" 'Man-previous-manpage)
305 (define-key Man-mode-map ">" 'end-of-buffer)
306 (define-key Man-mode-map "<" 'beginning-of-buffer)
307 (define-key Man-mode-map "." 'beginning-of-buffer)
308 (define-key Man-mode-map "r" 'Man-follow-manual-reference)
309 (define-key Man-mode-map "g" 'Man-goto-section)
310 (define-key Man-mode-map "s" 'Man-goto-see-also-section)
311 (define-key Man-mode-map "k" 'Man-kill)
312 (define-key Man-mode-map "q" 'Man-quit)
313 (define-key Man-mode-map "m" 'man)
314 (define-key Man-mode-map "?" 'describe-mode)
315 )
316
317
318 ;; ======================================================================
319 ;; utilities
320
321 (defun Man-init-defvars ()
322 "Used for initialising variables based on the value of window-system.
323 This is necessary if one wants to dump man.el with emacs."
324
325 ;; The following is necessary until fonts are implemented on
326 ;; terminals.
327 (setq Man-fontify-manpage-flag (and Man-fontify-manpage-flag
328 window-system))
329
330 (setq Man-sed-script
331 (cond
332 (Man-fontify-manpage-flag
333 nil)
334 ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
335 Man-sysv-sed-script)
336 ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
337 Man-berkeley-sed-script)
338 (t
339 nil)))
340
341 (setq Man-filter-list
342 (list
343 (cons
344 Man-sed-command
345 (list
346 (if Man-sed-script
347 (concat "-e '" Man-sed-script "'")
348 "")
349 "-e '/^[\001-\032][\001-\032]*$/d'"
350 "-e '/\e[789]/s///g'"
351 "-e '/Reformatting page. Wait/d'"
352 "-e '/Reformatting entry. Wait/d'"
353 "-e '/^[ \t]*Hewlett-Packard[ \t]Company[ \t]*-[ \t][0-9]*[ \t]-/d'"
354 "-e '/^[ \t]*Hewlett-Packard[ \t]*-[ \t][0-9]*[ \t]-.*$/d'"
355 "-e '/^[ \t][ \t]*-[ \t][0-9]*[ \t]-[ \t]*Formatted:.*[0-9]$/d'"
356 "-e '/^[ \t]*Page[ \t][0-9]*.*(printed[ \t][0-9\\/]*)$/d'"
357 "-e '/^Printed[ \t][0-9].*[0-9]$/d'"
358 "-e '/^[ \t]*X[ \t]Version[ \t]1[01].*Release[ \t][0-9]/d'"
359 "-e '/^[A-za-z].*Last[ \t]change:/d'"
360 "-e '/^Sun[ \t]Release[ \t][0-9].*[0-9]$/d'"
361 "-e '/[ \t]*Copyright [0-9]* UNIX System Laboratories, Inc.$/d'"
362 "-e '/^[ \t]*Rev\\..*Page [0-9][0-9]*$/d'"
363 ))
364 (cons
365 Man-awk-command
366 (list
367 "'\n"
368 "BEGIN { blankline=0; anonblank=0; }\n"
369 "/^$/ { if (anonblank==0) next; }\n"
370 "{ anonblank=1; }\n"
371 "/^$/ { blankline++; next; }\n"
372 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }\n"
373 "'"
374 ))
375 (if (not Man-uses-untabify-flag)
376 (cons
377 Man-untabify-command
378 Man-untabify-command-args)
379 )))
380 )
381
382 (defsubst Man-match-substring (&optional n string)
383 "Return the substring matched by the last search.
384 Optional arg N means return the substring matched by the Nth paren
385 grouping. Optional second arg STRING means return a substring from
386 that string instead of from the current buffer."
387 (if (null n) (setq n 0))
388 (if string
389 (substring string (match-beginning n) (match-end n))
390 (buffer-substring (match-beginning n) (match-end n))))
391
392 (defsubst Man-make-page-mode-string ()
393 "Formats part of the mode line for Man mode."
394 (format "%s page %d of %d"
395 (or (nth 2 (nth (1- Man-current-page) Man-page-list))
396 "")
397 Man-current-page
398 (length Man-page-list)))
399
400 (defsubst Man-build-man-command ()
401 "Builds the entire background manpage and cleaning command."
402 (let ((command (concat manual-program " " Man-switches " %s 2>/dev/null"))
403 (flist Man-filter-list))
404 (while (and flist (car flist))
405 (let ((pcom (car (car flist)))
406 (pargs (cdr (car flist))))
407 (setq command
408 (concat command " | " pcom " "
409 (mapconcat '(lambda (phrase)
410 (if (not (stringp phrase))
411 (error "Malformed Man-filter-list"))
412 phrase)
413 pargs " ")))
414 (setq flist (cdr flist))))
415 command))
416
417 (defun Man-translate-references (ref)
418 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
419 Leave it as is if already in that style. Possibly downcase and
420 translate the section (see the Man-downcase-section-letters-flag
421 and the Man-section-translations-alist variables)."
422 (let ((name "")
423 (section "")
424 (slist Man-section-translations-alist))
425 (cond
426 ;; "chmod(2V)" case ?
427 ((string-match (concat "^" Man-reference-regexp "$") ref)
428 (setq name (Man-match-substring 1 ref)
429 section (Man-match-substring 2 ref)))
430 ;; "2v chmod" case ?
431 ((string-match (concat "^\\(" Man-section-regexp
432 "\\) +\\(" Man-name-regexp "\\)$") ref)
433 (setq name (Man-match-substring 2 ref)
434 section (Man-match-substring 1 ref))))
435 (if (string= name "")
436 ref ; Return the reference as is
437 (if Man-downcase-section-letters-flag
438 (setq section (downcase section)))
439 (while slist
440 (let ((s1 (car (car slist)))
441 (s2 (cdr (car slist))))
442 (setq slist (cdr slist))
443 (if Man-downcase-section-letters-flag
444 (setq s1 (downcase s1)))
445 (if (not (string= s1 section)) nil
446 (setq section (if Man-downcase-section-letters-flag
447 (downcase s2)
448 s2)
449 slist nil))))
450 (concat Man-specified-section-option section " " name))))
451
452
453 ;; ======================================================================
454 ;; default man entry: get word under point
455
456 (defsubst Man-default-man-entry ()
457 "Make a guess at a default manual entry.
458 This guess is based on the text surrounding the cursor, and the
459 default section number is selected from `Man-auto-section-alist'."
460 (let (default-title)
461 (save-excursion
462
463 ;; Default man entry title is any word the cursor is on, or if
464 ;; cursor not on a word, then nearest preceding word. Cannot
465 ;; use the current-word function because it skips the dots.
466 (if (not (looking-at "[-a-zA-Z_.]"))
467 (skip-chars-backward "^a-zA-Z"))
468 (skip-chars-backward "-(a-zA-Z_0-9_.")
469 (if (looking-at "(") (forward-char 1))
470 (setq default-title
471 (buffer-substring
472 (point)
473 (progn (skip-chars-forward "-a-zA-Z0-9_.") (point))))
474
475 ;; If looking at something like ioctl(2) or brc(1M), include the
476 ;; section number in the returned value. Remove text properties.
477 (let ((result (concat
478 default-title
479 (if (looking-at
480 (concat "[ \t]*([ \t]*\\("
481 Man-section-regexp "\\)[ \t]*)"))
482 (format "(%s)" (Man-match-substring 1))))))
483 (set-text-properties 0 (length result) nil result)
484 result))))
485
486
487 ;; ======================================================================
488 ;; Top level command and background process sentinel
489
490 ;; For compatibility with older versions.
491 ;;;###autoload 282 ;;;###autoload
492 (defalias 'manual-entry 'man) 283 (defun manual-entry (topic &optional arg silent)
493 284 "Display the Unix manual entry (or entries) for TOPIC.
494 ;;;###autoload 285 If prefix arg is given, modify the search according to the value:
495 (defun man (man-args) 286 2 = complement default exact matching of the TOPIC name;
496 "Get a Un*x manual page and put it in a buffer. 287 exact matching default is specified by `Manual-match-topic-exactly'
497 This command is the top-level command in the man package. It runs a Un*x 288 3 = force a search of the unformatted man directories
498 command to retrieve and clean a manpage in the background and places the 289 4 = both 2 and 3
499 results in a Man mode (manpage browsing) buffer. See variable 290 The manual entries are searched according to the variable
500 `Man-notify-method' for what happens when the buffer is ready. 291 Manual-directory-list, which should be a list of directories. If
501 If a buffer already exists for this man page, it will display immediately." 292 Manual-directory-list is nil, \\[Manual-directory-list-init] is
293 invoked to create this list from the MANPATH environment variable.
294 See the variable Manual-topic-buffer which controls how the buffer
295 is named. See also the variables Manual-match-topic-exactly,
296 Manual-query-multiple-pages, and Manual-buffer-view-mode."
502 (interactive 297 (interactive
503 (list (let* ((default-entry (Man-default-man-entry)) 298 (list (let* ((fmh "-A-Za-z0-9_.")
504 (input (read-string 299 (default (save-excursion
505 (format "Manual entry%s: " 300 (buffer-substring
506 (if (string= default-entry "") 301 (progn
507 "" 302 (re-search-backward "\\sw" nil t)
508 (format " (default %s)" default-entry)))))) 303 (skip-chars-backward fmh) (point))
509 (if (string= input "") 304 (progn (skip-chars-forward fmh) (point)))))
510 (if (string= default-entry "") 305 (thing (read-string
511 (error "No man args given") 306 (if (equal default "") "Manual entry: "
512 default-entry) 307 (concat "Manual entry: (default " default ") ")))))
513 input)))) 308 (if (equal thing "") default thing))
514 309 (prefix-numeric-value current-prefix-arg)))
515 ;; Possibly translate the "subject(section)" syntax into the 310 ;;(interactive "sManual entry (topic): \np")
516 ;; "section subject" syntax and possibly downcase the section. 311 (or arg (setq arg 1))
517 (setq man-args (Man-translate-references man-args)) 312 (Manual-directory-list-init nil)
518 313 (let ((exact (if (or (= arg 2) (= arg 4))
519 (Man-getpage-in-background man-args)) 314 (not Manual-match-topic-exactly)
520 315 Manual-match-topic-exactly))
521 316 (force (if (>= arg 3)
522 (defun Man-getpage-in-background (topic) 317 t
523 "Uses TOPIC to build and fire off the manpage and cleaning command." 318 nil))
524 (let* ((man-args topic) 319 section fmtlist manlist apropos-mode)
525 (bufname (concat "*Man " man-args "*")) 320 (let ((case-fold-search nil))
526 (buffer (get-buffer bufname))) 321 (if (and (null section)
527 (if buffer 322 (string-match
528 (Man-notify-when-ready buffer) 323 "\\`[ \t]*\\([^( \t]+\\)[ \t]*(\\(.+\\))[ \t]*\\'" topic))
529 (require 'env) 324 (setq section (substring topic (match-beginning 2)
530 (message "Invoking %s %s in the background" manual-program man-args) 325 (match-end 2))
531 (setq buffer (generate-new-buffer bufname)) 326 topic (substring topic (match-beginning 1)
327 (match-end 1)))
328 (if (string-match "\\`[ \t]*-k[ \t]+\\([^ \t]+\\)\\'" topic)
329 (setq section "-k"
330 topic (substring topic (match-beginning 1))))))
331 (if (equal section "-k")
332 (setq apropos-mode t)
333 (or silent
334 (message "Looking for formatted entry for %s%s..."
335 topic (if section (concat "(" section ")") "")))
336 (setq fmtlist (Manual-select-man-pages
337 Manual-formatted-directory-list
338 topic section exact '()))
339 (if (or force (not section) (null fmtlist))
340 (progn
341 (or silent
342 (message "%sooking for unformatted entry for %s%s..."
343 (if fmtlist "L" "No formatted entry, l")
344 topic (if section (concat "(" section ")") "")))
345 (setq manlist (Manual-select-man-pages
346 Manual-unformatted-directory-list
347 topic section exact (if force '() fmtlist))))))
348
349 ;; Delete duplicate man pages (a file of the same name in multiple
350 ;; directories.)
351 (or nil ;force
352 (let ((rest (append fmtlist manlist)))
353 (while rest
354 (let ((rest2 (cdr rest)))
355 (while rest2
356 (if (equal (file-name-nondirectory (car rest))
357 (file-name-nondirectory (car rest2)))
358 (setq fmtlist (delq (car rest2) fmtlist)
359 manlist (delq (car rest2) manlist)))
360 (setq rest2 (cdr rest2))))
361 (setq rest (cdr rest)))))
362
363 (if (not (or fmtlist manlist apropos-mode))
364 (progn
365 (message "No entries found for %s%s" topic
366 (if section (concat "(" section ")") ""))
367 nil)
368 (let ((bufname (cond ((not Manual-topic-buffer)
369 ;; What's the point of retaining this?
370 (if apropos-mode
371 "*Manual Apropos*"
372 "*Manual Entry*"))
373 (apropos-mode
374 (concat "*man apropos " topic "*"))
375 (t
376 (concat "*man "
377 (cond (exact
378 (if section
379 (concat topic "." section)
380 topic))
381 ((or (cdr fmtlist) (cdr manlist)
382 (and fmtlist manlist))
383 ;; more than one entry found
384 (concat topic "..."))
385 (t
386 (file-name-nondirectory
387 (car (or fmtlist manlist)))))
388 "*"))))
389 (temp-buffer-show-function
390 (cond ((eq 't Manual-buffer-view-mode) 'view-buffer)
391 ((eq 'nil Manual-buffer-view-mode)
392 temp-buffer-show-function)
393 (t 'view-buffer-other-window))))
394
395 (if apropos-mode
396 (setq manlist (list (format "%s.%s" topic section))))
397
398 (cond
399 ((and Manual-topic-buffer (get-buffer bufname))
400 ;; reselect an old man page buffer if it exists already.
401 (save-excursion
402 (set-buffer (get-buffer bufname))
403 (Manual-mode))
404 (if temp-buffer-show-function
405 (funcall temp-buffer-show-function (get-buffer bufname))
406 (display-buffer bufname)))
407 (t
408 (with-output-to-temp-buffer bufname
409 (buffer-disable-undo standard-output)
410 (save-excursion
411 (set-buffer standard-output)
412 (setq buffer-read-only nil)
413 (erase-buffer)
414 (Manual-insert-pages fmtlist manlist apropos-mode)
415 (set-buffer-modified-p nil)
416 (Manual-mode)
417 ))))
418 (setq Manual-page-history
419 (cons (buffer-name)
420 (delete (buffer-name) Manual-page-history)))
421 (message nil)
422 t))))
423
424 (defun Manpage-apropos (topic &optional arg silent)
425 "Apropos on Unix manual pages for TOPIC.
426 It calls the function `manual-entry'. Look at this function for
427 further description. Look also at the variable `Manual-apropos-switch',
428 if this function doesn't work on your system."
429 (interactive
430 (list (let* ((fmh "-A-Za-z0-9_.")
431 (default (save-excursion
432 (buffer-substring
433 (progn
434 (re-search-backward "\\sw" nil t)
435 (skip-chars-backward fmh) (point))
436 (progn (skip-chars-forward fmh) (point)))))
437 (thing (read-string
438 (if (equal default "") "Manual entry: "
439 (concat "Manual entry: (default " default ") ")))))
440 (if (equal thing "") default thing))
441 (prefix-numeric-value current-prefix-arg)))
442 (manual-entry (concat Manual-apropos-switch " " topic) arg silent))
443
444 (defun Manual-insert-pages (fmtlist manlist apropos-mode)
445 (let ((sep (make-string 65 ?-))
446 name start end topic section)
447 (while fmtlist ; insert any formatted files
448 (setq name (car fmtlist))
449 (goto-char (point-max))
450 (setq start (point))
451 ;; In case the file can't be read or uncompressed or
452 ;; something like that.
453 (condition-case ()
454 (Manual-insert-man-file name)
455 (file-error nil))
456 (goto-char (point-max))
457 (setq end (point))
532 (save-excursion 458 (save-excursion
533 (set-buffer buffer) 459 (save-restriction
534 (setq Man-original-frame (selected-frame)) 460 (message "Cleaning manual entry for %s..."
535 (setq Man-arguments man-args)) 461 (file-name-nondirectory name))
536 (let ((process-environment (copy-sequence process-environment))) 462 (narrow-to-region start end)
537 ;; Prevent any attempt to use display terminal fanciness. 463 (Manual-nuke-nroff-bs)
538 (setenv "TERM" "dumb") 464 (goto-char (point-min))
539 (set-process-sentinel 465 (insert "File: " name "\n")
540 (start-process manual-program buffer "sh" "-c" 466 (goto-char (point-max))
541 (format (Man-build-man-command) man-args)) 467 ))
542 'Man-bgproc-sentinel))))) 468 (if (or (cdr fmtlist) manlist)
543 469 (insert "\n\n" sep "\n"))
544 (defun Man-notify-when-ready (man-buffer) 470 (setq fmtlist (cdr fmtlist)))
545 "Notify the user when MAN-BUFFER is ready. 471
546 See the variable `Man-notify-method' for the different notification behaviors." 472 (while manlist ; process any unformatted files
547 (let ((saved-frame (save-excursion 473 (setq name (car manlist))
548 (set-buffer man-buffer) 474 (or (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\(\\.gz\\'\\)" name)
549 Man-original-frame))) 475 (string-match "\\([^/]+\\)\\.\\([^./]+\\)\\'" name))
550 (cond 476 (setq topic (substring name (match-beginning 1) (match-end 1)))
551 ((eq Man-notify-method 'newframe) 477 (setq section (substring name (match-beginning 2) (match-end 2)))
552 ;; Since we run asynchronously, perhaps while Emacs is waiting 478 ;; This won't work under IRIX, because SGI man accepts only the
553 ;; for input, we must not leave a different buffer current. We 479 ;; "main" (one-character) section id, not full section ids
554 ;; can't rely on the editor command loop to reselect the 480 ;; like 1M, 3X, etc. Put (setq Manual-use-full-section-ids nil)
555 ;; selected window's buffer. 481 ;; in your .emacs to work around this problem.
482 (if (not (or Manual-use-full-section-ids (string-equal section "")))
483 (setq section (substring section 0 1)))
484 (message "Invoking man %s%s %s..."
485 (if Manual-section-switch
486 (concat Manual-section-switch " ")
487 "")
488 section topic)
489 (setq start (point))
490 (Manual-run-formatter name topic section)
491 (setq end (point))
556 (save-excursion 492 (save-excursion
557 (set-buffer man-buffer) 493 (save-restriction
558 (make-frame Man-frame-parameters))) 494 (message "Cleaning manual entry for %s(%s)..." topic section)
559 ((eq Man-notify-method 'pushy) 495 (narrow-to-region start end)
560 (switch-to-buffer man-buffer)) 496 (Manual-nuke-nroff-bs apropos-mode)
561 ((eq Man-notify-method 'bully) 497 (goto-char (point-min))
562 (and window-system 498 (insert "File: " name "\n")
563 (frame-live-p saved-frame) 499 (goto-char (point-max))
564 (select-frame saved-frame)) 500 ))
565 (pop-to-buffer man-buffer) 501 (if (cdr manlist)
566 (delete-other-windows)) 502 (insert "\n\n" sep "\n"))
567 ((eq Man-notify-method 'aggressive) 503 (setq manlist (cdr manlist))))
568 (and window-system 504 (if (< (buffer-size) 200)
569 (frame-live-p saved-frame) 505 (progn
570 (select-frame saved-frame)) 506 (goto-char (point-min))
571 (pop-to-buffer man-buffer)) 507 (if (looking-at "^File: ")
572 ((eq Man-notify-method 'friendly) 508 (forward-line 1))
573 (and window-system 509 (error (buffer-substring (point) (progn (end-of-line) (point))))))
574 (frame-live-p saved-frame) 510 nil)
575 (select-frame saved-frame)) 511
576 (display-buffer man-buffer 'not-this-window)) 512
577 ((eq Man-notify-method 'polite) 513 (defun Manual-run-formatter (name topic section)
578 (beep) 514 (cond ((string-match "roff\\'" Manual-program)
579 (message "Manual buffer %s is ready" (buffer-name man-buffer))) 515 ;; kludge kludge
580 ((eq Man-notify-method 'quiet) 516 (call-process Manual-program nil t nil "-Tman" "-man" name))
581 (message "Manual buffer %s is ready" (buffer-name man-buffer))) 517 (Manual-section-switch
582 ((or (eq Man-notify-method 'meek) 518 (call-process Manual-program nil t nil Manual-section-switch
583 t) 519 section topic))
584 (message "")) 520 (t
585 ))) 521 (call-process Manual-program nil t nil section topic))))
586 522
587 (defun Man-fontify-manpage () 523
588 "Convert overstriking and underlining to the correct fonts. 524 (defvar Manual-mode-map
589 Same for the ANSI bold and normal escape sequences." 525 (let ((m (make-sparse-keymap)))
526 (set-keymap-name m 'Manual-mode-map)
527 (define-key m "l" 'Manual-last-page)
528 (define-key m 'button2 'Manual-follow-xref)
529 (define-key m 'button3 'Manual-popup-menu)
530 m))
531
532 (defun Manual-mode ()
533 (kill-all-local-variables)
534 (setq buffer-read-only t)
535 (use-local-map Manual-mode-map)
536 (setq major-mode 'Manual-mode
537 mode-name "Manual")
538 ;; man pages with long lines are buggy!
539 ;; This looks slightly better if they only
540 ;; overran by a couple of chars.
541 (setq truncate-lines t)
542 ;; turn off horizontal scrollbars in this buffer
543 (set-specifier scrollbar-height (cons (current-buffer) 0))
544 (run-hooks 'Manual-mode-hook))
545
546 (defun Manual-last-page ()
590 (interactive) 547 (interactive)
591 (message "Please wait: making up the %s man page..." Man-arguments) 548 (while (or (not (get-buffer (car (or Manual-page-history
592 (goto-char (point-min)) 549 (error "No more history.")))))
593 (while (search-forward "\e[1m" nil t) 550 (eq (get-buffer (car Manual-page-history)) (current-buffer)))
594 (delete-backward-char 4) 551 (setq Manual-page-history (cdr Manual-page-history)))
595 (put-text-property (point) 552 (switch-to-buffer (car Manual-page-history)))
596 (progn (if (search-forward "\e[0m" nil 'move) 553
597 (delete-backward-char 4)) 554
598 (point)) 555 ;; Manual-select-subdirectories
599 'face Man-overstrike-face)) 556 ;; Given a DIRLIST and a SUBDIR name, return all subdirectories of the former which
557 ;; match the latter.
558
559 (defun Manual-select-subdirectories (dirlist subdir)
560 (let ((dirs '())
561 (case-fold-search nil)
562 (match (concat "\\`" (regexp-quote subdir)))
563 d)
564 (while dirlist
565 (setq d (car dirlist) dirlist (cdr dirlist))
566 (if (file-directory-p d)
567 (let ((files (directory-files d t match nil 'dirs-only))
568 (dir-temp '()))
569 (while files
570 (if (file-executable-p (car files))
571 (setq dir-temp (cons (file-name-as-directory (car files))
572 dir-temp)))
573 (setq files (cdr files)))
574 (and dir-temp
575 (setq dirs (append dirs (nreverse dir-temp)))))))
576 dirs))
577
578
579 ;; Manual-filter-subdirectories
580 ;; Given a DIRLIST and a SUBDIR name, return all members of the former
581 ;; which match the latter.
582
583 (defun Manual-filter-subdirectories (dirlist subdir)
584 (let ((match (concat
585 "/"
586 (regexp-quote subdir)
587 "[" Manual-man-page-section-ids "]"))
588 slist dir)
589 (while dirlist
590 (setq dir (car dirlist) dirlist (cdr dirlist))
591 (if (and (file-executable-p dir) (string-match match dir))
592 (setq slist (cons dir slist))))
593 (nreverse slist)))
594
595
596 (defun Manual-all-subdirectories (dirlist leaf-signature dirs &optional silent) "\
597 Given a DIRLIST, return a backward-sorted list of all subdirectories
598 thereof, prepended to DIRS if non-nil. This function calls itself
599 recursively until subdirectories matching LEAF-SIGNATURE are reached,
600 or the hierarchy has been thoroughly searched. This code is a modified
601 version of a function written by Tim Bradshaw (tfb@ed.ac.uk)."
602 (Manual-all-subdirectories-noloop dirlist leaf-signature dirs nil silent))
603
604 (defun Manual-all-subdirectories-noloop (dirlist leaf-signature dirs been &optional silent) "\
605 Does the job of manual-all-subdirectories and keeps track of where it
606 has been to avoid loops."
607 (let (dir)
608 (while dirlist
609 (setq dir (car dirlist) dirlist (cdr dirlist))
610 (if (file-directory-p dir)
611 (let ((dir-temp (cons (file-name-as-directory dir) dirs)))
612 ;; Without feedback the user might wonder about the delay!
613 (or silent (message
614 "Building list of search directories... %s"
615 (car dir-temp)))
616 (if (member (file-truename dir) been)
617 () ; Ignore. We have been here before
618 (setq been (cons (file-truename dir) been))
619 (setq dirs
620 (if (string-match leaf-signature dir)
621 dir-temp
622 (Manual-all-subdirectories-noloop
623 (directory-files dir t "[^.]$" nil 'dirs-only)
624 leaf-signature dir-temp been silent))))))))
625 dirs)
626
627
628 (defvar Manual-bogus-file-pattern "\\.\\(lpr\\|ps\\|PS\\)\\'"
629 "Some systems have files in the man/man*/ directories which aren't man pages.
630 This pattern is used to prune those files.")
631
632 ;; Manual-select-man-pages
633 ;;
634 ;; Given a DIRLIST, discover all filenames which complete given the TOPIC
635 ;; and SECTION.
636
637 ;; ## Note: BSD man looks for .../man1/foo.1 and .../man1/$MACHINE/foo.1
638
639 ;; ## Fixed for SGI IRIX 5.x on Sat Jul 15 1995 by Dale Atems
640 ;; (atems@physics.wayne.edu).
641
642 (defun Manual-select-man-pages (dirlist topic section exact shadow)
643 (let ((case-fold-search nil))
644 (and section
645 (let ((l '())
646 ;;(match (concat (substring section 0 1) "/?\\'"))
647 ;; ^^^
648 ;; We'll lose any pages inside subdirectories of the "standard"
649 ;; ones if we insist on this! The following regexp should
650 ;; match any directory ending with the full section id or
651 ;; its first character, or any direct subdirectory thereof:
652 (match (concat "\\("
653 (regexp-quote section)
654 "\\|"
655 (substring section 0 1)
656 "\\)/?"))
657 d)
658 (while dirlist
659 (setq d (car dirlist) dirlist (cdr dirlist))
660 (if (string-match match d)
661 (setq l (cons d l))))
662 (setq dirlist l)))
663 (if shadow
664 (setq shadow (concat "/\\("
665 (mapconcat #'(lambda (n)
666 (regexp-quote
667 (file-name-nondirectory n)))
668 shadow
669 "\\|")
670 "\\)\\'")))
671 (let ((manlist '())
672 (match (concat "\\`"
673 (regexp-quote topic)
674 ;; **Note: on IRIX the preformatted pages
675 ;; are packed, so they end with ".z". This
676 ;; way you miss them if you specify a
677 ;; section. I don't see any point to it here
678 ;; even on BSD systems since we're looking
679 ;; one level down already, but I can't test
680 ;; this. More thought needed (???)
681
682 (cond ((and section
683 (not Manual-use-subdirectory-list))
684 (concat "\\." (regexp-quote section)))
685 (exact
686 ;; If Manual-match-topic-exactly is
687 ;; set, then we must make sure the
688 ;; completions are exact, except for
689 ;; trailing weird characters after
690 ;; the section.
691 "\\.")
692 (t
693 ""))))
694 dir)
695 (while dirlist
696 (setq dir (car dirlist) dirlist (cdr dirlist))
697 (if (not (file-directory-p dir))
698 (progn
699 (message "warning: %s is not a directory" dir)
700 ;;(sit-for 1)
701 )
702 (let ((files (directory-files dir t match nil t))
703 f)
704 (while files
705 (setq f (car files) files (cdr files))
706 (cond ((string-match Manual-bogus-file-pattern f)
707 ;(message "Bogus fule %s" f) (sit-for 2)
708 )
709 ((and shadow (string-match shadow f))
710 ;(message "Shadowed %s" f) (sit-for 2)
711 )
712 ((not (file-readable-p f))
713 ;(message "Losing with %s" f) (sit-for 2)
714 )
715 (t
716 (setq manlist (cons f manlist))))))))
717 (setq manlist (nreverse manlist))
718 (and Manual-unique-man-sections-only
719 (setq manlist (Manual-clean-to-unique-pages-only manlist)))
720 (if (and manlist Manual-query-multiple-pages)
721 (apply #'append
722 (mapcar #'(lambda (page)
723 (and page
724 (y-or-n-p (format "Read %s? " page))
725 (list page)))
726 manlist))
727 manlist))))
728
729 (defun Manual-clean-to-unique-pages-only (manlist)
730 "Prune the current list of pages down to a unique set."
731 (let (page-name unique-pages)
732 (apply 'append
733 (mapcar '(lambda (page)
734 (cond (page
735 (and (string-match ".*/\\(.*\\)" page)
736 (setq page-name (substring page (match-beginning 1)
737 (match-end 1)))
738 ;; try to clip off .Z, .gz suffixes
739 (and (string-match "\\(.*\\)\\.\\(.+\\)\\.\\(.+\\)"
740 page-name)
741 (setq page-name
742 (substring page-name (match-beginning 1)
743 (match-end 2)))))
744 ;; add Manual-unique-pages if it isn't there
745 ;; and return file
746 (if (and unique-pages
747 page-name
748 (string-match (concat "\\b" page-name "\\b")
749 unique-pages))
750 nil
751 (setq unique-pages (concat unique-pages
752 page-name
753 " "))
754 (list page)))))
755 manlist))))
756
757
758
759 (defun Manual-insert-man-file (name)
760 ;; Insert manual file (unpacked as necessary) into buffer
761 (cond ((equal (substring name -3) ".gz")
762 (call-process "gunzip" nil t nil "--stdout" name))
763 ((or (equal (substring name -2) ".Z")
764 ;; HPUX uses directory names that end in .Z and compressed
765 ;; files that don't. How gratuitously random.
766 (let ((case-fold-search nil))
767 (string-match "\\.Z/" name)))
768 (call-process "zcat" name t nil)) ;; XEmacs change for HPUX
769 ((equal (substring name -2) ".z")
770 (call-process "pcat" nil t nil name))
771 (t
772 (insert-file-contents name))))
773
774 (defmacro Manual-delete-char (n)
775 ;; in v19, delete-char is compiled as a function call, but delete-region
776 ;; is byte-coded, so it's much faster. (We were spending 40% of our time
777 ;; in delete-char alone.)
778 (list 'delete-region '(point) (list '+ '(point) n)))
779
780 ;; Hint: BS stands form more things than "back space"
781 (defun Manual-nuke-nroff-bs (&optional apropos-mode)
782 (interactive "*")
783 ;;
784 ;; turn underlining into italics
785 ;;
600 (goto-char (point-min)) 786 (goto-char (point-min))
601 (while (search-forward "_\b" nil t) 787 (while (search-forward "_\b" nil t)
602 (backward-delete-char 2) 788 ;; searching for underscore-backspace and then comparing the following
603 (put-text-property (point) (1+ (point)) 'face Man-underline-face)) 789 ;; chars until the sequence ends turns out to be much faster than searching
790 ;; for a regexp which matches the whole sequence.
791 (let ((s (match-beginning 0)))
792 (goto-char s)
793 (while (and (= (following-char) ?_)
794 (= (char-after (1+ (point))) ?\b))
795 (Manual-delete-char 2)
796 (forward-char 1))
797 (set-extent-face (make-extent s (point)) 'man-italic)))
798 ;;
799 ;; turn overstriking into bold
800 ;;
604 (goto-char (point-min)) 801 (goto-char (point-min))
605 (while (search-forward "\b_" nil t) 802 (while (re-search-forward "\\([^\n]\\)\\(\b\\1\\)" nil t)
606 (backward-delete-char 2) 803 ;; Surprisingly, searching for the above regexp is faster than searching
607 (put-text-property (1- (point)) (point) 'face Man-underline-face)) 804 ;; for a backspace and then comparing the preceding and following chars,
805 ;; I presume because there are many false matches, meaning more funcalls
806 ;; to re-search-forward.
807 (let ((s (match-beginning 0)))
808 (goto-char s)
809 ;; Some systems (SGI) overstrike multiple times, eg, "M\bM\bM\bM".
810 (while (looking-at "\\([^\n]\\)\\(\b\\1\\)+")
811 (delete-region (+ (point) 1) (match-end 0))
812 (forward-char 1))
813 (set-extent-face (make-extent s (point)) 'man-bold)))
814 ;;
815 ;; hack bullets: o^H+ --> +
608 (goto-char (point-min)) 816 (goto-char (point-min))
609 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t) 817 (while (search-forward "\b" nil t)
610 (replace-match "\\1") 818 (Manual-delete-char -2))
611 (put-text-property (1- (point)) (point) 'face Man-overstrike-face)) 819
820 (if (> (buffer-size) 100) ; minor kludge
821 (Manual-nuke-nroff-bs-footers))
822 ;;
823 ;; turn subsection header lines into bold
824 ;;
612 (goto-char (point-min)) 825 (goto-char (point-min))
613 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) 826 (if apropos-mode
614 (replace-match "o") 827 (while (re-search-forward "[a-zA-Z0-9] ([0-9]" nil t)
615 (put-text-property (1- (point)) (point) 'face 'bold)) 828 (forward-char -2)
829 (delete-backward-char 1))
830
831 ;; (while (re-search-forward "^[^ \t\n]" nil t)
832 ;; (set-extent-face (make-extent (match-beginning 0)
833 ;; (progn (end-of-line) (point)))
834 ;; 'man-heading))
835
836 ;; boldface the first line
837 (if (looking-at "[^ \t\n].*$")
838 (set-extent-face (make-extent (match-beginning 0) (match-end 0))
839 'man-bold))
840
841 ;; boldface subsequent title lines
842 ;; Regexp to match section headers changed to match a non-indented
843 ;; line preceded by a blank line and followed by an indented line.
844 ;; This seems to work ok for manual pages but gives better results
845 ;; with other nroff'd files
846 (while (re-search-forward "\n\n\\([^ \t\n].*\\)\n[ \t]+[^ \t\n]" nil t)
847 (goto-char (match-end 1))
848 (set-extent-face (make-extent (match-beginning 1) (match-end 1))
849 'man-heading)
850 (forward-line 1))
851 )
852
853 ;; Zap ESC7, ESC8, and ESC9
854 ;; This is for Sun man pages like "man 1 csh"
616 (goto-char (point-min)) 855 (goto-char (point-min))
617 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) 856 (while (re-search-forward "\e[789]" nil t)
618 (replace-match "+") 857 (replace-match ""))
619 (put-text-property (1- (point)) (point) 'face 'bold)) 858
620 ;; \255 is some kind of dash in Latin-1. 859 ;; Nuke blanks lines at start.
860 ;; (goto-char (point-min))
861 ;; (skip-chars-forward "\n")
862 ;; (delete-region (point-min) (point))
863
864 (Manual-mouseify-xrefs)
865 )
866
867 (fset 'nuke-nroff-bs 'Manual-nuke-nroff-bs) ; use old name
868
869
870 (defun Manual-nuke-nroff-bs-footers ()
871 ;; Nuke headers and footers.
872 ;;
873 ;; nroff assumes pages are 66 lines high. We assume that, and that the
874 ;; first and last line on each page is expendible. There is no way to
875 ;; tell the difference between a page break in the middle of a paragraph
876 ;; and a page break between paragraphs (the amount of extra whitespace
877 ;; that nroff inserts is the same in both cases) so this might strip out
878 ;; a blank line were one should remain. I think that's better than
879 ;; leaving in a blank line where there shouldn't be one. (Need I say
880 ;; it: FMH.)
881 ;;
882 ;; Note that if nroff spits out error messages, pages will be more than
883 ;; 66 lines high, and we'll lose badly. That's ok because standard
884 ;; nroff doesn't do any diagnostics, and the "gnroff" wrapper for groff
885 ;; turns off error messages for compatibility. (At least, it's supposed
886 ;; to.)
887 ;;
621 (goto-char (point-min)) 888 (goto-char (point-min))
622 (while (search-forward "\255" nil t) (replace-match "-")) 889 ;; first lose the status output
623 (message "%s man page made up" Man-arguments)) 890 (let ((case-fold-search t))
624 891 (if (and (not (looking-at "[^\n]*warning"))
625 (defun Man-cleanup-manpage () 892 (looking-at "Reformatting.*\n"))
626 "Remove overstriking and underlining from the current buffer." 893 (delete-region (match-beginning 0) (match-end 0))))
627 (interactive) 894
628 (message "Please wait: cleaning up the %s man page..." 895 ;; kludge around a groff bug where it won't keep quiet about some
629 Man-arguments) 896 ;; warnings even with -Wall or -Ww.
630 (if (or (interactive-p) (not Man-sed-script)) 897 (cond ((looking-at "grotty:")
631 (progn 898 (while (looking-at "grotty:")
632 (goto-char (point-min)) 899 (delete-region (point) (progn (forward-line 1) (point))))
633 (while (search-forward "_\b" nil t) (backward-delete-char 2)) 900 (if (looking-at " *done\n")
634 (goto-char (point-min)) 901 (delete-region (point) (match-end 0)))))
635 (while (search-forward "\b_" nil t) (backward-delete-char 2)) 902
636 (goto-char (point-min)) 903 (let ((pages '())
637 (while (re-search-forward "\\(.\\)\\(\b\\1\\)+" nil t) 904 p)
638 (replace-match "\\1")) 905 ;; collect the page boundary markers before we start deleting, to make
639 (goto-char (point-min)) 906 ;; it easier to strip things out without changing the page sizes.
640 (while (re-search-forward "\e\\[[0-9]+m" nil t) (replace-match "")) 907 (while (not (eobp))
641 (goto-char (point-min)) 908 (forward-line 66)
642 (while (re-search-forward "o\b\\+\\|\\+\bo" nil t) (replace-match "o")) 909 (setq pages (cons (point-marker) pages)))
643 )) 910 (setq pages (nreverse pages))
911 (while pages
912 (goto-char (car pages))
913 (set-marker (car pages) nil)
914 ;;
915 ;; The lines are: 3 blank; footer; 6 blank; header; 3 blank.
916 ;; We're in between the previous footer and the following header,
917 ;;
918 ;; First lose 3 blank lines, the header, and then 3 more.
919 ;;
920 (setq p (point))
921 (skip-chars-forward "\n")
922 (delete-region p (point))
923 (and (looking-at "[^\n]+\n\n?\n?\n?")
924 (delete-region (match-beginning 0) (match-end 0)))
925 ;;
926 ;; Next lose the footer, and the 3 blank lines after, and before it.
927 ;; But don't lose the last footer of the manual entry; that contains
928 ;; the "last change" date, so it's not completely uninteresting.
929 ;; (Actually lose all blank lines before it; sh(1) needs this.)
930 ;;
931 (skip-chars-backward "\n")
932 (beginning-of-line)
933 (if (null (cdr pages))
934 nil
935 (and (looking-at "[^\n]+\n\n?\n?\n?")
936 (delete-region (match-beginning 0) (match-end 0))))
937 (setq p (point))
938 (skip-chars-backward "\n")
939 (if (> (- p (point)) 4)
940 (delete-region (+ 2 (point)) p)
941 (delete-region (1+ (point)) p))
942 ; (and (looking-at "\n\n?\n?")
943 ; (delete-region (match-beginning 0) (match-end 0)))
944
945 (setq pages (cdr pages)))
946 ;;
947 ;; Now nuke the extra blank lines at the beginning and end.
948 (goto-char (point-min))
949 (if (looking-at "\n+")
950 (delete-region (match-beginning 0) (match-end 0)))
951 (forward-line 1)
952 (if (looking-at "\n\n+")
953 (delete-region (1+ (match-beginning 0)) (match-end 0)))
954 (goto-char (point-max))
955 (skip-chars-backward "\n")
956 (delete-region (point) (point-max))
957 (beginning-of-line)
958 (forward-char -1)
959 (setq p (point))
960 (skip-chars-backward "\n")
961 (if (= ?\n (following-char)) (forward-char 1))
962 (if (> (point) (1+ p))
963 (delete-region (point) p))
964 ))
965
966 ;(defun Manual-nuke-nroff-bs-footers ()
967 ; ;; Nuke headers: "MORE(1) UNIX Programmer's Manual MORE(1)"
968 ; (goto-char (point-min))
969 ; (while (re-search-forward "^ *\\([A-Za-z][-_A-Za-z0-9]*([0-9A-Za-z]+)\\).*\\1$" nil t)
970 ; (replace-match ""))
971 ;
972 ; ;;
973 ; ;; it would appear that we have a choice between sometimes introducing
974 ; ;; an extra blank line when a paragraph was broken by a footer, and
975 ; ;; sometimes not putting in a blank line between two paragraphs when
976 ; ;; a footer appeared right between them. FMH; I choose the latter.
977 ; ;;
978 ;
979 ; ;; Nuke footers: "Printed 12/3/85 27 April 1981 1"
980 ; ;; Sun appear to be on drugz:
981 ; ;; "Sun Release 3.0B Last change: 1 February 1985 1"
982 ; ;; HP are even worse!
983 ; ;; " Hewlett-Packard -1- (printed 12/31/99)" FMHWA12ID!!
984 ; ;; System V (well WICATs anyway):
985 ; ;; "Page 1 (printed 7/24/85)"
986 ; ;; Who is administering PCP to these corporate bozos?
987 ; (goto-char (point-min))
988 ; (while (re-search-forward
989 ; (cond
990 ; ((eq system-type 'hpux)
991 ; "\n\n?[ \t]*Hewlett-Packard\\(\\| Company\\)[ \t]*- [0-9]* -.*\n")
992 ; ((eq system-type 'dgux-unix)
993 ; "\n\n?[ \t]*Licensed material--.*Page [0-9]*\n")
994 ; ((eq system-type 'usg-unix-v)
995 ; "\n\n? *Page [0-9]*.*(printed [0-9/]*)\n")
996 ; (t
997 ; "\n\n?\\(Printed\\|Sun Release\\) [0-9].*[0-9]\n"))
998 ; nil t)
999 ; (replace-match ""))
1000 ;
1001 ; ;; Also, hack X footers:
1002 ; ;; "X Version 11 Last change: Release 5 1"
1003 ; (goto-char (point-min))
1004 ; (while (re-search-forward "\n\n?X Version [^\n]+\n" nil t)
1005 ; (replace-match ""))
1006 ;
1007 ; ;; Crunch blank lines
1008 ; (goto-char (point-min))
1009 ; (while (re-search-forward "\n\n\n\n*" nil t)
1010 ; (replace-match "\n\n"))
1011 ; )
1012
1013 (defun Manual-mouseify-xrefs ()
644 (goto-char (point-min)) 1014 (goto-char (point-min))
645 (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+")) 1015 (forward-line 1)
646 ;; \255 is some kind of dash in Latin-1. 1016 (let ((case-fold-search nil)
647 (goto-char (point-min)) 1017 s e name extent)
648 (while (search-forward "\255" nil t) (replace-match "-")) 1018 ;; possibly it would be faster to rewrite this expression to search for
649 (message "%s man page cleaned up" Man-arguments)) 1019 ;; a less common sequence first (like "([0-9]") and then back up to see
650 1020 ;; if it's really a match. This function is 15% of the total time, 13%
651 (defun Man-bgproc-sentinel (process msg) 1021 ;; of which is this call to re-search-forward.
652 "Manpage background process sentinel." 1022 (while (re-search-forward "[a-zA-Z_][-a-zA-Z0-9_.]*([0-9][a-zA-Z0-9]*)"
653 (let ((Man-buffer (process-buffer process)) 1023 nil t)
654 (delete-buff nil) 1024 (setq s (match-beginning 0)
655 (err-mess nil)) 1025 e (match-end 0)
656 1026 name (buffer-substring s e))
657 (if (null (buffer-name Man-buffer)) ;; deleted buffer 1027 (goto-char s)
658 (set-process-buffer process nil) 1028 (skip-chars-backward " \t")
659 1029 (if (and (bolp)
660 (save-excursion 1030 (progn (backward-char 1) (= (preceding-char) ?-)))
661 (set-buffer Man-buffer) 1031 (progn
662 (let ((case-fold-search nil)) 1032 (setq s (point))
663 (goto-char (point-min)) 1033 (skip-chars-backward "-a-zA-Z0-9_.")
664 (cond ((or (looking-at "No \\(manual \\)*entry for") 1034 (setq name (concat (buffer-substring (point) (1- s)) name))
665 (looking-at "[^\n]*: nothing appropriate$")) 1035 (setq s (point))))
666 (setq err-mess (buffer-substring (point) 1036 ;; if there are upper case letters in the section, downcase them.
667 (progn 1037 (if (string-match "(.*[A-Z]+.*)$" name)
668 (end-of-line) (point))) 1038 (setq name (concat (substring name 0 (match-beginning 0))
669 delete-buff t)) 1039 (downcase (substring name (match-beginning 0))))))
670 ((not (and (eq (process-status process) 'exit) 1040 ;; (setq already-fontified (extent-at s))
671 (= (process-exit-status process) 0))) 1041 (setq extent (make-extent s e))
672 (setq err-mess 1042 (set-extent-property extent 'man (list 'Manual-follow-xref name))
673 (concat (buffer-name Man-buffer) 1043 (set-extent-property extent 'highlight t)
674 ": process " 1044 ;; (if (not already-fontified)...
675 (let ((eos (1- (length msg)))) 1045 (set-extent-face extent 'man-xref)
676 (if (= (aref msg eos) ?\n) 1046 (goto-char e))))
677 (substring msg 0 eos) msg)))) 1047
678 (goto-char (point-max)) 1048 (defun Manual-follow-xref (&optional name-or-event)
679 (insert (format "\nprocess %s" msg)) 1049 "Invoke `manual-entry' on the cross-reference under the mouse.
680 )) 1050 When invoked noninteractively, the arg may be an xref string to parse instead."
681 (if delete-buff 1051 (interactive "e")
682 (kill-buffer Man-buffer) 1052 (if (eventp name-or-event)
683 (if Man-fontify-manpage-flag 1053 (let* ((p (event-point name-or-event))
684 (Man-fontify-manpage) 1054 (extent (and p (extent-at p
685 (Man-cleanup-manpage)) 1055 (event-buffer name-or-event)
686 (run-hooks 'Man-cooked-hook) 1056 'highlight)))
687 (Man-mode) 1057 (data (and extent (extent-property extent 'man))))
688 (set-buffer-modified-p nil) 1058 (if (eq (car-safe data) 'Manual-follow-xref)
689 )) 1059 (eval data)
690 ;; Restore case-fold-search before calling 1060 (error "no manual cross-reference there.")))
691 ;; Man-notify-when-ready because it may switch buffers. 1061 (let ((Manual-match-topic-exactly t)
692 1062 (Manual-query-multiple-pages nil))
693 (if (not delete-buff) 1063 (or (manual-entry name-or-event)
694 (Man-notify-when-ready Man-buffer)) 1064 ;; If that didn't work, maybe it's in a different section than the
695 1065 ;; man page writer expected. For example, man pages tend assume
696 (if err-mess 1066 ;; that all user programs are in section 1, but X tends to generate
697 (error err-mess)) 1067 ;; makefiles that put things in section "n" instead...
698 )))) 1068 (and (string-match "[ \t]*([^)]+)\\'" name-or-event)
699 1069 (progn
700 1070 (message "No entries found for %s; checking other sections..."
701 ;; ====================================================================== 1071 name-or-event)
702 ;; set up manual mode in buffer and build alists 1072 (manual-entry
703 1073 (substring name-or-event 0 (match-beginning 0))
704 (defun Man-mode () 1074 nil t)))))))
705 "A mode for browsing Un*x manual pages. 1075
706 1076 (defun Manual-popup-menu (&optional event)
707 The following man commands are available in the buffer. Try 1077 "Pops up a menu of cross-references in this manual page.
708 \"\\[describe-key] <key> RET\" for more information: 1078 If there is a cross-reference under the mouse button which invoked this
709 1079 command, it will be the first item on the menu. Otherwise, they are
710 \\[man] Prompt to retrieve a new manpage. 1080 on the menu in the order in which they appear in the buffer."
711 \\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section. 1081 (interactive "e")
712 \\[Man-next-manpage] Jump to next manpage in circular list. 1082 (let ((buffer (current-buffer))
713 \\[Man-previous-manpage] Jump to previous manpage in circular list. 1083 (sep "---")
714 \\[Man-next-section] Jump to next manpage section. 1084 (prefix "Show Manual Page for ")
715 \\[Man-previous-section] Jump to previous manpage section. 1085 xref items)
716 \\[Man-goto-section] Go to a manpage section. 1086 (cond (event
717 \\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section. 1087 (setq buffer (event-buffer event))
718 \\[Man-quit] Deletes the manpage window, bury its buffer. 1088 (let* ((p (event-point event))
719 \\[Man-kill] Deletes the manpage window, kill its buffer. 1089 (extent (and p (extent-at p buffer 'highlight)))
720 \\[describe-mode] Prints this help text. 1090 (data (and extent (extent-property extent 'man))))
721 1091 (if (eq (car-safe data) 'Manual-follow-xref)
722 The following variables may be of some use. Try 1092 (setq xref (nth 1 data))))))
723 \"\\[describe-variable] <variable-name> RET\" for more information: 1093 (if xref (setq items (list sep xref)))
724 1094 (map-extents #'(lambda (extent ignore)
725 Man-notify-method What happens when manpage formatting is done. 1095 (let ((data (extent-property extent 'man)))
726 Man-downcase-section-letters-flag Force section letters to lower case. 1096 (if (and (eq (car-safe data) 'Manual-follow-xref)
727 Man-circular-pages-flag Treat multiple manpage list as circular. 1097 (not (member (nth 1 data) items)))
728 Man-auto-section-alist List of major modes and their section numbers. 1098 (setq items (cons (nth 1 data) items)))
729 Man-section-translations-alist List of section numbers and their Un*x equiv. 1099 nil))
730 Man-filter-list Background manpage filter command. 1100 buffer)
731 Man-mode-line-format Mode line format for Man mode buffers. 1101 (if (eq sep (car items)) (setq items (cdr items)))
732 Man-mode-map Keymap bindings for Man mode buffers. 1102 (let ((popup-menu-titles nil))
733 Man-mode-hook Normal hook run on entry to Man mode. 1103 (popup-menu
734 Man-section-regexp Regexp describing manpage section letters. 1104 (cons "Manual Entry"
735 Man-heading-regexp Regexp describing section headers. 1105 (mapcar #'(lambda (item)
736 Man-see-also-regexp Regexp for SEE ALSO section (or your equiv). 1106 (if (eq item sep)
737 Man-first-heading-regexp Regexp for first heading on a manpage. 1107 item
738 Man-reference-regexp Regexp matching a references in SEE ALSO. 1108 (vector (concat prefix item)
739 Man-switches Background `man' command switches. 1109 (list 'Manual-follow-xref item) t)))
740 1110 (nreverse items)))))))
741 The following key bindings are currently in effect in the buffer: 1111
742 \\{Man-mode-map}" 1112 (defun pager-cleanup-hook ()
743 (interactive) 1113 "cleanup man page if called via $PAGER"
744 (setq major-mode 'Man-mode 1114 (let ((buf-name (or buffer-file-name (buffer-name))))
745 mode-name "Man" 1115 (if (and (or (string-match "^/tmp/man[0-9]+" buf-name)
746 buffer-auto-save-file-name nil 1116 (string-match ".*/man/\\(man\\|cat\\)[1-9a-z]/" buf-name))
747 mode-line-format Man-mode-line-format 1117 (not (string-match Manual-bogus-file-pattern buf-name)))
748 truncate-lines t 1118 (let (buffer manpage)
749 buffer-read-only t) 1119 (require 'man)
750 (buffer-disable-undo (current-buffer))
751 (auto-fill-mode -1)
752 (use-local-map Man-mode-map)
753 (Man-build-page-list)
754 (Man-strip-page-headers)
755 (Man-unindent)
756 (Man-goto-page 1)
757 (run-hooks 'Man-mode-hook))
758
759 (defsubst Man-build-section-alist ()
760 "Build the association list of manpage sections."
761 (setq Man-sections-alist nil)
762 (goto-char (point-min))
763 (let ((case-fold-search nil))
764 (while (re-search-forward Man-heading-regexp (point-max) t)
765 (aput 'Man-sections-alist (Man-match-substring 1))
766 (forward-line 1))))
767
768 (defsubst Man-build-references-alist ()
769 "Build the association list of references (in the SEE ALSO section)."
770 (setq Man-refpages-alist nil)
771 (save-excursion
772 (if (Man-find-section Man-see-also-regexp)
773 (let ((start (progn (forward-line 1) (point)))
774 (end (progn
775 (Man-next-section 1)
776 (point)))
777 hyphenated
778 (runningpoint -1))
779 (save-restriction
780 (narrow-to-region start end)
781 (goto-char (point-min))
782 (back-to-indentation)
783 (while (and (not (eobp)) (/= (point) runningpoint))
784 (setq runningpoint (point))
785 (if (re-search-forward Man-reference-regexp end t)
786 (let* ((word (Man-match-substring 0))
787 (len (1- (length word))))
788 (if hyphenated
789 (setq word (concat hyphenated word)
790 hyphenated nil))
791 (if (= (aref word len) ?-)
792 (setq hyphenated (substring word 0 len))
793 (aput 'Man-refpages-alist word))))
794 (skip-chars-forward " \t\n,")))))))
795
796 (defun Man-build-page-list ()
797 "Build the list of separate manpages in the buffer."
798 (setq Man-page-list nil)
799 (let ((page-start (point-min))
800 (page-end (point-max))
801 (header ""))
802 (goto-char page-start)
803 ;; (switch-to-buffer (current-buffer))(debug)
804 (while (not (eobp))
805 (setq header
806 (if (looking-at Man-page-header-regexp)
807 (Man-match-substring 1)
808 nil))
809 ;; Go past both the current and the next Man-first-heading-regexp
810 (if (re-search-forward Man-first-heading-regexp nil 'move 2)
811 (let ((p (progn (beginning-of-line) (point))))
812 ;; We assume that the page header is delimited by blank
813 ;; lines and that it contains at most one blank line. So
814 ;; if we back by three blank lines we will be sure to be
815 ;; before the page header but not before the possible
816 ;; previous page header.
817 (search-backward "\n\n" nil t 3)
818 (if (re-search-forward Man-page-header-regexp p 'move)
819 (beginning-of-line))))
820 (setq page-end (point))
821 (setq Man-page-list (append Man-page-list
822 (list (list (copy-marker page-start)
823 (copy-marker page-end)
824 header))))
825 (setq page-start page-end)
826 )))
827
828 (defun Man-strip-page-headers ()
829 "Strip all the page headers but the first from the manpage."
830 (let ((buffer-read-only nil)
831 (case-fold-search nil)
832 (page-list Man-page-list)
833 (page ())
834 (header ""))
835 (while page-list
836 (setq page (car page-list))
837 (and (nth 2 page)
838 (goto-char (car page))
839 (re-search-forward Man-first-heading-regexp nil t)
840 (setq header (buffer-substring (car page) (match-beginning 0)))
841 ;; Since the awk script collapses all successive blank
842 ;; lines into one, and since we don't want to get rid of
843 ;; the fast awk script, one must choose between adding
844 ;; spare blank lines between pages when there were none and
845 ;; deleting blank lines at page boundaries when there were
846 ;; some. We choose the first, so we comment the following
847 ;; line.
848 ;; (setq header (concat "\n" header)))
849 (while (search-forward header (nth 1 page) t)
850 (replace-match "")))
851 (setq page-list (cdr page-list)))))
852
853 (defun Man-unindent ()
854 "Delete the leading spaces that indent the manpage."
855 (let ((buffer-read-only nil)
856 (case-fold-search nil)
857 (page-list Man-page-list))
858 (while page-list
859 (let ((page (car page-list))
860 (indent "")
861 (nindent 0))
862 (narrow-to-region (car page) (car (cdr page)))
863 (if Man-uses-untabify-flag
864 (untabify (point-min) (point-max)))
865 (if (catch 'unindent
866 (goto-char (point-min)) 1120 (goto-char (point-min))
867 (if (not (re-search-forward Man-first-heading-regexp nil t)) 1121 (setq buffer-read-only nil)
868 (throw 'unindent nil)) 1122 (Manual-nuke-nroff-bs)
869 (beginning-of-line)
870 (setq indent (buffer-substring (point)
871 (progn
872 (skip-chars-forward " ")
873 (point))))
874 (setq nindent (length indent))
875 (if (zerop nindent)
876 (throw 'unindent nil))
877 (setq indent (concat indent "\\|$"))
878 (goto-char (point-min)) 1123 (goto-char (point-min))
879 (while (not (eobp)) 1124 (if (re-search-forward "[^ \t]")
880 (if (looking-at indent) 1125 (goto-char (- (point) 1)))
881 (forward-line 1) 1126 (if (looking-at "\\([a-zA-Z0-9]+\\)[ \t]*(")
882 (throw 'unindent nil))) 1127 (setq manpage (buffer-substring (match-beginning 1) (match-end 1)))
883 (goto-char (point-min))) 1128 (setq manpage "???"))
884 (while (not (eobp)) 1129 (setq buffer
885 (or (eolp) 1130 (rename-buffer
886 (delete-char nindent)) 1131 (generate-new-buffer-name (concat "*man " manpage "*"))))
887 (forward-line 1))) 1132 (setq buffer-file-name nil)
888 (setq page-list (cdr page-list)) 1133 (goto-char (point-min))
889 )))) 1134 (insert (format "%s\n" buf-name))
890 1135 (goto-char (point-min))
891 1136 (buffer-disable-undo buffer)
892 ;; ====================================================================== 1137 (set-buffer-modified-p nil)
893 ;; Man mode commands 1138 (Manual-mode)
894 1139 ))))
895 (defun Man-next-section (n) 1140
896 "Move point to Nth next section (default 1)." 1141 (add-hook 'server-visit-hook 'pager-cleanup-hook)
897 (interactive "p")
898 (let ((case-fold-search nil))
899 (if (looking-at Man-heading-regexp)
900 (forward-line 1))
901 (if (re-search-forward Man-heading-regexp (point-max) t n)
902 (beginning-of-line)
903 (goto-char (point-max)))))
904
905 (defun Man-previous-section (n)
906 "Move point to Nth previous section (default 1)."
907 (interactive "p")
908 (let ((case-fold-search nil))
909 (if (looking-at Man-heading-regexp)
910 (forward-line -1))
911 (if (re-search-backward Man-heading-regexp (point-min) t n)
912 (beginning-of-line)
913 (goto-char (point-min)))))
914
915 (defun Man-find-section (section)
916 "Move point to SECTION if it exists, otherwise don't move point.
917 Returns t if section is found, nil otherwise."
918 (let ((curpos (point))
919 (case-fold-search nil))
920 (goto-char (point-min))
921 (if (re-search-forward (concat "^" section) (point-max) t)
922 (progn (beginning-of-line) t)
923 (goto-char curpos)
924 nil)
925 ))
926
927 (defun Man-goto-section ()
928 "Query for section to move point to."
929 (interactive)
930 (aput 'Man-sections-alist
931 (let* ((default (aheadsym Man-sections-alist))
932 (completion-ignore-case t)
933 chosen
934 (prompt (concat "Go to section: (default " default ") ")))
935 (setq chosen (completing-read prompt Man-sections-alist))
936 (if (or (not chosen)
937 (string= chosen ""))
938 default
939 chosen)))
940 (Man-find-section (aheadsym Man-sections-alist)))
941
942 (defun Man-goto-see-also-section ()
943 "Move point the the \"SEE ALSO\" section.
944 Actually the section moved to is described by `Man-see-also-regexp'."
945 (interactive)
946 (if (not (Man-find-section Man-see-also-regexp))
947 (error (concat "No " Man-see-also-regexp
948 " section found in the current manpage"))))
949
950 (defun Man-follow-manual-reference (reference)
951 "Get one of the manpages referred to in the \"SEE ALSO\" section.
952 Specify which reference to use; default is based on word at point."
953 (interactive
954 (if (not Man-refpages-alist)
955 (error "There are no references in the current man page")
956 (list (let* ((default (or
957 (car (all-completions
958 (save-excursion
959 (skip-syntax-backward "w()")
960 (skip-chars-forward " \t")
961 (let ((word (current-word)))
962 ;; strip a trailing '-':
963 (if (string-match "-$" word)
964 (substring word 0
965 (match-beginning 0))
966 word)))
967 Man-refpages-alist))
968 (aheadsym Man-refpages-alist)))
969 chosen
970 (prompt (concat "Refer to: (default " default ") ")))
971 (setq chosen (completing-read prompt Man-refpages-alist nil t))
972 (if (or (not chosen)
973 (string= chosen ""))
974 default
975 chosen)))))
976 (if (not Man-refpages-alist)
977 (error "Can't find any references in the current manpage")
978 (aput 'Man-refpages-alist reference)
979 (Man-getpage-in-background
980 (Man-translate-references (aheadsym Man-refpages-alist)))))
981
982 (defun Man-kill ()
983 "Kill the buffer containing the manpage."
984 (interactive)
985 (let ((buff (current-buffer)))
986 (delete-windows-on buff)
987 (kill-buffer buff))
988 (if (and window-system
989 (or (eq Man-notify-method 'newframe)
990 (and pop-up-frames
991 (eq Man-notify-method 'bully))))
992 (delete-frame)))
993
994 (defun Man-quit ()
995 "Bury the buffer containing the manpage."
996 (interactive)
997 (let ((buff (current-buffer)))
998 (delete-windows-on buff)
999 (bury-buffer buff))
1000 (if (and window-system
1001 (or (eq Man-notify-method 'newframe)
1002 (and pop-up-frames
1003 (eq Man-notify-method 'bully))))
1004 (delete-frame)))
1005
1006 (defun Man-goto-page (page)
1007 "Go to the manual page on page PAGE."
1008 (interactive
1009 (if (not Man-page-list)
1010 (let ((args Man-arguments))
1011 (kill-buffer (current-buffer))
1012 (error "Can't find the %s manpage" args))
1013 (if (= (length Man-page-list) 1)
1014 (error "You're looking at the only manpage in the buffer")
1015 (list (read-minibuffer (format "Go to manpage [1-%d]: "
1016 (length Man-page-list)))))))
1017 (if (not Man-page-list)
1018 (let ((args Man-arguments))
1019 (kill-buffer (current-buffer))
1020 (error "Can't find the %s manpage" args)))
1021 (if (or (< page 1)
1022 (> page (length Man-page-list)))
1023 (error "No manpage %d found" page))
1024 (let* ((page-range (nth (1- page) Man-page-list))
1025 (page-start (car page-range))
1026 (page-end (car (cdr page-range))))
1027 (setq Man-current-page page
1028 Man-page-mode-string (Man-make-page-mode-string))
1029 (widen)
1030 (goto-char page-start)
1031 (narrow-to-region page-start page-end)
1032 (Man-build-section-alist)
1033 (Man-build-references-alist)
1034 (goto-char (point-min))))
1035
1036
1037 (defun Man-next-manpage ()
1038 "Find the next manpage entry in the buffer."
1039 (interactive)
1040 (if (= (length Man-page-list) 1)
1041 (error "This is the only manpage in the buffer"))
1042 (if (< Man-current-page (length Man-page-list))
1043 (Man-goto-page (1+ Man-current-page))
1044 (if Man-circular-pages-flag
1045 (Man-goto-page 1)
1046 (error "You're looking at the last manpage in the buffer"))))
1047
1048 (defun Man-previous-manpage ()
1049 "Find the previous manpage entry in the buffer."
1050 (interactive)
1051 (if (= (length Man-page-list) 1)
1052 (error "This is the only manpage in the buffer"))
1053 (if (> Man-current-page 1)
1054 (Man-goto-page (1- Man-current-page))
1055 (if Man-circular-pages-flag
1056 (Man-goto-page (length Man-page-list))
1057 (error "You're looking at the first manpage in the buffer"))))
1058
1059 ;; Init the man package variables, if not already done.
1060 (Man-init-defvars)
1061
1062 (provide 'man) 1142 (provide 'man)
1063
1064 ;;; man.el ends here