3235
|
1 ;;; man.el --- browse UNIX manual pages
|
|
2
|
|
3 ;; Copyright (C) 1993 Free Software Foundation, Inc.
|
|
4
|
|
5 ;; Author: Barry A. Warsaw <bwarsaw@cen.com>
|
|
6 ;; Last-Modified: 31-Jul-1991
|
|
7 ;; Version: 1.1
|
|
8 ;; Keywords: help
|
|
9 ;; Adapted-By: ESR
|
|
10
|
|
11 ;; This file is part of GNU Emacs.
|
|
12
|
|
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
14 ;; it under the terms of the GNU General Public License as published by
|
|
15 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
16 ;; any later version.
|
|
17
|
|
18 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 ;; GNU General Public License for more details.
|
|
22
|
|
23 ;; You should have received a copy of the GNU General Public License
|
|
24 ;; along with GNU Emacs; see the file COPYING. If not, write to
|
|
25 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
26
|
|
27 ;;; Commentary:
|
|
28
|
|
29 ;; This code provides a function, manual-entry, with which you can
|
|
30 ;; browse UNIX manual pages. Formatting is done in background so that
|
|
31 ;; you can continue to use your Emacs while processing is going on.
|
|
32 ;;
|
|
33 ;; The mode also supports hypertext-like following of manual page SEE
|
|
34 ;; ALSO references, and other features. See below or do `?' in a
|
|
35 ;; manual page buffer for details.
|
|
36
|
|
37 ;; ========== Credits and History ==========
|
|
38 ;; In mid 1991, several people posted some interesting improvements to
|
|
39 ;; man.el from the standard emacs 18.57 distribution. I liked many of
|
|
40 ;; these, but wanted everthing in one single package, so I decided
|
|
41 ;; to encorporate them into a single manual browsing mode. While
|
|
42 ;; much of the code here has been rewritten, and some features added,
|
|
43 ;; these folks deserve lots of credit for providing the initial
|
|
44 ;; excellent packages on which this one is based.
|
|
45
|
|
46 ;; Nick Duffek <duffek@chaos.cs.brandeis.edu>, posted a very nice
|
|
47 ;; improvement which retrieved and cleaned the manpages in a
|
|
48 ;; background process, and which correctly deciphered such options as
|
|
49 ;; man -k.
|
|
50
|
|
51 ;; Eric Rose <erose@jessica.stanford.edu>, submitted manual.el which
|
|
52 ;; provided a very nice manual browsing mode.
|
|
53
|
|
54 ;; This package was available as `superman.el' from the LCD paackage
|
|
55 ;; for some time before it was accepted into Emacs 19. The entry
|
|
56 ;; point and some other names have been changed to make it a drop-in
|
|
57 ;; replacement for the old man.el package.
|
|
58
|
|
59 ;; ========== Features ==========
|
|
60 ;; + Runs "man" in the background and pipes the results through a
|
|
61 ;; series of sed and awk scripts so that all retrieving and cleaning
|
|
62 ;; is done in the background. The cleaning commands are configurable.
|
|
63 ;; + Syntax is the same as Un*x man
|
|
64 ;; + Functionality is the same as Un*x man, including "man -k" and
|
|
65 ;; "man <section>, etc.
|
|
66 ;; + Provides a manual browsing mode with keybindings for traversing
|
|
67 ;; the sections of a manpage, following references in the SEE ALSO
|
|
68 ;; section, and more.
|
|
69 ;; + Multiple manpages created with the same man command are put into
|
|
70 ;; a narrowed buffer circular list.
|
|
71
|
|
72 ;;; Code:
|
|
73
|
|
74 (require 'assoc)
|
|
75 (provide 'man)
|
|
76
|
|
77 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
78 ;; user variables
|
|
79
|
|
80 (defvar Man-notify 'friendly
|
|
81 "*Selects the behavior when manpage is ready.
|
|
82 This variable may have one of the following values:
|
|
83
|
|
84 bully -- make the manpage the current buffer and only window
|
|
85 aggressive -- make the manpage the current buffer in the other window
|
|
86 friendly -- display manpage in other window but don't make current
|
|
87 polite -- don't display manpage, but prints message when ready (beeps)
|
|
88 quiet -- like `polite', but don't beep
|
|
89 meek -- make no indication that manpage is ready
|
|
90
|
|
91 Any other value of `Man-notify' is equivalent to `meek'.")
|
|
92
|
|
93 (defvar Man-reuse-okay-p t
|
|
94 "*Reuse a manpage buffer if possible.
|
|
95 When t, and a manpage buffer already exists with the same invocation,
|
|
96 man just indicates the manpage is ready according to the value of
|
|
97 Man-notify. When nil, it always fires off a background process, putting
|
|
98 the results in a uniquely named buffer.")
|
|
99
|
|
100 (defvar Man-downcase-section-letters-p t
|
|
101 "*Letters in sections are converted to lower case.
|
|
102 Some Un*x man commands can't handle uppercase letters in sections, for
|
|
103 example \"man 2V chmod\", but they are often displayed in the manpage
|
|
104 with the upper case letter. When this variable is t, the section
|
|
105 letter (e.g., \"2V\") is converted to lowercase (e.g., \"2v\") before
|
|
106 being sent to the man background process.")
|
|
107
|
|
108 (defvar Man-circular-pages-p t
|
|
109 "*If t, the manpage list is treated as circular for traversal.")
|
|
110
|
|
111 (defvar Man-auto-section-alist
|
|
112 '((c-mode . ("2" "3"))
|
|
113 (c++-mode . ("2" "3"))
|
|
114 (shell-mode . ("1" "8"))
|
|
115 (cmushell-mode . ("1" "8"))
|
|
116 (text-mode . "1")
|
|
117 )
|
|
118 "*Association list of major modes and their default section numbers.
|
|
119 List is of the form: (MAJOR-MODE . [SECTION | (SECTION*)]). If current
|
|
120 major mode is not in list, then the default is to check for manpages
|
|
121 in all sections.")
|
|
122
|
|
123 (defvar Man-section-translations-alist
|
|
124 '(("3C++" . "3")
|
|
125 ("1-UCB" . ""))
|
|
126 "*Association list of bogus sections to real section numbers.
|
|
127 Some manpages (e.g. the Sun C++ 2.1 manpages) have section numbers in
|
|
128 their references which Un*x man(1) does not recognize. This
|
|
129 assocation list is used to translate those sections, when found, to
|
|
130 the associated section number.")
|
|
131
|
|
132 (defvar Man-filter-list
|
|
133 '(("sed "
|
|
134 ("-e 's/.\010//g'"
|
|
135 "-e '/[Nn]o such file or directory/d'"
|
|
136 "-e '/Reformatting page. Wait... done/d'"
|
|
137 "-e '/^\\([A-Z][A-Z.]*([0-9A-Za-z][-0-9A-Za-z+]*)\\).*\\1$/d'"
|
|
138 "-e '/^[ \\t]*Hewlett-Packard Company[ \\t]*- [0-9]* -.*$/d'"
|
|
139 "-e '/^[ \\t]*Hewlett-Packard[ \\t]*- [0-9]* -.*$/d'"
|
|
140 "-e '/^ *Page [0-9]*.*(printed [0-9\\/]*)$/d'"
|
|
141 "-e '/^Printed [0-9].*[0-9]$/d'"
|
|
142 "-e '/^Sun Microsystems.*Last change:/d'"
|
|
143 "-e '/^Sun Release [0-9].*[0-9]$/d'"
|
|
144 "-e '/^\\n$/D'"
|
|
145 ))
|
|
146 ("awk '"
|
|
147 ("BEGIN { blankline=0; anonblank=0; }"
|
|
148 "/^$/ { if (anonblank==0) next; }"
|
|
149 "{ anonblank=1; }"
|
|
150 "/^$/ { blankline++; next; }"
|
|
151 "{ if (blankline>0) { print \"\"; blankline=0; } print $0; }"
|
|
152 "'"
|
|
153 ))
|
|
154 )
|
|
155 "*Manpage cleaning filter command phrases.
|
|
156 This variable contains an association list of the following form:
|
|
157
|
|
158 '((command-string (phrase-string*))*)
|
|
159
|
|
160 Each phrase-string is concatenated onto the command-string to form a
|
|
161 command filter. The (standard) output (and standard error) of the Un*x
|
|
162 man command is piped through each command filter in the order the
|
|
163 commands appear in the association list. The final output is placed in
|
|
164 the manpage buffer.")
|
|
165
|
|
166 (defvar Man-mode-line-format
|
|
167 '("" mode-line-modified
|
|
168 mode-line-buffer-identification " "
|
|
169 global-mode-string
|
|
170 Man-page-mode-string
|
|
171 " %[(" mode-name minor-mode-alist mode-line-process ")%]----"
|
|
172 (-3 . "%p") "-%-")
|
|
173 "*Mode line format for manual mode buffer.")
|
|
174
|
|
175 (defvar Man-mode-map nil
|
|
176 "*Keymap for Man-mode.")
|
|
177
|
|
178 (defvar Man-mode-hooks nil
|
|
179 "*Hooks for Man-mode.")
|
|
180
|
|
181 (defvar Man-section-regexp "[0-9][a-zA-Z+]*"
|
|
182 "*Regular expression describing a manpage section within parentheses.")
|
|
183
|
|
184 (defvar Man-heading-regexp "^[A-Z]"
|
|
185 "*Regular expression describing a manpage heading entry.")
|
|
186
|
|
187 (defvar Man-see-also-regexp "SEE ALSO"
|
|
188 "*Regular expression for SEE ALSO heading (or your equivalent).
|
|
189 This regexp should not start with a `^' character.")
|
|
190
|
|
191 (defvar Man-first-heading-regexp "^NAME$\\|^No manual entry for .*$"
|
|
192 "*Regular expression describing first heading on a manpage.
|
|
193 This regular expression should start with a `^' character.")
|
|
194
|
|
195 (defvar Man-reference-regexp "[-a-zA-Z0-9_.]+\\(([0-9][a-zA-Z+]*)\\)?"
|
|
196 "*Regular expression describing a reference in the SEE ALSO section.")
|
|
197
|
|
198
|
|
199 ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
200 ;; end user variables
|
|
201
|
|
202 (defconst Man-version-number "1.1"
|
|
203 "man's version number.")
|
|
204
|
|
205
|
|
206 ;; other variables and keymap initializations
|
|
207 (make-variable-buffer-local 'Man-sections-alist)
|
|
208 (make-variable-buffer-local 'Man-refpages-alist)
|
|
209 (make-variable-buffer-local 'Man-page-list)
|
|
210 (make-variable-buffer-local 'Man-current-page)
|
|
211 (make-variable-buffer-local 'Man-page-mode-string)
|
|
212
|
|
213 (setq-default Man-sections-alist nil)
|
|
214 (setq-default Man-refpages-alist nil)
|
|
215 (setq-default Man-page-list nil)
|
|
216 (setq-default Man-current-page 0)
|
|
217 (setq-default Man-page-mode-string "1 (of 1)")
|
|
218
|
|
219 (if Man-mode-map
|
|
220 nil
|
|
221 (setq Man-mode-map (make-keymap))
|
|
222 (suppress-keymap Man-mode-map)
|
|
223 (define-key Man-mode-map " " 'scroll-up)
|
|
224 (define-key Man-mode-map "\177" 'scroll-down)
|
|
225 (define-key Man-mode-map "n" 'Man-next-section)
|
|
226 (define-key Man-mode-map "p" 'Man-previous-section)
|
|
227 (define-key Man-mode-map "\en" 'Man-next-manpage)
|
|
228 (define-key Man-mode-map "\ep" 'Man-previous-manpage)
|
|
229 (define-key Man-mode-map "," 'beginning-of-buffer)
|
|
230 (define-key Man-mode-map "." 'end-of-buffer)
|
|
231 (define-key Man-mode-map "r" 'Man-follow-manual-reference)
|
|
232 (define-key Man-mode-map "t" 'toggle-truncate-lines)
|
|
233 (define-key Man-mode-map "g" 'Man-goto-section)
|
|
234 (define-key Man-mode-map "s" 'Man-goto-see-also-section)
|
|
235 (define-key Man-mode-map "q" 'Man-quit)
|
|
236 (define-key Man-mode-map "m" 'manual-entry)
|
|
237 (define-key Man-mode-map "v" 'Man-version)
|
|
238 (define-key Man-mode-map "?" 'describe-mode)
|
|
239 )
|
|
240
|
|
241
|
|
242 ;; ======================================================================
|
|
243 ;; utilities
|
|
244
|
|
245 (defun Man-page-mode-string ()
|
|
246 "Formats part of the mode line for manual mode."
|
|
247 (format "%d (of %d)" Man-current-page (length Man-page-list)))
|
|
248
|
|
249 (defun Man-delete-trailing-newline (str)
|
|
250 (if (string= (substring str (1- (length str))) "\n")
|
|
251 (substring str 0 (1- (length str)))
|
|
252 str))
|
|
253
|
|
254 (defun Man-build-man-command ()
|
|
255 "Builds the entire background manpage and cleaning command."
|
|
256 (let ((command "man %s 2>&1 | ")
|
|
257 (flist Man-filter-list))
|
|
258 (while flist
|
|
259 (let ((pcom (car (car flist)))
|
|
260 (pargs (car (cdr (car flist)))))
|
|
261 (setq flist (cdr flist))
|
|
262 (if (or (not (stringp pcom))
|
|
263 (not (listp pargs)))
|
|
264 (error "malformed Man-filter-list."))
|
|
265 (setq command (concat command pcom
|
|
266 (mapconcat '(lambda (phrase) phrase)
|
|
267 pargs " "))))
|
|
268 (if flist
|
|
269 (setq command (concat command " | " ))))
|
|
270 command))
|
|
271
|
|
272 (defun Man-downcase (man-args)
|
|
273 "Downcases section letters in MAN-ARGS."
|
|
274 (let ((newargs "")
|
|
275 (s 0)
|
|
276 mstart mend
|
|
277 (len (length man-args)))
|
|
278 (while (and (< s len)
|
|
279 (setq mstart (string-match Man-section-regexp man-args s)))
|
|
280 (setq mend (match-end 0)
|
|
281 newargs (concat newargs (substring man-args s mstart)))
|
|
282 (setq newargs (concat newargs (downcase
|
|
283 (substring man-args mstart mend)))
|
|
284 s mend))
|
|
285 (concat newargs (substring man-args s len))))
|
|
286
|
|
287 (defun Man-translate-references (ref)
|
|
288 "Translates REF from \"chmod(2V)\" to \"2v chmod\" style."
|
|
289 (if (string-match (concat "(" Man-section-regexp ")$") ref)
|
|
290 (let* ((word (progn (string-match "(" ref)
|
|
291 (substring ref 0 (1- (match-end 0)))))
|
|
292 (section-re (concat "(\\(" Man-section-regexp "\\))"))
|
|
293 (section (if (string-match section-re ref)
|
|
294 (substring ref (match-beginning 1) (match-end 1))
|
|
295 ""))
|
|
296 (slist Man-section-translations-alist)
|
|
297 )
|
|
298 (if Man-downcase-section-letters-p
|
|
299 (setq section (Man-downcase section)))
|
|
300 (while slist
|
|
301 (let ((s1 (car (car slist)))
|
|
302 (s2 (cdr (car slist))))
|
|
303 (setq slist (cdr slist))
|
|
304 (if Man-downcase-section-letters-p
|
|
305 (setq s1 (Man-downcase s1)))
|
|
306 (if (not (string= s1 section)) nil
|
|
307 (setq section (if Man-downcase-section-letters-p
|
|
308 (Man-downcase s2)
|
|
309 s2)
|
|
310 slist nil))))
|
|
311 (concat section " " word))
|
|
312 ref))
|
|
313
|
|
314 (defun Man-linepos (&optional position col-p)
|
|
315 "Return the character position at various line/buffer positions.
|
|
316 Preserves the state of point, mark, etc. Optional POSITION can be one
|
|
317 of the following symbols:
|
|
318 bol == beginning of line
|
|
319 boi == beginning of indentation
|
|
320 eol == end of line [default]
|
|
321 bob == beginning of buffer
|
|
322 eob == end of buffer
|
|
323
|
|
324 Optional COL-P non-nil returns current-column instead of character position."
|
|
325 (let ((tpnt (point))
|
|
326 rval)
|
|
327 (cond
|
|
328 ((eq position 'bol) (beginning-of-line))
|
|
329 ((eq position 'boi) (back-to-indentation))
|
|
330 ((eq position 'bob) (goto-char (point-min)))
|
|
331 ((eq position 'eob) (goto-char (point-max)))
|
|
332 (t (end-of-line)))
|
|
333 (setq rval (if col-p (current-column) (point)))
|
|
334 (goto-char tpnt)
|
|
335 rval))
|
|
336
|
|
337
|
|
338 ;; ======================================================================
|
|
339 ;; default man entry and get word under point
|
|
340
|
|
341 (defun Man-default-man-args (manword)
|
|
342 "Build the default man args from MANWORD and major-mode."
|
|
343 (let ((mode major-mode)
|
|
344 (slist Man-auto-section-alist))
|
|
345 (while (and slist
|
|
346 (not (eq (car (car slist)) mode)))
|
|
347 (setq slist (cdr slist)))
|
|
348 (if (not slist)
|
|
349 manword
|
|
350 (let ((sections (cdr (car slist))))
|
|
351 (if (not (listp sections))
|
|
352 (concat sections " " manword)
|
|
353 (let ((manarg ""))
|
|
354 (while sections
|
|
355 (setq manarg (concat manarg " " (car sections) " " manword))
|
|
356 (setq sections (cdr sections)))
|
|
357 manarg)
|
|
358 )))))
|
|
359
|
|
360 (defun Man-default-man-entry ()
|
|
361 "Make a guess at a default manual entry.
|
|
362 This guess is based on the text surrounding the cursor, and the
|
|
363 default section number is selected from Man-auto-section-alist."
|
|
364 (let ((default-section nil)
|
|
365 default-title)
|
|
366 (save-excursion
|
|
367
|
|
368 ;; Default man entry title is any word the cursor is on,
|
|
369 ;; or if cursor not on a word, then nearest preceding
|
|
370 ;; word.
|
|
371 (and (not (looking-at "[a-zA-Z_]"))
|
|
372 (skip-chars-backward "^a-zA-Z_"))
|
|
373 (skip-chars-backward "(a-zA-Z_0-9")
|
|
374 (and (looking-at "(") (forward-char 1))
|
|
375 (setq default-title
|
|
376 (buffer-substring
|
|
377 (point)
|
|
378 (progn (skip-chars-forward "a-zA-Z0-9_") (point))))
|
|
379
|
|
380 ;; If looking at something like ioctl(2) or brc(1M), include
|
|
381 ;; section number in default-entry
|
|
382 (if (looking-at "[ \t]*([ \t]*[0-9][a-zA-Z]?[ \t]*)")
|
|
383 (progn (skip-chars-forward "^0-9")
|
|
384 (setq default-section
|
|
385 (buffer-substring
|
|
386 (point)
|
|
387 (progn
|
|
388 (skip-chars-forward "0-9a-zA-Z")
|
|
389 (point)))))
|
|
390
|
|
391 ;; Otherwise, assume section number to be 2 if we're
|
|
392 ;; in C code
|
|
393 (and (eq major-mode 'c-mode)
|
|
394 (setq default-section "2")))
|
|
395 (if default-section
|
|
396 (format "%s %s" default-section default-title)
|
|
397 default-title))))
|
|
398
|
|
399
|
|
400 ;; ======================================================================
|
|
401 ;; top level command and background process sentinel
|
|
402
|
|
403 ;;;###autoload
|
|
404 (defun manual-entry (arg)
|
|
405 "Get a Un*x manual page and put it in a buffer.
|
|
406 This command is the top-level command in the man package. It runs a Un*x
|
|
407 command to retrieve and clean a manpage in the background and places the
|
|
408 results in a Man-mode (manpage browsing) buffer. See variable
|
|
409 Man-notify for what happens when the buffer is ready.
|
|
410 Universal argument ARG, is passed to Man-getpage-in-background."
|
|
411 (interactive "P")
|
|
412 (let* ((default-entry (Man-default-man-entry))
|
|
413 (man-args
|
|
414 (read-string (format "Manual-entry: %s"
|
|
415 (if (string= default-entry "") ""
|
|
416 (format "(default: %s) "
|
|
417 default-entry))))))
|
|
418 (and (string= man-args "")
|
|
419 (if (string= default-entry "")
|
|
420 (error "No man args given.")
|
|
421 (setq man-args default-entry)))
|
|
422 (if Man-downcase-section-letters-p
|
|
423 (setq man-args (Man-downcase man-args)))
|
|
424 (Man-getpage-in-background man-args (consp arg))
|
|
425 ))
|
|
426
|
|
427 (defun Man-getpage-in-background (man-args &optional override-reuse-p)
|
|
428 "Uses MAN-ARGS to build and fire off the manpage and cleaning command.
|
|
429 Optional OVERRIDE-REUSE-P, when supplied non-nil forces man to
|
|
430 start a background process even if a buffer already exists and
|
|
431 Man-reuse-okay-p is non-nil."
|
|
432 (let* ((bufname (concat "*man " man-args "*"))
|
|
433 (buffer (get-buffer bufname)))
|
|
434 (if (and Man-reuse-okay-p
|
|
435 (not override-reuse-p)
|
|
436 buffer)
|
|
437 (Man-notify-when-ready buffer)
|
|
438 (message "Invoking man %s in background..." man-args)
|
|
439 (setq buffer (generate-new-buffer bufname))
|
|
440 (set-process-sentinel
|
|
441 (start-process "man" buffer "sh" "-c"
|
|
442 (format (Man-build-man-command) man-args))
|
|
443 'Man-bgproc-sentinel))
|
|
444 ))
|
|
445
|
|
446 (defun Man-notify-when-ready (man-buffer)
|
|
447 "Notify the user when MAN-BUFFER is ready.
|
|
448 See the variable Man-notify for the different notification behaviors."
|
|
449 (cond
|
|
450 ((eq man-notify 'bully)
|
|
451 (pop-to-buffer man-buffer)
|
|
452 (delete-other-windows))
|
|
453 ((eq man-notify 'aggressive)
|
|
454 (pop-to-buffer man-buffer))
|
|
455 ((eq man-notify 'friendly)
|
|
456 (display-buffer man-buffer 'not-this-window))
|
|
457 ((eq man-notify 'polite)
|
|
458 (beep)
|
|
459 (message "Manual buffer %s is ready." (buffer-name man-buffer)))
|
|
460 ((eq man-notify 'quiet)
|
|
461 (message "Manual buffer %s is ready." (buffer-name man-buffer)))
|
|
462 ((or (eq man-notify 'meek)
|
|
463 t)
|
|
464 (message ""))
|
|
465 ))
|
|
466
|
|
467 (defun Man-bgproc-sentinel (process msg)
|
|
468 "Manpage background process sentinel."
|
|
469 (let ((Man-buffer (process-buffer process))
|
|
470 (delete-buff nil)
|
|
471 (err-mess nil))
|
|
472 (if (null (buffer-name Man-buffer)) ;; deleted buffer
|
|
473 (set-process-buffer process nil)
|
|
474 (save-excursion
|
|
475 (set-buffer Man-buffer)
|
|
476 (goto-char (point-min))
|
|
477 (cond ((or (looking-at "No \\(manual \\)*entry for")
|
|
478 (looking-at "[^\n]*: nothing appropriate$"))
|
|
479 (setq err-mess (buffer-substring (point) (Man-linepos 'eol))
|
|
480 delete-buff t)
|
|
481 )
|
|
482 ((not (and (eq (process-status process) 'exit)
|
|
483 (= (process-exit-status process) 0)))
|
|
484 (setq err-mess
|
|
485 (concat (buffer-name Man-buffer)
|
|
486 ": process "
|
|
487 (let ((eos (1- (length msg))))
|
|
488 (if (= (aref msg eos) ?\n)
|
|
489 (substring msg 0 eos) msg))))
|
|
490 (goto-char (point-max))
|
|
491 (insert (format "\nprocess %s" msg))
|
|
492 )))
|
|
493 (if delete-buff
|
|
494 (kill-buffer Man-buffer)
|
|
495 (save-window-excursion
|
|
496 (save-excursion
|
|
497 (set-buffer Man-buffer)
|
|
498 (Man-mode)
|
|
499 (set-buffer-modified-p nil)))
|
|
500 (Man-notify-when-ready Man-buffer))
|
|
501
|
|
502 (if err-mess
|
|
503 (error err-mess))
|
|
504 )))
|
|
505
|
|
506
|
|
507 ;; ======================================================================
|
|
508 ;; set up manual mode in buffer and build alists
|
|
509
|
|
510 (defun Man-mode ()
|
|
511 "SUPERMAN 1.1: A mode for browsing Un*x manual pages.
|
|
512
|
|
513 The following man commands are available in the buffer. Try
|
|
514 \"\\[describe-key] <key> RET\" for more information:
|
|
515
|
|
516 \\[manual-entry] Prompt to retrieve a new manpage.
|
|
517 \\[Man-follow-manual-reference] Retrieve reference in SEE ALSO section.
|
|
518 \\[Man-next-manpage] Jump to next manpage in circular list.
|
|
519 \\[Man-previous-manpage] Jump to previous manpage in circular list.
|
|
520 \\[Man-next-section] Jump to next manpage section.
|
|
521 \\[Man-previous-section] Jump to previous manpage section.
|
|
522 \\[Man-goto-section] Go to a manpage section.
|
|
523 \\[Man-goto-see-also-section] Jumps to the SEE ALSO manpage section.
|
|
524 \\[Man-quit] Deletes the manpage, its buffer, and window.
|
|
525 \\[Man-version] Prints man's version number.
|
|
526 \\[describe-mode] Prints this help text.
|
|
527
|
|
528 The following variables may be of some use. Try
|
|
529 \"\\[describe-variable] <variable-name> RET\" for more information:
|
|
530
|
|
531 Man-notify What happens when manpage formatting is done.
|
|
532 Man-reuse-okay-p Okay to reuse already formatted buffer?
|
|
533 Man-downcase-section-letters-p Force section letters to lower case?
|
|
534 Man-circular-pages-p Multiple manpage list treated as circular?
|
|
535 Man-auto-section-alist List of major modes and their section numbers.
|
|
536 Man-section-translations-alist List of section numbers and their Un*x equiv.
|
|
537 Man-filter-list Background manpage filter command.
|
|
538 Man-mode-line-format Mode line format for Man-mode buffers.
|
|
539 Man-mode-map Keymap bindings for Man-mode buffers.
|
|
540 Man-mode-hooks Hooks for Man-mode.
|
|
541 Man-section-regexp Regexp describing manpage section letters.
|
|
542 Man-heading-regexp Regexp describing section headers.
|
|
543 Man-see-also-regexp Regexp for SEE ALSO section (or your equiv).
|
|
544 Man-first-heading-regexp Regexp for first heading on a manpage.
|
|
545 Man-reference-regexp Regexp matching a references in SEE ALSO.
|
|
546 Man-version-number Superman version number.
|
|
547
|
|
548 The following key bindings are currently in effect in the buffer:
|
|
549 \\{Man-mode-map}"
|
|
550 (interactive)
|
|
551 (setq major-mode 'Man-mode
|
|
552 mode-name "Manual"
|
|
553 buffer-auto-save-file-name nil
|
|
554 mode-line-format Man-mode-line-format
|
|
555 truncate-lines t
|
|
556 buffer-read-only t)
|
|
557 (buffer-disable-undo (current-buffer))
|
|
558 (auto-fill-mode -1)
|
|
559 (use-local-map Man-mode-map)
|
|
560 (goto-char (point-min))
|
|
561 (Man-build-page-list)
|
|
562 (Man-goto-page 1))
|
|
563
|
|
564 (defun Man-build-section-alist ()
|
|
565 "Build the association list of manpage sections."
|
|
566 (setq Man-sections-alist nil)
|
|
567 (goto-char (point-min))
|
|
568 (while (re-search-forward Man-heading-regexp (point-max) t)
|
|
569 (aput 'Man-sections-alist
|
|
570 (buffer-substring (Man-linepos 'bol) (Man-linepos)))
|
|
571 (forward-line 1)
|
|
572 ))
|
|
573
|
|
574 (defun Man-build-references-alist ()
|
|
575 "Build the association list of references (in the SEE ALSO section)."
|
|
576 (setq Man-refpages-alist nil)
|
|
577 (save-excursion
|
|
578 (if (Man-find-section Man-see-also-regexp)
|
|
579 (let ((start (progn (forward-line 1) (point)))
|
|
580 (end (progn
|
|
581 (Man-next-section 1)
|
|
582 (point)))
|
|
583 hyphenated
|
|
584 (runningpoint -1))
|
|
585 (narrow-to-region start end)
|
|
586 (goto-char (point-min))
|
|
587 (back-to-indentation)
|
|
588 (while (and (not (eobp)) (/= (point) runningpoint))
|
|
589 (setq runningpoint (point))
|
|
590 (let* ((bow (point))
|
|
591 (eow (re-search-forward Man-reference-regexp end t))
|
|
592 (word (buffer-substring bow (match-end 0)))
|
|
593 (len (1- (length word))))
|
|
594 (if (not eow) nil
|
|
595 (if hyphenated
|
|
596 (setq word (concat hyphenated word)
|
|
597 hyphenated nil))
|
|
598 (if (= (aref word len) ?-)
|
|
599 (setq hyphenated (substring word 0 len))
|
|
600 (aput 'Man-refpages-alist word))))
|
|
601 (skip-chars-forward " \t\n,"))
|
|
602 ))))
|
|
603
|
|
604 (defun Man-build-page-list ()
|
|
605 "Build the list of separate manpages in the buffer."
|
|
606 (setq Man-page-list nil)
|
|
607 (save-excursion
|
|
608 (let ((page-start (Man-linepos 'bob))
|
|
609 (page-end (Man-linepos 'eob))
|
|
610 (regexp Man-first-heading-regexp))
|
|
611 (goto-char (point-min))
|
|
612 (re-search-forward regexp (point-max) t)
|
|
613 (while (not (eobp))
|
|
614 (if (re-search-forward regexp (point-max) t)
|
|
615 (progn
|
|
616 (setq page-end (Man-linepos 'bol))
|
|
617 (end-of-line))
|
|
618 (goto-char (point-max))
|
|
619 (setq page-end (point)))
|
|
620 (setq Man-page-list (append Man-page-list
|
|
621 (list (cons page-start page-end)))
|
|
622 page-start page-end)
|
|
623 ))))
|
|
624
|
|
625
|
|
626 ;; ======================================================================
|
|
627 ;; Man-mode commands
|
|
628
|
|
629 (defun Man-next-section (n)
|
|
630 "Move point to Nth next section (default 1)."
|
|
631 (interactive "p")
|
|
632 (if (looking-at Man-heading-regexp)
|
|
633 (forward-line 1))
|
|
634 (if (re-search-forward Man-heading-regexp (point-max) t n)
|
|
635 (beginning-of-line)
|
|
636 (goto-char (point-max))))
|
|
637
|
|
638 (defun Man-previous-section (n)
|
|
639 "Move point to Nth previous section (default 1)."
|
|
640 (interactive "p")
|
|
641 (if (looking-at Man-heading-regexp)
|
|
642 (forward-line -1))
|
|
643 (if (re-search-backward Man-heading-regexp (point-min) t n)
|
|
644 (beginning-of-line)
|
|
645 (goto-char (point-min))))
|
|
646
|
|
647 (defun Man-find-section (section)
|
|
648 "Move point to SECTION if it exists, otherwise don't move point.
|
|
649 Returns t if section is found, nil otherwise."
|
|
650 (let ((curpos (point)))
|
|
651 (goto-char (point-min))
|
|
652 (if (re-search-forward (concat "^" section) (point-max) t)
|
|
653 (progn (beginning-of-line) t)
|
|
654 (goto-char curpos)
|
|
655 nil)
|
|
656 ))
|
|
657
|
|
658 (defun Man-goto-section ()
|
|
659 "Query for section to move point to."
|
|
660 (interactive)
|
|
661 (aput 'Man-sections-alist
|
|
662 (let* ((default (aheadsym Man-sections-alist))
|
|
663 (completion-ignore-case t)
|
|
664 chosen
|
|
665 (prompt (concat "Go to section: (default " default ") ")))
|
|
666 (setq chosen (completing-read prompt Man-sections-alist))
|
|
667 (if (or (not chosen)
|
|
668 (string= chosen ""))
|
|
669 default
|
|
670 chosen)))
|
|
671 (Man-find-section (aheadsym Man-sections-alist)))
|
|
672
|
|
673 (defun Man-goto-see-also-section ()
|
|
674 "Move point the the \"SEE ALSO\" section.
|
|
675 Actually the section moved to is described by Man-see-also-regexp."
|
|
676 (interactive)
|
|
677 (if (not (Man-find-section Man-see-also-regexp))
|
|
678 (error (concat "No " Man-see-also-regexp
|
|
679 " section found in current manpage."))))
|
|
680
|
|
681 (defun Man-follow-manual-reference (arg)
|
|
682 "Get one of the manpages referred to in the \"SEE ALSO\" section.
|
|
683 Queries you for the page to retrieve. Of course it does this in the
|
|
684 background. Universal argument ARG is passed to Man-getpage-in-background."
|
|
685 (interactive "P")
|
|
686 (if (not Man-refpages-alist)
|
|
687 (error (concat "No references found in current manpage."))
|
|
688 (aput 'Man-refpages-alist
|
|
689 (let* ((default (aheadsym Man-refpages-alist))
|
|
690 chosen
|
|
691 (prompt (concat "Refer to: (default " default ") ")))
|
|
692 (setq chosen (completing-read prompt Man-refpages-alist nil t))
|
|
693 (if (or (not chosen)
|
|
694 (string= chosen ""))
|
|
695 default
|
|
696 chosen)))
|
|
697 (Man-getpage-in-background
|
|
698 (Man-translate-references (aheadsym Man-refpages-alist))
|
|
699 (consp arg))))
|
|
700
|
|
701 (defun Man-quit ()
|
|
702 "Kill the buffer containing the manpage."
|
|
703 (interactive)
|
|
704 (let ((buff (current-buffer)))
|
|
705 (delete-windows-on buff)
|
|
706 (kill-buffer buff)))
|
|
707
|
|
708 (defun Man-goto-page (page)
|
|
709 "Go to the manual page on page PAGE."
|
|
710 (interactive
|
|
711 (if (not Man-page-list)
|
|
712 (error "You're looking at the only manpage in the buffer.")
|
|
713 (format "nGo to manpage [1-%d]: " (length Man-page-list))))
|
|
714 (if (or (< page 1)
|
|
715 (> page (length Man-page-list)))
|
|
716 (error "No manpage %d found" page))
|
|
717 (let* ((page-range (nth (1- page) Man-page-list))
|
|
718 (page-start (car page-range))
|
|
719 (page-end (cdr page-range)))
|
|
720 (setq Man-current-page page
|
|
721 Man-page-mode-string (Man-page-mode-string))
|
|
722 (widen)
|
|
723 (goto-char page-start)
|
|
724 (narrow-to-region page-start page-end)
|
|
725 (Man-build-section-alist)
|
|
726 (Man-build-references-alist)
|
|
727 (widen)
|
|
728 (narrow-to-region page-start page-end)
|
|
729 (goto-char (point-min))))
|
|
730
|
|
731
|
|
732 (defun Man-next-manpage ()
|
|
733 "Find the next manpage entry in the buffer."
|
|
734 (interactive)
|
|
735 (if (= (length Man-page-list) 1)
|
|
736 (error "This is the only manpage in the buffer."))
|
|
737 (if (< Man-current-page (length Man-page-list))
|
|
738 (Man-goto-page (1+ Man-current-page))
|
|
739 (if Man-circular-pages-p
|
|
740 (Man-goto-page 1)
|
|
741 (error "You're looking at the last manpage in the buffer."))))
|
|
742
|
|
743 (defun Man-previous-manpage ()
|
|
744 "Find the previous manpage entry in the buffer."
|
|
745 (interactive)
|
|
746 (if (= (length Man-page-list) 1)
|
|
747 (error "This is the only manpage in the buffer."))
|
|
748 (if (> Man-current-page 1)
|
|
749 (Man-goto-page (1- Man-current-page))
|
|
750 (if Man-circular-pages-p
|
|
751 (Man-goto-page (length Man-page-list))
|
|
752 (error "You're looking at the first manpage in the buffer."))))
|
|
753
|
|
754 (defun Man-version (arg)
|
|
755 "Show man's version.
|
|
756 Universal argument (\\[universal-argument]) ARG inserts version
|
|
757 information in the current buffer instead of printing the message in
|
|
758 the echo area."
|
|
759 (interactive "P")
|
|
760 (if (consp arg)
|
|
761 (insert "Using Superman version " Man-version-number ".")
|
|
762 (message "Using Superman version %s." Man-version-number)))
|
|
763
|
|
764 ;;; man.el ends here
|