Mercurial > hg > xemacs-beta
comparison lisp/packages/hyper-apropos.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; hyper-apropos.el --- Hypertext emacs lisp documentation interface. | |
2 | |
3 ;; Copyright (C) 1994, 1995 Tinker Systems and INS Engineering Corp. | |
4 ;; Copyright (C) 1995 Sun Microsystems. | |
5 ;; Copyright (C) 1996 Ben Wing. | |
6 | |
7 ;; Maintainer: Jonathan Stigelman <Stig@hackvan.com> | |
8 ;; Keywords: lisp, tools, help, docs, matching | |
9 | |
10 ;; This file is part of XEmacs. | |
11 | |
12 ;; XEmacs is free software; you can redistribute it and/or modify | |
13 ;; it under the terms of the GNU General Public License as published by | |
14 ;; the Free Software Foundation; either version 2 of the License, or | |
15 ;; (at your option) any later version. | |
16 ;; | |
17 ;; XEmacs is distributed in the hope that it will be useful, | |
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 ;; GNU General Public License for more details. | |
21 ;; | |
22 ;; You should have received a copy of the GNU General Public License | |
23 ;; along with XEmacs; if not, write to the Free Software | |
24 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | |
26 ;;; Synched up with: Not in FSF. | |
27 | |
28 ;;; Commentary: | |
29 | |
30 ;; based upon emacs-apropos.el by Frank C. Guida <fcg@philabs.philips.com> | |
31 ;; | |
32 ;; Rather than run apropos and print all the documentation at once, | |
33 ;; I find it easier to view a "table of contents" first, then | |
34 ;; get the details for symbols as you need them. | |
35 ;; | |
36 ;; This version of apropos prints two lists of symbols matching the | |
37 ;; given regexp: functions/macros and variables/constants. | |
38 ;; | |
39 ;; The user can then do the following: | |
40 ;; | |
41 ;; - add an additional regexp to narrow the search | |
42 ;; - display documentation for the current symbol | |
43 ;; - find the tag for the current symbol | |
44 ;; - show any keybindings if the current symbol is a command | |
45 ;; - invoke functions | |
46 ;; - set variables | |
47 ;; | |
48 ;; An additional feature is the ability to search the current tags | |
49 ;; table, allowing you to interrogate functions not yet loaded (this | |
50 ;; isn't available with the standard package). | |
51 ;; | |
52 ;; Mouse bindings and menus are provided for XEmacs. | |
53 ;; | |
54 ;; additions by Ben Wing <wing@666.com> July 1995: | |
55 ;; added support for function aliases, made programmer's apropos be the | |
56 ;; default, various other hacking. | |
57 | |
58 ;;; Code: | |
59 | |
60 (or (fboundp 'pprint) | |
61 (progn (autoload 'pp "pp") | |
62 (fset 'pprint 'pp))) | |
63 ;;(require 'tags "etags") | |
64 | |
65 ;;;###autoload | |
66 (defvar hypropos-show-brief-docs t | |
67 "*If non-nil, `hyper-apropos' will display some documentation in the | |
68 \"*Hyper Apropos*\" buffer. Setting this to nil will speed up searches.") | |
69 | |
70 (defvar hypropos-prettyprint-long-values t | |
71 "*If non-nil, then try to beautify the printing of very long values.") | |
72 | |
73 ;; I changed this to true because I think it's more useful this way. --ben | |
74 | |
75 (defvar hypropos-programming-apropos t | |
76 "*If non-nil, then `hyper-apropos' takes a bit longer and generates more | |
77 output. If nil, then only functions that are interactive and variables that | |
78 are user variables are found by `hyper-apropos'.") | |
79 | |
80 (defvar hypropos-prev-wconfig) | |
81 | |
82 ;; #### - move this to subr.el | |
83 (or (fboundp 'event-buffer) | |
84 (defun event-buffer (event) | |
85 "Returns the buffer associated with event, or nil." | |
86 (let ((win (event-window event))) | |
87 (and win (window-buffer win))))) | |
88 | |
89 (defmacro eval-in-buffer (buffer &rest forms) | |
90 "Evaluate FORMS in BUFFER." | |
91 (` (let ((_unwind_buf_ (current-buffer))) | |
92 (unwind-protect | |
93 (progn (set-buffer (, buffer)) | |
94 (,@ forms)) | |
95 (set-buffer _unwind_buf_))))) | |
96 (put 'eval-in-buffer 'lisp-indent-function 'defun) | |
97 | |
98 ;; #### - move to faces.el | |
99 (defmacro init-face (face &rest init-forms) | |
100 "Make a FACE if it doesn't already exist. Then if it does not differ from | |
101 the default face, execute INIT-FORMS to initialize the face. While the | |
102 init-forms are executing, the symbol `this' is bound to the face-object | |
103 being initialized." | |
104 (` (let ((this (make-face (, face)))) ; harmless if the face is already there | |
105 (or (face-differs-from-default-p this) | |
106 (, (cons 'progn init-forms)))))) | |
107 (put 'init-face 'lisp-indent-function 'defun) | |
108 | |
109 (init-face 'hyperlink | |
110 (copy-face 'bold this) | |
111 ;;(set-face-underline-p this nil) -- dog slow and ugly | |
112 (condition-case nil | |
113 (set-face-foreground this "blue") | |
114 (error nil))) | |
115 (init-face 'documentation | |
116 (let* ((ff-instance (face-font-instance 'default)) | |
117 (ff (and ff-instance (font-instance-name ff-instance)))) | |
118 (cond ((and ff (string-match "courier" ff)) | |
119 ;; too wide unless you shrink it | |
120 ;; (copy-face 'italic this) fugly. | |
121 ;; (make-face-smaller this) fugly. | |
122 )) | |
123 (condition-case nil | |
124 (set-face-foreground this "firebrick") | |
125 (error (copy-face 'italic this))))) | |
126 | |
127 ;; mucking with the sizes of fonts (perhaps with the exception of courier or | |
128 ;; misc) is a generally losing thing to do. Changing the size of 'clean' | |
129 ;; really loses, for instance... | |
130 | |
131 (init-face 'major-heading | |
132 (copy-face 'bold this) | |
133 (make-face-larger this) | |
134 (make-face-larger this)) | |
135 (init-face 'section-heading | |
136 (copy-face 'bold this) | |
137 (make-face-larger this)) | |
138 (init-face 'heading | |
139 (copy-face 'bold this)) | |
140 (init-face 'standout | |
141 (copy-face 'italic this)) | |
142 | |
143 (init-face 'warning | |
144 (copy-face 'bold this) | |
145 (and (eq (device-type) 'x) | |
146 (eq (device-class) 'color) | |
147 (set-face-foreground this "red"))) | |
148 | |
149 (defvar hypropos-help-map (let ((map (make-sparse-keymap))) | |
150 (suppress-keymap map) | |
151 (set-keymap-name map 'hypropos-help-map) | |
152 ;; movement | |
153 (define-key map " " 'scroll-up) | |
154 (define-key map "b" 'scroll-down) | |
155 (define-key map "/" 'isearch-forward) | |
156 (define-key map "?" 'isearch-backward) | |
157 ;; follow links | |
158 (define-key map "\r" 'hypropos-get-doc) | |
159 (define-key map "s" 'hypropos-set-variable) | |
160 (define-key map "t" 'hypropos-find-tag) | |
161 (define-key map "l" 'hypropos-last-help) | |
162 (define-key map [button2] 'hypropos-mouse-get-doc) | |
163 (define-key map [button3] 'hypropos-popup-menu) | |
164 ;; for the totally hardcore... | |
165 (define-key map "D" 'hypropos-disassemble) | |
166 ;; administrativa | |
167 (define-key map "a" 'hyper-apropos) | |
168 (define-key map "n" 'hyper-apropos) | |
169 (define-key map "q" 'hypropos-quit) | |
170 map | |
171 ) | |
172 "Keybindings for both the *Hyper Help* buffer and the *Hyper Apropos* buffer") | |
173 | |
174 (defvar hypropos-map (let ((map (make-sparse-keymap))) | |
175 (set-keymap-name map 'hypropos-map) | |
176 (set-keymap-parents map (list hypropos-help-map)) | |
177 ;; slightly differrent scrolling... | |
178 (define-key map " " 'hypropos-scroll-up) | |
179 (define-key map "b" 'hypropos-scroll-down) | |
180 ;; act on the current line... | |
181 (define-key map "w" 'hypropos-where-is) | |
182 (define-key map "i" 'hypropos-invoke-fn) | |
183 (define-key map "s" 'hypropos-set-variable) | |
184 ;; more administrativa... | |
185 (define-key map "P" 'hypropos-toggle-programming-flag) | |
186 (define-key map "k" 'hypropos-add-keyword) | |
187 (define-key map "e" 'hypropos-eliminate-keyword) | |
188 map | |
189 ) | |
190 "Keybindings for the *Hyper Apropos* buffer. | |
191 This map inherits from `hypropos-help-map.'") | |
192 | |
193 (defvar hyper-apropos-mode-hook nil | |
194 "*User function run after hyper-apropos mode initialization. Usage: | |
195 \(setq hyper-apropos-mode-hook '(lambda () ... your init forms ...)).") | |
196 | |
197 ;; ---------------------------------------------------------------------- ;; | |
198 | |
199 (defconst hypropos-junk-regexp "^Apropos\\|^Functions\\|^Variables\\|^$") | |
200 | |
201 (defvar hypropos-currently-showing nil) ; symbol documented in help buffer now | |
202 (defvar hypropos-help-history nil) ; chain of symbols followed as links in | |
203 ; help buffer | |
204 (defvar hypropos-last-regexp nil) ; regex used for last apropos | |
205 (defconst hypropos-apropos-buf "*Hyper Apropos*") | |
206 (defconst hypropos-help-buf "*Hyper Help*") | |
207 | |
208 ;;;###autoload | |
209 (defun hyper-apropos (regexp toggle-apropos) | |
210 "Display lists of functions and variables matching REGEXP | |
211 in buffer \"*Hyper Apropos*\". If optional prefix arg is given, then the value | |
212 of `hypropos-programming-apropos' is toggled for this search. | |
213 See also `hyper-apropos-mode'." | |
214 (interactive "sList symbols matching regexp: \nP") | |
215 (or (memq major-mode '(hyper-apropos-mode hyper-help-mode)) | |
216 (setq hypropos-prev-wconfig (current-window-configuration))) | |
217 (if (string= "" regexp) | |
218 (if (get-buffer hypropos-apropos-buf) | |
219 (if toggle-apropos | |
220 (hypropos-toggle-programming-flag) | |
221 (message "Using last search results")) | |
222 (error "Be more specific...")) | |
223 (let (flist vlist) | |
224 (set-buffer (get-buffer-create hypropos-apropos-buf)) | |
225 (setq buffer-read-only nil) | |
226 (erase-buffer) | |
227 (if toggle-apropos | |
228 (set (make-local-variable 'hypropos-programming-apropos) | |
229 (not (default-value 'hypropos-programming-apropos)))) | |
230 (if (not hypropos-programming-apropos) | |
231 (setq flist (apropos-internal regexp 'commandp) | |
232 vlist (apropos-internal regexp 'user-variable-p)) | |
233 ;; #### - add obsolete functions/variables here... | |
234 ;; #### - 'variables' may be unbound !!! | |
235 (setq flist (apropos-internal regexp 'fboundp) | |
236 vlist (apropos-internal regexp 'boundp))) | |
237 (insert-face (format "Apropos search for: %S\n\n" regexp) 'major-heading) | |
238 (insert-face "* = command (M-x) or user-variable.\n" 'documentation) | |
239 (insert-face "a = autoloaded, b = byte-compiled, i = internal, l = lambda, m = macro.\n\n" 'documentation) | |
240 (insert-face "Functions and Macros:\n\n" 'major-heading) | |
241 (hypropos-grok-functions flist) | |
242 (insert-face "\n\nVariables and Constants:\n\n" 'major-heading) | |
243 (hypropos-grok-variables vlist) | |
244 (goto-char (point-min)) | |
245 )) | |
246 (switch-to-buffer hypropos-apropos-buf) | |
247 (hyper-apropos-mode regexp)) | |
248 | |
249 (defun hypropos-toggle-programming-flag () | |
250 (interactive) | |
251 (eval-in-buffer hypropos-apropos-buf | |
252 (set (make-local-variable 'hypropos-programming-apropos) | |
253 (not hypropos-programming-apropos))) | |
254 (message "Re-running apropos...") | |
255 (hyper-apropos hypropos-last-regexp nil)) | |
256 | |
257 (defun hypropos-grok-functions (fns) | |
258 (let (fn bind type) | |
259 (while (setq fn (car fns)) | |
260 (setq bind (symbol-function fn) | |
261 type (cond ((subrp bind) ?i) | |
262 ((compiled-function-p bind) ?b) | |
263 ((consp bind) (or (cdr | |
264 (assq (car bind) '((autoload . ?a) | |
265 (lambda . ?l) | |
266 (macro . ?m)))) | |
267 ??)) | |
268 (t ? ))) | |
269 (insert type (if (commandp fn) "* " " ")) | |
270 (insert-face (format "%-30S" fn) 'hyperlink) | |
271 (and hypropos-show-brief-docs | |
272 (if (function-obsolete-p fn) | |
273 (insert-face " - Obsolete." 'documentation) | |
274 (let ((doc (documentation fn))) | |
275 (if (not doc) | |
276 (insert-face " - Not documented." 'documentation) | |
277 (insert-face (concat " - " | |
278 (substring doc 0 | |
279 (string-match "\n" doc))) | |
280 'documentation))))) | |
281 (insert ?\n) | |
282 (setq fns (cdr fns)) | |
283 ))) | |
284 | |
285 (defun hypropos-grok-variables (vars) | |
286 (let (var userp) | |
287 (while (setq var (car vars)) | |
288 (setq userp (user-variable-p var) | |
289 vars (cdr vars)) | |
290 (insert (if userp " * " " ")) | |
291 (insert-face (format "%-30S" var) 'hyperlink) | |
292 (and hypropos-show-brief-docs | |
293 (if (variable-obsolete-p var) | |
294 (insert-face " - Obsolete." 'documentation) | |
295 (let ((doc (documentation-property var 'variable-documentation))) | |
296 (if (not doc) | |
297 (insert-face " - Not documented." 'documentation) | |
298 (insert-face (concat " - " | |
299 (substring doc (if userp 1 0) | |
300 (string-match "\n" doc))) | |
301 'documentation))))) | |
302 (insert ?\n) | |
303 ))) | |
304 | |
305 ;; ---------------------------------------------------------------------- ;; | |
306 | |
307 (defun hyper-apropos-mode (regexp) | |
308 "Improved apropos mode for displaying Emacs documentation. Function and | |
309 variable names are displayed in the buffer \"*Hyper Apropos*\". | |
310 | |
311 Functions are preceded by a single character to indicates their types: | |
312 a = autoloaded, b = byte-compiled, i = internal, l = lambda, m = macro. | |
313 Interactive functions are also preceded by an asterisk. | |
314 Variables are preceded by an asterisk if they are user variables. | |
315 | |
316 General Commands: | |
317 | |
318 SPC - scroll documentation or apropos window forward | |
319 b - scroll documentation or apropos window backward | |
320 k - eliminate all hits that don't contain keyword | |
321 n - new search | |
322 / - isearch-forward | |
323 q - quit and restore previous window configuration | |
324 | |
325 Operations for Symbol on Current Line: | |
326 | |
327 RET - toggle display of symbol's documentation | |
328 (also on button2 in xemacs) | |
329 w - show the keybinding if symbol is a command | |
330 i - invoke function on current line | |
331 s - set value of variable on current line | |
332 t - display the C or lisp source (find-tag)" | |
333 (delete-other-windows) | |
334 (setq mode-name "Hyper-Apropos" | |
335 major-mode 'hyper-apropos-mode | |
336 buffer-read-only t | |
337 truncate-lines t | |
338 hypropos-last-regexp regexp | |
339 modeline-buffer-identification (concat "Hyper Apropos: " | |
340 "\"" regexp "\"")) | |
341 (setq mode-motion-hook 'mode-motion-highlight-line) | |
342 (use-local-map hypropos-map) | |
343 (run-hooks 'hyper-apropos-mode-hook)) | |
344 | |
345 ;; ---------------------------------------------------------------------- ;; | |
346 | |
347 ;;;###autoload | |
348 (defun hyper-describe-variable (symbol) | |
349 "Hypertext drop-in replacement for `describe-variable'. | |
350 See also `hyper-apropos' and `hyper-describe-function'." | |
351 ;; #### - perhaps a prefix arg should suppress the prompt... | |
352 (interactive | |
353 (let* ((v (variable-at-point)) | |
354 (val (let ((enable-recursive-minibuffers t)) | |
355 (completing-read | |
356 (if v | |
357 (format "Describe variable (default %s): " v) | |
358 "Describe variable: ") | |
359 obarray 'boundp t)))) | |
360 (list (if (string= val "") v (intern-soft val))))) | |
361 (if (null symbol) | |
362 (message "Sorry, nothing to describe.") | |
363 (or (memq major-mode '(hyper-apropos-mode hyper-help-mode)) | |
364 (setq hypropos-prev-wconfig (current-window-configuration))) | |
365 (hypropos-get-doc symbol t))) | |
366 | |
367 ;;;###autoload | |
368 (defun hyper-describe-function (symbol) | |
369 "Hypertext replacement for `describe-function'. Unlike `describe-function' | |
370 in that the symbol under the cursor is the default if it is a function. | |
371 See also `hyper-apropos' and `hyper-describe-variable'." | |
372 ;; #### - perhaps a prefix arg should suppress the prompt... | |
373 (interactive | |
374 (let (fn val) | |
375 (setq fn (hypropos-this-symbol)) ; symbol under point | |
376 (or (fboundp fn) | |
377 (setq fn (function-called-at-point))) | |
378 (setq val (let ((enable-recursive-minibuffers t)) | |
379 (completing-read | |
380 (if fn | |
381 (format "Describe function (default %s): " fn) | |
382 "Describe function: ") | |
383 obarray 'fboundp t))) | |
384 (list (if (equal val "") fn (intern-soft val))))) | |
385 (if (null symbol) | |
386 (message "Sorry, nothing to describe.") | |
387 (or (memq major-mode '(hyper-apropos-mode hyper-help-mode)) | |
388 (setq hypropos-prev-wconfig (current-window-configuration))) | |
389 (hypropos-get-doc symbol t))) | |
390 | |
391 (defun hypropos-last-help (arg) | |
392 "Go back to the last symbol documented in the *Hyper Help* buffer." | |
393 (interactive "P") | |
394 (let ((win (get-buffer-window hypropos-help-buf)) | |
395 (n (prefix-numeric-value arg))) | |
396 (cond ((and (not win) (not arg)) | |
397 ;; don't alter the help-history, just redisplay | |
398 ) | |
399 ((<= (length hypropos-help-history) n) | |
400 ;; go back as far as we can... | |
401 (setcdr (nreverse hypropos-help-history) nil)) | |
402 (t | |
403 (setq hypropos-help-history (nthcdr n hypropos-help-history)))) | |
404 (hypropos-get-doc (car hypropos-help-history) t))) | |
405 | |
406 (defun hypropos-get-doc (&optional symbol force type) | |
407 ;; #### - update this docstring | |
408 "Toggle display of documentation for the symbol on the current line." | |
409 ;; SYMBOL is the symbol to document. FORCE, if non-nil, means to | |
410 ;; regenerate the documentation even if it already seems to be there. And | |
411 ;; TYPE, if present, forces the generation of only variable documentation | |
412 ;; or only function documentation. Normally, if both are present, then | |
413 ;; both will be generated. | |
414 ;; | |
415 ;; TYPES TO IMPLEMENT: obsolete face | |
416 ;; | |
417 (interactive) | |
418 (or symbol | |
419 (setq symbol (hypropos-this-symbol))) | |
420 (or type | |
421 (setq type '(function variable face))) | |
422 (if (and (eq hypropos-currently-showing symbol) | |
423 (get-buffer hypropos-help-buf) | |
424 (get-buffer-window hypropos-help-buf) | |
425 (not force)) | |
426 ;; we're already displaying this help, so toggle its display. | |
427 (delete-windows-on hypropos-help-buf) | |
428 ;; OK, we've got to refresh and display it... | |
429 (or (eq symbol (car hypropos-help-history)) | |
430 (setq hypropos-help-history | |
431 (if (eq major-mode 'hyper-help-mode) | |
432 ;; if we're following a link in the help buffer, then | |
433 ;; record that in the help history. | |
434 (cons symbol hypropos-help-history) | |
435 ;; otherwise clear the history because it's a new search. | |
436 (list symbol)))) | |
437 (save-excursion | |
438 (set-buffer (get-buffer-create hypropos-help-buf)) | |
439 (setq buffer-read-only nil) | |
440 (erase-buffer) | |
441 (let ((standard-output (current-buffer)) | |
442 ok beg desc | |
443 ftype macrop fndef | |
444 keys val doc | |
445 obsolete aliases alias-desc) | |
446 (insert-face (format "`%s'\n\n" symbol) 'major-heading) | |
447 (and (memq 'function type) | |
448 (fboundp symbol) | |
449 (progn | |
450 (setq ok t | |
451 fndef (symbol-function symbol)) | |
452 (while (symbolp fndef) | |
453 (setq aliases (cons fndef aliases)) | |
454 (setq fndef (symbol-function fndef))) | |
455 (if (eq 'macro (car-safe fndef)) | |
456 (setq macrop t | |
457 fndef (cdr fndef))) | |
458 (setq aliases (nreverse aliases)) | |
459 ;; #### - the gods of internationalization shall strike me down! | |
460 (while aliases | |
461 (if alias-desc | |
462 (setq alias-desc (concat alias-desc ",\nwhich is "))) | |
463 (setq alias-desc (concat alias-desc | |
464 (format "an alias for `%s'" | |
465 (car aliases)))) | |
466 (setq aliases (cdr aliases))) | |
467 (setq ftype (cond ((subrp fndef) 'subr) | |
468 ((compiled-function-p fndef) 'bytecode) | |
469 ((eq (car-safe fndef) 'autoload) 'autoload) | |
470 ((eq (car-safe fndef) 'lambda) 'lambda)) | |
471 desc (concat (if (commandp symbol) "interactive ") | |
472 (cdr (assq ftype | |
473 '((subr . "built-in ") | |
474 (bytecode . "compiled Lisp ") | |
475 (autoload . "autoloaded Lisp ") | |
476 (lambda . "Lisp ")))) | |
477 (if macrop "macro" "function") | |
478 )) | |
479 (if alias-desc | |
480 (setq desc (concat alias-desc | |
481 (if (memq (aref desc 0) | |
482 '(?a ?e ?i ?o ?u)) | |
483 ", an " ", a ") | |
484 desc))) | |
485 (aset desc 0 (upcase (aref desc 0))) ; capitalize | |
486 (insert-face desc 'section-heading) | |
487 (and (eq ftype 'autoload) | |
488 (insert (format ", (autoloaded from \"%s\")" | |
489 (nth 1 fndef)))) | |
490 ;; #### - should also show local binding in some other | |
491 ;; buffer so that this function can be used in place of | |
492 ;; describe-function and describe-variable. | |
493 (if (setq keys (where-is-internal symbol (current-global-map) | |
494 nil nil nil)) | |
495 (insert (format ", (globally bound to %s)" | |
496 (mapconcat | |
497 #'(lambda (x) | |
498 (format "\"%s\"" | |
499 (key-description x))) | |
500 (sort keys #'(lambda (x y) | |
501 (< (length x) (length y)))) | |
502 ", ")))) | |
503 (insert ":\n\n") | |
504 (setq beg (point) | |
505 doc (or (documentation symbol) "function not documented")) | |
506 (insert-face "arguments: " 'heading) | |
507 (cond ((eq ftype 'lambda) | |
508 (princ (or (nth 1 fndef) "()"))) | |
509 ((eq ftype 'bytecode) | |
510 (princ (or (if (fboundp 'compiled-function-arglist) | |
511 (compiled-function-arglist fndef) | |
512 (aref fndef 0)) "()"))) | |
513 ((and (eq ftype 'subr) | |
514 (string-match | |
515 "[\n\t ]*\narguments: ?\\((.*)\\)\n?\\'" | |
516 doc)) | |
517 (insert (substring doc | |
518 (match-beginning 1) | |
519 (match-end 1))) | |
520 (setq doc (substring doc 0 (match-beginning 0)))) | |
521 (t (princ "[not available]"))) | |
522 (insert "\n\n") | |
523 (let ((new | |
524 ;; cookbook from bytecomp.el | |
525 (get symbol 'byte-obsolete-info))) | |
526 (and new | |
527 (insert-face | |
528 (format "%s is an obsolete function; %s\n\n" symbol | |
529 (if (stringp (car new)) | |
530 (car new) | |
531 (format "use %s instead." (car new)))) | |
532 'warning))) | |
533 (insert-face doc 'documentation) | |
534 (indent-rigidly beg (point) 1) | |
535 (insert"\n\n") | |
536 )) | |
537 (and (memq 'variable type) | |
538 (boundp symbol) | |
539 (progn | |
540 (setq ok t) | |
541 (insert-face (if (user-variable-p symbol) | |
542 "User variable" | |
543 "Variable") | |
544 'section-heading) | |
545 (and (local-variable-p symbol nil t) | |
546 (insert ", local when set")) | |
547 (insert ":\n\n") | |
548 (setq beg (point) | |
549 val (prin1-to-string (symbol-value symbol)) | |
550 doc (or (documentation-property | |
551 symbol 'variable-documentation) | |
552 "variable not documented")) | |
553 | |
554 (let ((ob (get symbol 'byte-obsolete-variable))) | |
555 (setq obsolete | |
556 (and ob (format "%s is an obsolete variable; %s\n\n" | |
557 symbol | |
558 (if (stringp ob) | |
559 ob | |
560 (format "use %s instead." ob)))))) | |
561 ;; generally, the value of the variable is short and the | |
562 ;; documentation of the variable long, so it's desirable | |
563 ;; to see all of the value and the start of the | |
564 ;; documentation. Some variables, though, have huge and | |
565 ;; nearly meaningless values that force you to page | |
566 ;; forward just to find the doc string. That is | |
567 ;; undesirable. | |
568 (if (< (length val) 69) ; 80 cols. docstrings assume this. | |
569 (progn (insert-face "value: " 'heading) | |
570 (insert (format "%s\n\n" val)) | |
571 (and obsolete (insert-face obsolete 'warning)) | |
572 (insert-face doc 'documentation)) | |
573 (insert "(see below for value)\n\n") | |
574 (and obsolete (insert-face obsolete 'warning)) | |
575 (insert-face doc 'documentation) | |
576 (insert "\n\n") | |
577 (insert-face "value: " 'heading) | |
578 (if hypropos-prettyprint-long-values | |
579 (let ((pp-print-readably nil)) | |
580 (pprint (symbol-value symbol))) | |
581 (insert val))) | |
582 (indent-rigidly beg (point) 2) | |
583 )) | |
584 (and (memq 'face type) | |
585 (find-face symbol) | |
586 (progn | |
587 (setq ok t) | |
588 ;; #### - add some code here | |
589 (insert "Face documentation is \"To be implemented.\"\n\n") | |
590 ) | |
591 ) | |
592 (or ok (insert-face "symbol is not currently bound" 'heading))) | |
593 (goto-char (point-min)) | |
594 ;; pop up window and shrink it if it's wasting space | |
595 (shrink-window-if-larger-than-buffer | |
596 (display-buffer (current-buffer))) | |
597 (hyper-help-mode)) ) | |
598 (setq hypropos-currently-showing symbol)) | |
599 | |
600 ; ----------------------------------------------------------------------------- | |
601 | |
602 (defun hyper-help-mode () | |
603 "Major mode for hypertext XEmacs help. In this mode, you can quickly | |
604 follow links between back and forth between the documentation strings for | |
605 different variables and functions. Common commands: | |
606 | |
607 \\{hypropos-help-map}" | |
608 (setq mode-motion-hook 'hypropos-highlight-lisp-symbol | |
609 buffer-read-only t | |
610 major-mode 'hyper-help-mode | |
611 mode-name "Hyper-Help") | |
612 (set-syntax-table emacs-lisp-mode-syntax-table) | |
613 (use-local-map hypropos-help-map)) | |
614 | |
615 (defun hypropos-highlight-lisp-symbol (event) | |
616 ;; mostly copied from mode-motion-highlight-internal | |
617 (let* ((window (event-window event)) | |
618 (buffer (and window (window-buffer window))) | |
619 (point (and buffer (event-point event))) | |
620 st en sym highlight-p) | |
621 (if buffer | |
622 (progn | |
623 (set-buffer buffer) | |
624 (if point | |
625 (save-excursion | |
626 (goto-char point) | |
627 (setq st (save-excursion | |
628 (skip-syntax-backward "w_") | |
629 (skip-chars-forward "`") | |
630 (point)) | |
631 en (save-excursion | |
632 (goto-char st) | |
633 (skip-syntax-forward "w_") | |
634 (skip-chars-backward ".") | |
635 (point)) | |
636 sym (and (not (eq st en)) | |
637 (intern-soft (buffer-substring st en))) | |
638 highlight-p (and sym | |
639 (or (boundp sym) | |
640 (fboundp sym)))) | |
641 (if highlight-p | |
642 (if mode-motion-extent | |
643 (set-extent-endpoints mode-motion-extent st en) | |
644 (setq mode-motion-extent (make-extent st en)) | |
645 (set-extent-property mode-motion-extent 'highlight t)) | |
646 (and mode-motion-extent | |
647 (progn (delete-extent mode-motion-extent) | |
648 (setq mode-motion-extent nil))) | |
649 )) | |
650 ;; not over text; zero the extent. | |
651 (if (and mode-motion-extent (extent-buffer mode-motion-extent) | |
652 (not (eq (extent-start-position mode-motion-extent) | |
653 (extent-end-position mode-motion-extent)))) | |
654 (set-extent-endpoints mode-motion-extent 1 1))))))) | |
655 | |
656 | |
657 ;; ---------------------------------------------------------------------- ;; | |
658 | |
659 (defun hypropos-scroll-up () | |
660 "Scroll up the \"*Hyper Help*\" buffer if it's visible, or scroll this window up." | |
661 (interactive) | |
662 (let ((win (get-buffer-window hypropos-help-buf)) | |
663 (owin (selected-window))) | |
664 (if win | |
665 (progn | |
666 (select-window win) | |
667 (condition-case nil | |
668 (scroll-up nil) | |
669 (error (goto-char (point-max)))) | |
670 (select-window owin)) | |
671 (scroll-up nil)))) | |
672 | |
673 (defun hypropos-scroll-down () | |
674 "Scroll down the \"*Hyper Help*\" buffer if it's visible, or scroll this window down." | |
675 (interactive) | |
676 (let ((win (get-buffer-window hypropos-help-buf)) | |
677 (owin (selected-window))) | |
678 (if win | |
679 (progn | |
680 (select-window win) | |
681 (condition-case nil | |
682 (scroll-down nil) | |
683 (error (goto-char (point-max)))) | |
684 (select-window owin)) | |
685 (scroll-down nil)))) | |
686 | |
687 ;; ---------------------------------------------------------------------- ;; | |
688 | |
689 (defun hypropos-mouse-get-doc (event) | |
690 "Get the documentation for the symbol the mouse is on." | |
691 (interactive "e") | |
692 (mouse-set-point event) | |
693 (save-excursion | |
694 (let ((symbol (hypropos-this-symbol))) | |
695 (if symbol | |
696 (hypropos-get-doc symbol) | |
697 (error "Click on a symbol"))))) | |
698 | |
699 ;; ---------------------------------------------------------------------- ;; | |
700 | |
701 (defun hypropos-add-keyword (pattern) | |
702 "Use additional keyword to narrow regexp match. | |
703 Deletes lines which don't match PATTERN." | |
704 (interactive "sAdditional Keyword: ") | |
705 (save-excursion | |
706 (goto-char (point-min)) | |
707 (let (buffer-read-only) | |
708 (keep-lines (concat pattern "\\|" hypropos-junk-regexp)) | |
709 ))) | |
710 | |
711 (defun hypropos-eliminate-keyword (pattern) | |
712 "Use additional keyword to eliminate uninteresting matches. | |
713 Deletes lines which match PATTERN." | |
714 (interactive "sKeyword to eliminate: ") | |
715 (save-excursion | |
716 (goto-char (point-min)) | |
717 (let (buffer-read-only) | |
718 (flush-lines pattern)) | |
719 )) | |
720 | |
721 ;; ---------------------------------------------------------------------- ;; | |
722 | |
723 (defun hypropos-this-symbol () | |
724 (save-excursion | |
725 (cond ((eq major-mode 'hyper-apropos-mode) | |
726 (beginning-of-line) | |
727 (if (looking-at hypropos-junk-regexp) | |
728 nil | |
729 (forward-char 3) | |
730 (read (point-marker)))) | |
731 (t | |
732 (let* ((st (progn | |
733 (skip-syntax-backward "w_") | |
734 ;; !@(*$^%%# stupid backquote implementation!!! | |
735 (skip-chars-forward "`") | |
736 (point))) | |
737 (en (progn | |
738 (skip-syntax-forward "w_") | |
739 (skip-chars-backward ".") | |
740 (point)))) | |
741 (and (not (eq st en)) | |
742 (intern-soft (buffer-substring st en)))))))) | |
743 | |
744 (defun hypropos-where-is (symbol) | |
745 "Find keybinding for symbol on current line." | |
746 (interactive (list (hypropos-this-symbol))) | |
747 (where-is symbol)) | |
748 | |
749 (defun hypropos-invoke-fn (fn) | |
750 "Interactively invoke the function on the current line." | |
751 (interactive (list (hypropos-this-symbol))) | |
752 (cond ((not (fboundp fn)) | |
753 (error "%S is not a function" fn)) | |
754 (t (call-interactively fn)))) | |
755 | |
756 ;;;###autoload | |
757 (defun hypropos-set-variable (var val) | |
758 "Interactively set the variable on the current line." | |
759 (interactive | |
760 (let ((var (save-excursion | |
761 (and (eq major-mode 'hypropos-help-mode) | |
762 (goto-char (point-min))) | |
763 (hypropos-this-symbol)))) | |
764 (or (boundp var) | |
765 (setq var (completing-read "Set variable: " | |
766 obarray 'boundp t))) | |
767 (hypropos-get-doc var t) | |
768 (list var | |
769 (let ((prop (get var 'variable-interactive)) | |
770 (print-readably t) | |
771 (val (symbol-value var))) | |
772 (if prop | |
773 (call-interactively (list 'lambda '(arg) | |
774 (list 'interactive prop) | |
775 'arg)) | |
776 (eval-minibuffer | |
777 (format "Set `%s' to value (evaluated): " var) | |
778 (format (if (or (consp val) | |
779 (and (symbolp val) | |
780 (not (memq val '(t nil))))) | |
781 "'%s" "%s") | |
782 (prin1-to-string val)))))) | |
783 )) | |
784 (set var val) | |
785 (hypropos-get-doc var t)) | |
786 | |
787 ;; ---------------------------------------------------------------------- ;; | |
788 | |
789 (defun hypropos-find-tag (&optional tag-name) | |
790 "Find the tag for the symbol on the current line in other window. In | |
791 order for this to work properly, the variable `tag-table-alist' or | |
792 `tags-file-name' must be set so that a TAGS file with tags for the emacs | |
793 source is found for the \"*Hyper Apropos*\" buffer." | |
794 (interactive) | |
795 ;; there ought to be a default tags file for this... | |
796 (or tag-name (setq tag-name (symbol-name (hypropos-this-symbol)))) | |
797 (find-tag-other-window (list tag-name))) | |
798 | |
799 ;; ---------------------------------------------------------------------- ;; | |
800 | |
801 (defun hypropos-disassemble (sym) | |
802 "Disassemble FUN if it is byte-coded. If it's a lambda, prettyprint it." | |
803 (interactive (list (hypropos-this-symbol))) | |
804 (let ((fun sym) (trail nil) macrop) | |
805 (while (and (symbolp fun) (not (memq fun trail))) | |
806 (setq trail (cons fun trail) | |
807 fun (symbol-function fun))) | |
808 (and (symbolp fun) | |
809 (error "Loop detected in function binding of `%s'" fun)) | |
810 (setq macrop (and (consp fun) | |
811 (eq 'macro (car fun)))) | |
812 (cond ((compiled-function-p (if macrop (cdr fun) fun)) | |
813 (disassemble fun) | |
814 (set-buffer "*Disassemble*") | |
815 (goto-char (point-min)) | |
816 (forward-sexp 2) | |
817 (insert (format " for function `%S'" sym)) | |
818 ) | |
819 ((consp fun) | |
820 (with-output-to-temp-buffer "*Disassemble*" | |
821 (pprint (if macrop | |
822 (cons 'defmacro (cons sym (cdr (cdr fun)))) | |
823 (cons 'defun (cons sym (cdr fun)))))) | |
824 (set-buffer "*Disassemble*") | |
825 (emacs-lisp-mode)) | |
826 ((or (vectorp fun) (stringp fun)) | |
827 ;; #### - do something fancy here | |
828 (with-output-to-temp-buffer "*Disassemble*" | |
829 (princ (format "%s is a keyboard macro:\n\n\t" sym)) | |
830 (prin1 fun))) | |
831 (t | |
832 (error "Sorry, cannot disassemble `%s'" sym))))) | |
833 | |
834 ;; ---------------------------------------------------------------------- ;; | |
835 | |
836 (defun hypropos-quit () | |
837 (interactive) | |
838 "Quit Hyper Apropos and restore original window config." | |
839 (let ((buf (get-buffer hypropos-apropos-buf))) | |
840 (and buf (bury-buffer buf))) | |
841 (set-window-configuration hypropos-prev-wconfig)) | |
842 | |
843 ;; ---------------------------------------------------------------------- ;; | |
844 | |
845 ;;;###autoload | |
846 (defun hypropos-popup-menu (event) | |
847 (interactive "e") | |
848 (mouse-set-point event) | |
849 (let* ((sym (hypropos-this-symbol)) | |
850 (notjunk (not (null sym))) | |
851 (command-p (commandp sym)) | |
852 (variable-p (and sym (boundp sym))) | |
853 (function-p (fboundp sym)) | |
854 (apropos-p (eq 'hyper-apropos-mode | |
855 (save-excursion (set-buffer (event-buffer event)) | |
856 major-mode))) | |
857 (name (if sym (symbol-name sym) "")) | |
858 (hypropos-menu | |
859 (delete | |
860 nil | |
861 (list (concat "Hyper-Help: " name) | |
862 (vector "Display documentation" 'hypropos-get-doc notjunk) | |
863 (vector "Set variable" 'hypropos-set-variable variable-p) | |
864 (vector "Show keys for" 'hypropos-where-is command-p) | |
865 (vector "Invoke command" 'hypropos-invoke-fn command-p) | |
866 (vector "Find tag" 'hypropos-find-tag notjunk) | |
867 (and apropos-p | |
868 ["Add keyword..." hypropos-add-keyword t]) | |
869 (and apropos-p | |
870 ["Eliminate keyword..." hypropos-eliminate-keyword t]) | |
871 (if apropos-p | |
872 ["Programmers' Apropos" hypropos-toggle-programming-flag | |
873 :style toggle :selected hypropos-programming-apropos] | |
874 ["Programmers' Help" hypropos-toggle-programming-flag | |
875 :style toggle :selected hypropos-programming-apropos]) | |
876 (and hypropos-programming-apropos | |
877 (vector "Disassemble function" | |
878 'hypropos-disassemble | |
879 function-p)) | |
880 ["Help" describe-mode t] | |
881 ["Quit" hypropos-quit t] | |
882 )))) | |
883 (popup-menu hypropos-menu))) | |
884 | |
885 (provide 'hyper-apropos) | |
886 | |
887 ;; end of hyper-apropos.el | |
888 |