* apropos.el (apropos-symbol): Don't set button skip by default.
[bpt/emacs.git] / lisp / apropos.el
CommitLineData
e8af40ee 1;;; apropos.el --- apropos commands for users and programmers
c0274f38 2
0d30b337 3;; Copyright (C) 1989, 1994, 1995, 2001, 2002, 2003, 2004,
409cc4a3 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
9750e079 5
e5167999 6;; Author: Joe Wells <jbw@bigbird.bu.edu>
ae212837 7;; Rewritten: Daniel Pfeiffer <occitan@esperanto.org>
e9571d2a 8;; Keywords: help
e5167999 9
6f8e447f
RS
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
6f8e447f 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
6f8e447f
RS
16
17;; GNU Emacs 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
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
6f8e447f 24
e5167999 25;;; Commentary:
6f8e447f
RS
26
27;; The ideas for this package were derived from the C code in
28;; src/keymap.c and elsewhere. The functions in this file should
29;; always be byte-compiled for speed. Someone should rewrite this in
30;; C (as part of src/keymap.c) for speed.
31
32;; The idea for super-apropos is based on the original implementation
33;; by Lynn Slater <lrs@esl.com>.
34
35;; History:
36;; Fixed bug, current-local-map can return nil.
37;; Change, doesn't calculate key-bindings unless needed.
38;; Added super-apropos capability, changed print functions.
3925e76d
KH
39;;; Made fast-apropos and super-apropos share code.
40;;; Sped up fast-apropos again.
6f8e447f 41;; Added apropos-do-all option.
3925e76d 42;;; Added fast-command-apropos.
6f8e447f 43;; Changed doc strings to comments for helping functions.
3925e76d 44;;; Made doc file buffer read-only, buried it.
6f8e447f
RS
45;; Only call substitute-command-keys if do-all set.
46
645c4f6a
KH
47;; Optionally use configurable faces to make the output more legible.
48;; Differentiate between command, function and macro.
3925e76d
KH
49;; Apropos-command (ex command-apropos) does cmd and optionally user var.
50;; Apropos shows all 3 aspects of symbols (fn, var and plist)
51;; Apropos-documentation (ex super-apropos) now finds all it should.
52;; New apropos-value snoops through all values and optionally plists.
53;; Reading DOC file doesn't load nroff.
54;; Added hypertext following of documentation, mouse-2 on variable gives value
55;; from buffer in active window.
56
e5167999
ER
57;;; Code:
58
851befd4 59(require 'button)
caa8e7aa 60(eval-when-compile (require 'cl))
851befd4 61
ddd2f740 62(defgroup apropos nil
32463e4d 63 "Apropos commands for users and programmers."
c906e3ab 64 :group 'help
ddd2f740
RS
65 :prefix "apropos")
66
3925e76d 67;; I see a degradation of maybe 10-20% only.
ddd2f740 68(defcustom apropos-do-all nil
671c04d9 69 "Whether the apropos commands should do more.
ddd2f740
RS
70
71Slows them down more or less. Set this non-nil if you have a fast machine."
72 :group 'apropos
73 :type 'boolean)
3925e76d
KH
74
75
07eeca5d 76(defcustom apropos-symbol-face 'bold
671c04d9 77 "Face for symbol name in Apropos output, or nil for none."
ddd2f740
RS
78 :group 'apropos
79 :type 'face)
645c4f6a 80
07eeca5d 81(defcustom apropos-keybinding-face 'underline
671c04d9 82 "Face for lists of keybinding in Apropos output, or nil for none."
ddd2f740
RS
83 :group 'apropos
84 :type 'face)
645c4f6a 85
671c04d9
SM
86(defcustom apropos-label-face '(italic variable-pitch)
87 "Face for label (`Command', `Variable' ...) in Apropos output.
07eeca5d
RS
88A value of nil means don't use any special font for them, and also
89turns off mouse highlighting."
ddd2f740
RS
90 :group 'apropos
91 :type 'face)
645c4f6a 92
07eeca5d 93(defcustom apropos-property-face 'bold-italic
671c04d9 94 "Face for property name in apropos output, or nil for none."
ddd2f740
RS
95 :group 'apropos
96 :type 'face)
645c4f6a 97
5248b3e3 98(defcustom apropos-match-face 'match
671c04d9 99 "Face for matching text in Apropos documentation/value, or nil for none.
07eeca5d 100This applies when you look for matches in the documentation or variable value
0820b753 101for the pattern; the part that matches gets displayed in this font."
ddd2f740
RS
102 :group 'apropos
103 :type 'face)
3925e76d 104
ab765ff7 105(defcustom apropos-sort-by-scores nil
671c04d9 106 "Non-nil means sort matches by scores; best match is shown first.
0820b753
KS
107This applies to all `apropos' commands except `apropos-documentation'.
108If value is `verbose', the computed score is shown for each match."
30aab741 109 :group 'apropos
0820b753
KS
110 :type '(choice (const :tag "off" nil)
111 (const :tag "on" t)
112 (const :tag "show scores" verbose)))
113
114(defcustom apropos-documentation-sort-by-scores t
115 "*Non-nil means sort matches by scores; best match is shown first.
116This applies to `apropos-documentation' only.
117If value is `verbose', the computed score is shown for each match."
118 :group 'apropos
119 :type '(choice (const :tag "off" nil)
120 (const :tag "on" t)
121 (const :tag "show scores" verbose)))
6f8e447f 122
26a4a227 123(defvar apropos-mode-map
3925e76d 124 (let ((map (make-sparse-keymap)))
e517f56d
MB
125 (set-keymap-parent map button-buffer-map)
126 ;; Use `apropos-follow' instead of just using the button
127 ;; definition of RET, so that users can use it anywhere in an
128 ;; apropos item, not just on top of a button.
3925e76d 129 (define-key map "\C-m" 'apropos-follow)
5b23b5e4
RS
130 (define-key map " " 'scroll-up)
131 (define-key map "\177" 'scroll-down)
132 (define-key map "q" 'quit-window)
3925e76d 133 map)
26a4a227 134 "Keymap used in Apropos mode.")
4de5599d 135
45f485a6 136(defvar apropos-mode-hook nil
671c04d9 137 "Hook run when mode is turned on.")
3925e76d 138
fe8bc3fa 139(defvar apropos-pattern nil
0820b753
KS
140 "Apropos pattern as entered by user.")
141
142(defvar apropos-pattern-quoted nil
c6b19225 143 "Apropos pattern passed through `regexp-quote'.")
0820b753
KS
144
145(defvar apropos-words ()
146 "Current list of apropos words extracted from `apropos-pattern'.")
645c4f6a 147
0820b753
KS
148(defvar apropos-all-words ()
149 "Current list of words and synonyms.")
7dbffb1c 150
0820b753
KS
151(defvar apropos-regexp nil
152 "Regexp used in current apropos run.")
153
154(defvar apropos-all-words-regexp nil
7dbffb1c
KS
155 "Regexp matching apropos-all-words.")
156
645c4f6a 157(defvar apropos-files-scanned ()
1259a080 158 "List of elc files already scanned in current run of `apropos-documentation'.")
645c4f6a
KH
159
160(defvar apropos-accumulator ()
161 "Alist of symbols already found in current apropos run.")
3925e76d 162
645c4f6a 163(defvar apropos-item ()
7a5348db 164 "Current item in or for `apropos-accumulator'.")
e517f56d 165
7dbffb1c
KS
166(defvar apropos-synonyms '(
167 ("find" "open" "edit")
168 ("kill" "cut")
f4517e51
KS
169 ("yank" "paste")
170 ("region" "selection"))
7dbffb1c 171 "List of synonyms known by apropos.
5e24ee14 172Each element is a list of words where the first word is the standard Emacs
7dbffb1c
KS
173term, and the rest of the words are alternative terms.")
174
e517f56d
MB
175\f
176;;; Button types used by apropos
177
178(define-button-type 'apropos-symbol
179 'face apropos-symbol-face
894e460c 180 'help-echo "mouse-2, RET: Display more help on this symbol"
d8fac801 181 'follow-link t
894e460c
MB
182 'action #'apropos-symbol-button-display-help
183 'skip t)
e517f56d
MB
184
185(defun apropos-symbol-button-display-help (button)
186 "Display further help for the `apropos-symbol' button BUTTON."
187 (button-activate
188 (or (apropos-next-label-button (button-start button))
189 (error "There is nothing to follow for `%s'" (button-label button)))))
190
894e460c
MB
191(define-button-type 'apropos-function
192 'apropos-label "Function"
1d69bd9b 193 'apropos-short-label "f"
d8fac801
KS
194 'help-echo "mouse-2, RET: Display more help on this function"
195 'follow-link t
894e460c 196 'action (lambda (button)
d8fac801
KS
197 (describe-function (button-get button 'apropos-symbol))))
198
894e460c
MB
199(define-button-type 'apropos-macro
200 'apropos-label "Macro"
1d69bd9b 201 'apropos-short-label "m"
d8fac801
KS
202 'help-echo "mouse-2, RET: Display more help on this macro"
203 'follow-link t
894e460c 204 'action (lambda (button)
d8fac801
KS
205 (describe-function (button-get button 'apropos-symbol))))
206
894e460c
MB
207(define-button-type 'apropos-command
208 'apropos-label "Command"
1d69bd9b 209 'apropos-short-label "c"
d8fac801
KS
210 'help-echo "mouse-2, RET: Display more help on this command"
211 'follow-link t
894e460c 212 'action (lambda (button)
d8fac801 213 (describe-function (button-get button 'apropos-symbol))))
7cfedc97 214
894e460c
MB
215;; We used to use `customize-variable-other-window' instead for a
216;; customizable variable, but that is slow. It is better to show an
217;; ordinary help buffer and let the user click on the customization
218;; button in that buffer, if he wants to.
219;; Likewise for `customize-face-other-window'.
220(define-button-type 'apropos-variable
221 'apropos-label "Variable"
1d69bd9b 222 'apropos-short-label "v"
894e460c 223 'help-echo "mouse-2, RET: Display more help on this variable"
d8fac801 224 'follow-link t
894e460c
MB
225 'action (lambda (button)
226 (describe-variable (button-get button 'apropos-symbol))))
227
228(define-button-type 'apropos-face
229 'apropos-label "Face"
1d69bd9b 230 'apropos-short-label "F"
894e460c 231 'help-echo "mouse-2, RET: Display more help on this face"
d8fac801 232 'follow-link t
894e460c
MB
233 'action (lambda (button)
234 (describe-face (button-get button 'apropos-symbol))))
235
236(define-button-type 'apropos-group
237 'apropos-label "Group"
1d69bd9b 238 'apropos-short-label "g"
894e460c 239 'help-echo "mouse-2, RET: Display more help on this group"
d8fac801 240 'follow-link t
894e460c 241 'action (lambda (button)
2d37b91e 242 (customize-group-other-window
894e460c
MB
243 (button-get button 'apropos-symbol))))
244
245(define-button-type 'apropos-widget
246 'apropos-label "Widget"
1d69bd9b 247 'apropos-short-label "w"
894e460c 248 'help-echo "mouse-2, RET: Display more help on this widget"
d8fac801 249 'follow-link t
894e460c
MB
250 'action (lambda (button)
251 (widget-browse-other-window (button-get button 'apropos-symbol))))
252
253(define-button-type 'apropos-plist
254 'apropos-label "Plist"
1d69bd9b 255 'apropos-short-label "p"
894e460c 256 'help-echo "mouse-2, RET: Display more help on this plist"
d8fac801 257 'follow-link t
894e460c
MB
258 'action (lambda (button)
259 (apropos-describe-plist (button-get button 'apropos-symbol))))
e517f56d 260
2e3d43ac
SM
261(define-button-type 'apropos-library
262 'help-echo "mouse-2, RET: Display more help on this library"
263 'follow-link t
264 'action (lambda (button)
265 (apropos-library (button-get button 'apropos-symbol))))
266
e517f56d 267(defun apropos-next-label-button (pos)
a11a4e9f 268 "Return the next apropos label button after POS, or nil if there's none.
e517f56d
MB
269Will also return nil if more than one `apropos-symbol' button is encountered
270before finding a label."
a101302b 271 (let* ((button (next-button pos t))
e517f56d 272 (already-hit-symbol nil)
3b8c60f1
MB
273 (label (and button (button-get button 'apropos-label)))
274 (type (and button (button-get button 'type))))
e517f56d 275 (while (and button
3b8c60f1
MB
276 (not label)
277 (or (not (eq type 'apropos-symbol))
e517f56d 278 (not already-hit-symbol)))
3b8c60f1 279 (when (eq type 'apropos-symbol)
e517f56d
MB
280 (setq already-hit-symbol t))
281 (setq button (next-button (button-start button)))
282 (when button
3b8c60f1
MB
283 (setq label (button-get button 'apropos-label))
284 (setq type (button-get button 'type))))
285 (and label button)))
e517f56d 286
645c4f6a 287\f
7dbffb1c
KS
288(defun apropos-words-to-regexp (words wild)
289 "Make regexp matching any two of the words in WORDS."
290 (concat "\\("
291 (mapconcat 'identity words "\\|")
80f5d2ef 292 "\\)"
71296446 293 (if (cdr words)
80f5d2ef
AS
294 (concat wild
295 "\\("
7dbffb1c
KS
296 (mapconcat 'identity words "\\|")
297 "\\)")
298 "")))
299
0820b753
KS
300;;;###autoload
301(defun apropos-read-pattern (subject)
302 "Read an apropos pattern, either a word list or a regexp.
303Returns the user pattern, either a list of words which are matched
304literally, or a string which is used as a regexp to search for.
305
306SUBJECT is a string that is included in the prompt to identify what
307kind of objects to search."
308 (let ((pattern
309 (read-string (concat "Apropos " subject " (word list or regexp): "))))
310 (if (string-equal (regexp-quote pattern) pattern)
311 ;; Split into words
312 (split-string pattern "[ \t]+")
313 pattern)))
314
315(defun apropos-parse-pattern (pattern)
316 "Rewrite a list of words to a regexp matching all permutations.
3fefda51
KS
317If PATTERN is a string, that means it is already a regexp.
318This updates variables `apropos-pattern', `apropos-pattern-quoted',
319`apropos-regexp', `apropos-words', and `apropos-all-words-regexp'."
0820b753
KS
320 (setq apropos-words nil
321 apropos-all-words nil)
322 (if (consp pattern)
7dbffb1c
KS
323 ;; We don't actually make a regexp matching all permutations.
324 ;; Instead, for e.g. "a b c", we make a regexp matching
325 ;; any combination of two or more words like this:
326 ;; (a|b|c).*(a|b|c) which may give some false matches,
327 ;; but as long as it also gives the right ones, that's ok.
0820b753
KS
328 (let ((words pattern))
329 (setq apropos-pattern (mapconcat 'identity pattern " ")
330 apropos-pattern-quoted (regexp-quote apropos-pattern))
7dbffb1c
KS
331 (dolist (word words)
332 (let ((syn apropos-synonyms) (s word) (a word))
333 (while syn
334 (if (member word (car syn))
335 (progn
336 (setq a (mapconcat 'identity (car syn) "\\|"))
337 (if (member word (cdr (car syn)))
338 (setq s a))
339 (setq syn nil))
340 (setq syn (cdr syn))))
341 (setq apropos-words (cons s apropos-words)
342 apropos-all-words (cons a apropos-all-words))))
3fefda51
KS
343 (setq apropos-all-words-regexp
344 (apropos-words-to-regexp apropos-all-words ".+"))
345 (setq apropos-regexp
346 (apropos-words-to-regexp apropos-words ".*?")))
0820b753
KS
347 (setq apropos-pattern-quoted (regexp-quote pattern)
348 apropos-all-words-regexp pattern
3fefda51
KS
349 apropos-pattern pattern
350 apropos-regexp pattern)))
0820b753 351
7dbffb1c
KS
352
353(defun apropos-calc-scores (str words)
354 "Return apropos scores for string STR matching WORDS.
355Value is a list of offsets of the words into the string."
0820b753 356 (let (scores i)
7dbffb1c
KS
357 (if words
358 (dolist (word words scores)
359 (if (setq i (string-match word str))
360 (setq scores (cons i scores))))
361 ;; Return list of start and end position of regexp
347a20b8 362 (and (string-match apropos-pattern str)
0820b753 363 (list (match-beginning 0) (match-end 0))))))
7dbffb1c
KS
364
365(defun apropos-score-str (str)
366 "Return apropos score for string STR."
367 (if str
0820b753
KS
368 (let* ((l (length str))
369 (score (- (/ l 10))))
7dbffb1c 370 (dolist (s (apropos-calc-scores str apropos-all-words) score)
d5857a96 371 (setq score (+ score 1000 (/ (* (- l s) 1000) l)))))
7dbffb1c
KS
372 0))
373
374(defun apropos-score-doc (doc)
375 "Return apropos score for documentation string DOC."
b7a2a696
LK
376 (let ((l (length doc)))
377 (if (> l 0)
0820b753
KS
378 (let ((score 0) i)
379 (when (setq i (string-match apropos-pattern-quoted doc))
380 (setq score 10000))
b7a2a696
LK
381 (dolist (s (apropos-calc-scores doc apropos-all-words) score)
382 (setq score (+ score 50 (/ (* (- l s) 50) l)))))
383 0)))
71296446 384
7dbffb1c
KS
385(defun apropos-score-symbol (symbol &optional weight)
386 "Return apropos score for SYMBOL."
387 (setq symbol (symbol-name symbol))
388 (let ((score 0)
0820b753 389 (l (length symbol)))
7dbffb1c
KS
390 (dolist (s (apropos-calc-scores symbol apropos-words) (* score (or weight 3)))
391 (setq score (+ score (- 60 l) (/ (* (- l s) 60) l))))))
392
d2b30292
KS
393(defun apropos-true-hit (str words)
394 "Return t if STR is a genuine hit.
395This may fail if only one of the keywords is matched more than once.
396This requires that at least 2 keywords (unless only one was given)."
397 (or (not str)
398 (not words)
399 (not (cdr words))
400 (> (length (apropos-calc-scores str words)) 1)))
401
402(defun apropos-false-hit-symbol (symbol)
403 "Return t if SYMBOL is not really matched by the current keywords."
404 (not (apropos-true-hit (symbol-name symbol) apropos-words)))
405
406(defun apropos-false-hit-str (str)
407 "Return t if STR is not really matched by the current keywords."
408 (not (apropos-true-hit str apropos-words)))
409
410(defun apropos-true-hit-doc (doc)
411 "Return t if DOC is really matched by the current keywords."
412 (apropos-true-hit doc apropos-all-words))
413
38ab866c 414(define-derived-mode apropos-mode fundamental-mode "Apropos"
26a4a227
KH
415 "Major mode for following hyperlinks in output of apropos commands.
416
38ab866c 417\\{apropos-mode-map}")
26a4a227 418
1d69bd9b
SM
419(defvar apropos-multi-type t
420 "If non-nil, this apropos query concerns multiple types.
421This is used to decide whether to print the result's type or not.")
422
f38fd610 423;;;###autoload
0820b753
KS
424(defun apropos-variable (pattern &optional do-all)
425 "Show user variables that match PATTERN.
426PATTERN can be a word, a list of words (separated by spaces),
427or a regexp (using some regexp special characters). If it is a word,
428search for matches for that word as a substring. If it is a list of words,
429search for matches for any two (or more) of those words.
430
431With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, also show
05942d06 432normal variables."
0820b753
KS
433 (interactive (list (apropos-read-pattern
434 (if (or current-prefix-arg apropos-do-all)
435 "variable" "user option"))
05942d06 436 current-prefix-arg))
0820b753 437 (apropos-command pattern nil
cd00fd36 438 (if (or do-all apropos-do-all)
05942d06
RS
439 #'(lambda (symbol)
440 (and (boundp symbol)
441 (get symbol 'variable-documentation)))
442 'user-variable-p)))
26a4a227 443
645c4f6a
KH
444;; For auld lang syne:
445;;;###autoload
82e736c1 446(defalias 'command-apropos 'apropos-command)
6f8e447f 447;;;###autoload
0820b753
KS
448(defun apropos-command (pattern &optional do-all var-predicate)
449 "Show commands (interactively callable functions) that match PATTERN.
450PATTERN can be a word, a list of words (separated by spaces),
fe8bc3fa
RS
451or a regexp (using some regexp special characters). If it is a word,
452search for matches for that word as a substring. If it is a list of words,
453search for matches for any two (or more) of those words.
454
0820b753 455With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, also show
9a909b3c 456noninteractive functions.
05942d06 457
9a909b3c 458If VAR-PREDICATE is non-nil, show only variables, and only those that
0820b753
KS
459satisfy the predicate VAR-PREDICATE.
460
461When called from a Lisp program, a string PATTERN is used as a regexp,
462while a list of strings is used as a word list."
463 (interactive (list (apropos-read-pattern
464 (if (or current-prefix-arg apropos-do-all)
465 "command or function" "command"))
645c4f6a 466 current-prefix-arg))
3fefda51 467 (apropos-parse-pattern pattern)
c851bcec 468 (let ((message
26a4a227 469 (let ((standard-output (get-buffer-create "*Apropos*")))
3925e76d 470 (print-help-return-message 'identity))))
645c4f6a
KH
471 (or do-all (setq do-all apropos-do-all))
472 (setq apropos-accumulator
0820b753 473 (apropos-internal apropos-regexp
cd00fd36 474 (or var-predicate
554fde6e
SM
475 ;; We used to use `functionp' here, but this
476 ;; rules out macros. `fboundp' rules in
477 ;; keymaps, but it seems harmless.
478 (if do-all 'fboundp 'commandp))))
dea22c45
RS
479 (let ((tem apropos-accumulator))
480 (while tem
d2b30292
KS
481 (if (or (get (car tem) 'apropos-inhibit)
482 (apropos-false-hit-symbol (car tem)))
dea22c45
RS
483 (setq apropos-accumulator (delq (car tem) apropos-accumulator)))
484 (setq tem (cdr tem))))
a9155e87 485 (let ((p apropos-accumulator)
7dbffb1c 486 doc symbol score)
a9155e87
KH
487 (while p
488 (setcar p (list
489 (setq symbol (car p))
7dbffb1c 490 (setq score (apropos-score-symbol symbol))
a9155e87 491 (unless var-predicate
554fde6e 492 (if (fboundp symbol)
a9155e87 493 (if (setq doc (documentation symbol t))
7dbffb1c 494 (progn
71296446 495 (setq score (+ score (apropos-score-doc doc)))
7dbffb1c 496 (substring doc 0 (string-match "\n" doc)))
a9155e87
KH
497 "(not documented)")))
498 (and var-predicate
499 (funcall var-predicate symbol)
500 (if (setq doc (documentation-property
501 symbol 'variable-documentation t))
7dbffb1c
KS
502 (progn
503 (setq score (+ score (apropos-score-doc doc)))
504 (substring doc 0
505 (string-match "\n" doc)))))))
506 (setcar (cdr (car p)) score)
a9155e87 507 (setq p (cdr p))))
1d69bd9b
SM
508 (and (let ((apropos-multi-type do-all))
509 (apropos-print t nil nil t))
a9155e87 510 message
8a26c165 511 (message "%s" message))))
3925e76d
KH
512
513
3925e76d 514;;;###autoload
914b40da
RS
515(defun apropos-documentation-property (symbol property raw)
516 "Like (documentation-property SYMBOL PROPERTY RAW) but handle errors."
517 (condition-case ()
518 (let ((doc (documentation-property symbol property raw)))
519 (if doc (substring doc 0 (string-match "\n" doc))
520 "(not documented)"))
521 (error "(error retrieving documentation)")))
522
5760219d
JPW
523
524;;;###autoload
0820b753 525(defun apropos (pattern &optional do-all)
2a4ec7e1
RS
526 "Show all meaningful Lisp symbols whose names match PATTERN.
527Symbols are shown if they are defined as functions, variables, or
528faces, or if they have nonempty property lists.
529
0820b753 530PATTERN can be a word, a list of words (separated by spaces),
fe8bc3fa
RS
531or a regexp (using some regexp special characters). If it is a word,
532search for matches for that word as a substring. If it is a list of words,
533search for matches for any two (or more) of those words.
534
543e570f
RS
535With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil,
536consider all symbols (if they match PATTERN).
537
538Returns list of symbols and documentation found."
0820b753
KS
539 (interactive (list (apropos-read-pattern "symbol")
540 current-prefix-arg))
3fefda51 541 (apropos-parse-pattern pattern)
caa8e7aa 542 (apropos-symbols-internal
0820b753 543 (apropos-internal apropos-regexp
543e570f
RS
544 (and (not do-all)
545 (not apropos-do-all)
546 (lambda (symbol)
547 (or (fboundp symbol)
548 (boundp symbol)
549 (facep symbol)
550 (symbol-plist symbol)))))
caa8e7aa
SM
551 (or do-all apropos-do-all)))
552
2e3d43ac
SM
553(defun apropos-library-button (sym)
554 (if (null sym)
555 "<nothing>"
556 (let ((name (copy-sequence (symbol-name sym))))
557 (make-text-button name nil
558 'type 'apropos-library
559 'face apropos-symbol-face
560 'apropos-symbol name)
561 name)))
562
563;;;###autoload
564(defun apropos-library (file)
565 "List the variables and functions defined by library FILE.
566FILE should be one of the libraries currently loaded and should
567thus be found in `load-history'."
568 (interactive
569 (let ((libs
570 (nconc (delq nil
571 (mapcar
572 (lambda (l)
573 (setq l (file-name-nondirectory l))
574 (while
575 (not (equal (setq l (file-name-sans-extension l))
576 l)))
577 l)
578 (mapcar 'car load-history)))
579 (mapcar 'car load-history))))
580 (list (completing-read "Describe library: " libs nil t))))
581 (let ((symbols nil)
582 ;; (autoloads nil)
583 (provides nil)
584 (requires nil)
585 (lh-entry (assoc file load-history)))
586 (unless lh-entry
587 ;; `file' may be the "shortname".
588 (let ((lh load-history)
589 (re (concat "\\(?:\\`\\|[\\/]\\)" (regexp-quote file)
590 "\\(\\.\\|\\'\\)")))
591 (while (and lh (null lh-entry))
592 (if (string-match re (caar lh))
593 (setq lh-entry (car lh))
594 (setq lh (cdr lh)))))
595 (unless lh-entry (error "Unknown library `%s'" file)))
596 (dolist (x (cdr lh-entry))
597 (case (car-safe x)
598 ;; (autoload (push (cdr x) autoloads))
599 (require (push (cdr x) requires))
600 (provide (push (cdr x) provides))
601 (t (push (or (cdr-safe x) x) symbols))))
602 (let ((apropos-pattern "")) ;Dummy binding for apropos-symbols-internal.
603 (apropos-symbols-internal
604 symbols apropos-do-all
605 (concat
606 (format "Library `%s' provides: %s\nand requires: %s"
607 file
608 (mapconcat 'apropos-library-button
609 (or provides '(nil)) " and ")
610 (mapconcat 'apropos-library-button
611 (or requires '(nil)) " and ")))))))
612
caa8e7aa
SM
613(defun apropos-symbols-internal (symbols keys &optional text)
614 ;; Filter out entries that are marked as apropos-inhibit.
615 (let ((all nil))
616 (dolist (symbol symbols)
617 (unless (get symbol 'apropos-inhibit)
618 (push symbol all)))
619 (setq symbols all))
620 (let ((apropos-accumulator
621 (mapcar
622 (lambda (symbol)
623 (let (doc properties)
624 (list
625 symbol
626 (apropos-score-symbol symbol)
627 (when (fboundp symbol)
628 (if (setq doc (condition-case nil
629 (documentation symbol t)
630 (void-function
631 "(alias for undefined function)")
632 (error
633 "(can't retrieve function documentation)")))
634 (substring doc 0 (string-match "\n" doc))
635 "(not documented)"))
636 (when (boundp symbol)
637 (apropos-documentation-property
914b40da 638 symbol 'variable-documentation t))
a9155e87
KH
639 (when (setq properties (symbol-plist symbol))
640 (setq doc (list (car properties)))
641 (while (setq properties (cdr (cdr properties)))
642 (setq doc (cons (car properties) doc)))
643 (mapconcat #'symbol-name (nreverse doc) " "))
644 (when (get symbol 'widget-type)
914b40da
RS
645 (apropos-documentation-property
646 symbol 'widget-documentation t))
caa8e7aa
SM
647 (when (facep symbol)
648 (apropos-documentation-property
649 symbol 'face-documentation t))
650 (when (get symbol 'custom-group)
914b40da 651 (apropos-documentation-property
caa8e7aa
SM
652 symbol 'group-documentation t)))))
653 symbols)))
654 (apropos-print keys nil text)))
3925e76d
KH
655
656
6f8e447f 657;;;###autoload
0820b753 658(defun apropos-value (pattern &optional do-all)
2a4ec7e1 659 "Show all symbols whose value's printed representation matches PATTERN.
0820b753 660PATTERN can be a word, a list of words (separated by spaces),
fe8bc3fa
RS
661or a regexp (using some regexp special characters). If it is a word,
662search for matches for that word as a substring. If it is a list of words,
663search for matches for any two (or more) of those words.
664
0820b753 665With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, also looks
3925e76d 666at the function and at the names and values of properties.
645c4f6a 667Returns list of symbols and values found."
0820b753
KS
668 (interactive (list (apropos-read-pattern "value")
669 current-prefix-arg))
3fefda51 670 (apropos-parse-pattern pattern)
645c4f6a
KH
671 (or do-all (setq do-all apropos-do-all))
672 (setq apropos-accumulator ())
673 (let (f v p)
3925e76d
KH
674 (mapatoms
675 (lambda (symbol)
676 (setq f nil v nil p nil)
0820b753
KS
677 (or (memq symbol '(apropos-regexp
678 apropos-pattern apropos-all-words-regexp
7dbffb1c
KS
679 apropos-words apropos-all-words
680 do-all apropos-accumulator
681 symbol f v p))
645c4f6a 682 (setq v (apropos-value-internal 'boundp symbol 'symbol-value)))
3925e76d 683 (if do-all
645c4f6a
KH
684 (setq f (apropos-value-internal 'fboundp symbol 'symbol-function)
685 p (apropos-format-plist symbol "\n " t)))
d2b30292
KS
686 (if (apropos-false-hit-str v)
687 (setq v nil))
688 (if (apropos-false-hit-str f)
689 (setq f nil))
690 (if (apropos-false-hit-str p)
691 (setq p nil))
3925e76d 692 (if (or f v p)
71296446 693 (setq apropos-accumulator (cons (list symbol
7dbffb1c
KS
694 (+ (apropos-score-str f)
695 (apropos-score-str v)
696 (apropos-score-str p))
697 f v p)
645c4f6a 698 apropos-accumulator))))))
1d69bd9b
SM
699 (let ((apropos-multi-type do-all))
700 (apropos-print nil "\n----------------\n")))
3925e76d
KH
701
702
645c4f6a 703;;;###autoload
0820b753 704(defun apropos-documentation (pattern &optional do-all)
2a4ec7e1 705 "Show symbols whose documentation contains matches for PATTERN.
0820b753 706PATTERN can be a word, a list of words (separated by spaces),
fe8bc3fa
RS
707or a regexp (using some regexp special characters). If it is a word,
708search for matches for that word as a substring. If it is a list of words,
709search for matches for any two (or more) of those words.
710
0820b753 711With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, also use
645c4f6a
KH
712documentation that is not stored in the documentation file and show key
713bindings.
714Returns list of symbols and documentation found."
0820b753
KS
715 (interactive (list (apropos-read-pattern "documentation")
716 current-prefix-arg))
3fefda51 717 (apropos-parse-pattern pattern)
645c4f6a
KH
718 (or do-all (setq do-all apropos-do-all))
719 (setq apropos-accumulator () apropos-files-scanned ())
720 (let ((standard-input (get-buffer-create " apropos-temp"))
0820b753 721 (apropos-sort-by-scores apropos-documentation-sort-by-scores)
7dbffb1c 722 f v sf sv)
645c4f6a
KH
723 (unwind-protect
724 (save-excursion
725 (set-buffer standard-input)
726 (apropos-documentation-check-doc-file)
727 (if do-all
728 (mapatoms
729 (lambda (symbol)
730 (setq f (apropos-safe-documentation symbol)
26a4a227
KH
731 v (get symbol 'variable-documentation))
732 (if (integerp v) (setq v))
733 (setq f (apropos-documentation-internal f)
734 v (apropos-documentation-internal v))
7dbffb1c
KS
735 (setq sf (apropos-score-doc f)
736 sv (apropos-score-doc v))
645c4f6a
KH
737 (if (or f v)
738 (if (setq apropos-item
739 (cdr (assq symbol apropos-accumulator)))
740 (progn
741 (if f
7dbffb1c
KS
742 (progn
743 (setcar (nthcdr 1 apropos-item) f)
744 (setcar apropos-item (+ (car apropos-item) sf))))
645c4f6a 745 (if v
7dbffb1c
KS
746 (progn
747 (setcar (nthcdr 2 apropos-item) v)
748 (setcar apropos-item (+ (car apropos-item) sv)))))
645c4f6a 749 (setq apropos-accumulator
71296446 750 (cons (list symbol
7dbffb1c
KS
751 (+ (apropos-score-symbol symbol 2) sf sv)
752 f v)
645c4f6a 753 apropos-accumulator)))))))
0820b753 754 (apropos-print nil "\n----------------\n" nil t))
645c4f6a
KH
755 (kill-buffer standard-input))))
756
757\f
758(defun apropos-value-internal (predicate symbol function)
759 (if (funcall predicate symbol)
760 (progn
761 (setq symbol (prin1-to-string (funcall function symbol)))
0820b753 762 (if (string-match apropos-regexp symbol)
645c4f6a
KH
763 (progn
764 (if apropos-match-face
765 (put-text-property (match-beginning 0) (match-end 0)
766 'face apropos-match-face
767 symbol))
768 symbol)))))
769
770(defun apropos-documentation-internal (doc)
771 (if (consp doc)
772 (apropos-documentation-check-elc-file (car doc))
0820b753
KS
773 (if (and doc
774 (string-match apropos-all-words-regexp doc)
775 (apropos-true-hit-doc doc))
776 (when apropos-match-face
777 (setq doc (substitute-command-keys (copy-sequence doc)))
778 (if (or (string-match apropos-pattern-quoted doc)
779 (string-match apropos-all-words-regexp doc))
780 (put-text-property (match-beginning 0)
781 (match-end 0)
782 'face apropos-match-face doc))
783 doc))))
645c4f6a
KH
784
785(defun apropos-format-plist (pl sep &optional compare)
3925e76d
KH
786 (setq pl (symbol-plist pl))
787 (let (p p-out)
788 (while pl
789 (setq p (format "%s %S" (car pl) (nth 1 pl)))
0820b753 790 (if (or (not compare) (string-match apropos-regexp p))
645c4f6a 791 (if apropos-property-face
3925e76d 792 (put-text-property 0 (length (symbol-name (car pl)))
645c4f6a 793 'face apropos-property-face p))
3925e76d 794 (setq p nil))
645c4f6a
KH
795 (if p
796 (progn
797 (and compare apropos-match-face
798 (put-text-property (match-beginning 0) (match-end 0)
799 'face apropos-match-face
800 p))
801 (setq p-out (concat p-out (if p-out sep) p))))
3925e76d
KH
802 (setq pl (nthcdr 2 pl)))
803 p-out))
804
6f8e447f 805
0820b753 806;; Finds all documentation related to APROPOS-REGEXP in internal-doc-file-name.
3925e76d 807
645c4f6a 808(defun apropos-documentation-check-doc-file ()
0820b753 809 (let (type symbol (sepa 2) sepb)
26a4a227
KH
810 (insert ?\^_)
811 (backward-char)
645c4f6a 812 (insert-file-contents (concat doc-directory internal-doc-file-name))
26a4a227
KH
813 (forward-char)
814 (while (save-excursion
815 (setq sepb (search-forward "\^_"))
816 (not (eobp)))
817 (beginning-of-line 2)
818 (if (save-restriction
819 (narrow-to-region (point) (1- sepb))
0820b753 820 (re-search-forward apropos-all-words-regexp nil t))
26a4a227 821 (progn
26a4a227 822 (goto-char (1+ sepa))
d2b30292
KS
823 (setq type (if (eq ?F (preceding-char))
824 2 ; function documentation
825 3) ; variable documentation
826 symbol (read)
d2b30292
KS
827 doc (buffer-substring (1+ (point)) (1- sepb)))
828 (when (apropos-true-hit-doc doc)
829 (or (and (setq apropos-item (assq symbol apropos-accumulator))
830 (setcar (cdr apropos-item)
0820b753 831 (apropos-score-doc doc)))
71296446 832 (setq apropos-item (list symbol
d2b30292
KS
833 (+ (apropos-score-symbol symbol 2)
834 (apropos-score-doc doc))
835 nil nil)
836 apropos-accumulator (cons apropos-item
837 apropos-accumulator)))
0820b753
KS
838 (when apropos-match-face
839 (setq doc (substitute-command-keys doc))
840 (if (or (string-match apropos-pattern-quoted doc)
841 (string-match apropos-all-words-regexp doc))
842 (put-text-property (match-beginning 0)
843 (match-end 0)
844 'face apropos-match-face doc)))
d2b30292 845 (setcar (nthcdr type apropos-item) doc))))
26a4a227 846 (setq sepa (goto-char sepb)))))
645c4f6a
KH
847
848(defun apropos-documentation-check-elc-file (file)
849 (if (member file apropos-files-scanned)
850 nil
26a4a227 851 (let (symbol doc beg end this-is-a-variable)
645c4f6a
KH
852 (setq apropos-files-scanned (cons file apropos-files-scanned))
853 (erase-buffer)
854 (insert-file-contents file)
855 (while (search-forward "\n#@" nil t)
856 ;; Read the comment length, and advance over it.
857 (setq end (read)
26a4a227
KH
858 beg (1+ (point))
859 end (+ (point) end -1))
860 (forward-char)
861 (if (save-restriction
862 ;; match ^ and $ relative to doc string
863 (narrow-to-region beg end)
0820b753 864 (re-search-forward apropos-all-words-regexp nil t))
645c4f6a 865 (progn
26a4a227
KH
866 (goto-char (+ end 2))
867 (setq doc (buffer-substring beg end)
868 end (- (match-end 0) beg)
d2b30292
KS
869 beg (- (match-beginning 0) beg))
870 (when (apropos-true-hit-doc doc)
871 (setq this-is-a-variable (looking-at "(def\\(var\\|const\\) ")
872 symbol (progn
873 (skip-chars-forward "(a-z")
874 (forward-char)
875 (read))
876 symbol (if (consp symbol)
877 (nth 1 symbol)
878 symbol))
879 (if (if this-is-a-variable
880 (get symbol 'variable-documentation)
881 (and (fboundp symbol) (apropos-safe-documentation symbol)))
882 (progn
883 (or (and (setq apropos-item (assq symbol apropos-accumulator))
884 (setcar (cdr apropos-item)
885 (+ (cadr apropos-item) (apropos-score-doc doc))))
886 (setq apropos-item (list symbol
887 (+ (apropos-score-symbol symbol 2)
888 (apropos-score-doc doc))
889 nil nil)
890 apropos-accumulator (cons apropos-item
891 apropos-accumulator)))
0820b753
KS
892 (when apropos-match-face
893 (setq doc (substitute-command-keys doc))
894 (if (or (string-match apropos-pattern-quoted doc)
895 (string-match apropos-all-words-regexp doc))
896 (put-text-property (match-beginning 0)
897 (match-end 0)
898 'face apropos-match-face doc)))
d2b30292
KS
899 (setcar (nthcdr (if this-is-a-variable 3 2)
900 apropos-item)
901 doc))))))))))
645c4f6a
KH
902
903
904
905(defun apropos-safe-documentation (function)
7a5348db 906 "Like `documentation', except it avoids calling `get_doc_string'.
6f8e447f 907Will return nil instead."
3925e76d 908 (while (and function (symbolp function))
6f8e447f 909 (setq function (if (fboundp function)
3925e76d 910 (symbol-function function))))
d2e1218f
RS
911 (if (eq (car-safe function) 'macro)
912 (setq function (cdr function)))
3925e76d 913 (setq function (if (byte-code-function-p function)
645c4f6a
KH
914 (if (> (length function) 4)
915 (aref function 4))
916 (if (eq (car-safe function) 'autoload)
917 (nth 2 function)
918 (if (eq (car-safe function) 'lambda)
919 (if (stringp (nth 2 function))
920 (nth 2 function)
921 (if (stringp (nth 3 function))
922 (nth 3 function)))))))
923 (if (integerp function)
924 nil
925 function))
926
1d69bd9b
SM
927(defcustom apropos-compact-layout nil
928 "If non-nil, use a single line per binding."
929 :type 'boolean)
645c4f6a 930
0820b753 931(defun apropos-print (do-keys spacing &optional text nosubst)
a9155e87
KH
932 "Output result of apropos searching into buffer `*Apropos*'.
933The value of `apropos-accumulator' is the list of items to output.
71296446 934Each element should have the format
7dbffb1c 935 (SYMBOL SCORE FN-DOC VAR-DOC [PLIST-DOC WIDGET-DOC FACE-DOC GROUP-DOC]).
a9155e87
KH
936The return value is the list that was in `apropos-accumulator', sorted
937alphabetically by symbol name; but this function also sets
9cc84e31
RS
938`apropos-accumulator' to nil before returning.
939
caa8e7aa
SM
940If SPACING is non-nil, it should be a string; separate items with that string.
941If non-nil TEXT is a string that will be printed as a heading."
645c4f6a 942 (if (null apropos-accumulator)
0820b753 943 (message "No apropos matches for `%s'" apropos-pattern)
645c4f6a 944 (setq apropos-accumulator
30aab741
RS
945 (sort apropos-accumulator
946 (lambda (a b)
947 ;; Don't sort by score if user can't see the score.
948 ;; It would be confusing. -- rms.
ab765ff7 949 (if apropos-sort-by-scores
30aab741
RS
950 (or (> (cadr a) (cadr b))
951 (and (= (cadr a) (cadr b))
952 (string-lessp (car a) (car b))))
953 (string-lessp (car a) (car b))))))
09e32aaf 954 (with-output-to-temp-buffer "*Apropos*"
645c4f6a 955 (let ((p apropos-accumulator)
3925e76d 956 (old-buffer (current-buffer))
e517f56d 957 symbol item)
26a4a227
KH
958 (set-buffer standard-output)
959 (apropos-mode)
a2ee7919 960 (if (display-mouse-p)
8d33699b
EZ
961 (insert
962 "If moving the mouse over text changes the text's color, "
963 "you can click\n"
964 "mouse-2 (second button from right) on that text to "
965 "get more information.\n"))
53a7d078 966 (insert "In this buffer, go to the name of the command, or function,"
d94d5b5a
EZ
967 " or variable,\n"
968 (substitute-command-keys
969 "and type \\[apropos-follow] to get full documentation.\n\n"))
caa8e7aa 970 (if text (insert text "\n\n"))
671c04d9 971 (dolist (apropos-item p)
9cc84e31
RS
972 (when (and spacing (not (bobp)))
973 (princ spacing))
671c04d9 974 (setq symbol (car apropos-item))
0820b753
KS
975 ;; Insert dummy score element for backwards compatibility with 21.x
976 ;; apropos-item format.
977 (if (not (numberp (cadr apropos-item)))
978 (setq apropos-item
979 (cons (car apropos-item)
980 (cons nil (cdr apropos-item)))))
e517f56d
MB
981 (insert-text-button (symbol-name symbol)
982 'type 'apropos-symbol
983 ;; Can't use default, since user may have
984 ;; changed the variable!
985 ;; Just say `no' to variables containing faces!
986 'face apropos-symbol-face)
0820b753
KS
987 (if (and (eq apropos-sort-by-scores 'verbose)
988 (cadr apropos-item))
7dbffb1c 989 (insert " (" (number-to-string (cadr apropos-item)) ") "))
98ce2330 990 ;; Calculate key-bindings if we want them.
1d69bd9b
SM
991 (unless apropos-compact-layout
992 (and do-keys
993 (commandp symbol)
994 (not (eq symbol 'self-insert-command))
995 (indent-to 30 1)
996 (if (let ((keys
997 (with-current-buffer old-buffer
998 (where-is-internal symbol)))
999 filtered)
1000 ;; Copy over the list of key sequences,
1001 ;; omitting any that contain a buffer or a frame.
1002 ;; FIXME: Why omit keys that contain buffers and
1003 ;; frames? This looks like a bad workaround rather
1004 ;; than a proper fix. Does anybod know what problem
1005 ;; this is trying to address? --Stef
1006 (dolist (key keys)
1007 (let ((i 0)
1008 loser)
1009 (while (< i (length key))
1010 (if (or (framep (aref key i))
1011 (bufferp (aref key i)))
1012 (setq loser t))
1013 (setq i (1+ i)))
1014 (or loser
1015 (push key filtered))))
1016 (setq item filtered))
1017 ;; Convert the remaining keys to a string and insert.
1018 (insert
1019 (mapconcat
1020 (lambda (key)
1021 (setq key (condition-case ()
1022 (key-description key)
1023 (error)))
1024 (if apropos-keybinding-face
1025 (put-text-property 0 (length key)
1026 'face apropos-keybinding-face
1027 key))
1028 key)
1029 item ", "))
1030 (insert "M-x ... RET")
1031 (when apropos-keybinding-face
1032 (put-text-property (- (point) 11) (- (point) 8)
1033 'face apropos-keybinding-face)
1034 (put-text-property (- (point) 3) (point)
1035 'face apropos-keybinding-face))))
1036 (terpri))
7dbffb1c 1037 (apropos-print-doc 2
26a4a227 1038 (if (commandp symbol)
894e460c 1039 'apropos-command
26a4a227 1040 (if (apropos-macrop symbol)
894e460c
MB
1041 'apropos-macro
1042 'apropos-function))
0820b753
KS
1043 (not nosubst))
1044 (apropos-print-doc 3 'apropos-variable (not nosubst))
7dbffb1c
KS
1045 (apropos-print-doc 7 'apropos-group t)
1046 (apropos-print-doc 6 'apropos-face t)
1047 (apropos-print-doc 5 'apropos-widget t)
1048 (apropos-print-doc 4 'apropos-plist nil))
1d69bd9b
SM
1049 (set (make-local-variable 'truncate-partial-width-windows) t)
1050 (set (make-local-variable 'truncate-lines) t)
a9155e87 1051 (setq buffer-read-only t))))
645c4f6a
KH
1052 (prog1 apropos-accumulator
1053 (setq apropos-accumulator ()))) ; permit gc
1054
645c4f6a 1055(defun apropos-macrop (symbol)
b965722b 1056 "Return t if SYMBOL is a Lisp macro."
645c4f6a
KH
1057 (and (fboundp symbol)
1058 (consp (setq symbol
1059 (symbol-function symbol)))
1060 (or (eq (car symbol) 'macro)
1061 (if (eq (car symbol) 'autoload)
1062 (memq (nth 4 symbol)
1063 '(macro t))))))
3925e76d 1064
645c4f6a 1065
894e460c 1066(defun apropos-print-doc (i type do-keys)
671c04d9 1067 (when (stringp (setq i (nth i apropos-item)))
1d69bd9b
SM
1068 (if apropos-compact-layout
1069 (insert (propertize "\t" 'display '(space :align-to 32)) " ")
1070 (insert " "))
1071 ;; If the query is only for a single type, there's
1072 ;; no point writing it over and over again.
1073 (when apropos-multi-type
1074 (insert-text-button
1075 (if apropos-compact-layout
1076 (button-type-get type 'apropos-label)
1077 (format "<%s>" (button-type-get type 'apropos-short-label)))
1078 'type type
1079 ;; Can't use the default button face, since user may have changed the
1080 ;; variable! Just say `no' to variables containing faces!
1081 'face apropos-label-face
1082 'apropos-symbol (car apropos-item))
1083 (insert (if apropos-compact-layout " " ": ")))
1084 (insert (if do-keys (substitute-command-keys i) i))
671c04d9 1085 (or (bolp) (terpri))))
3925e76d 1086
e517f56d
MB
1087(defun apropos-follow ()
1088 "Invokes any button at point, otherwise invokes the nearest label button."
3925e76d 1089 (interactive)
e517f56d
MB
1090 (button-activate
1091 (or (apropos-next-label-button (line-beginning-position))
1092 (error "There is nothing to follow here"))))
3925e76d
KH
1093
1094
1095(defun apropos-describe-plist (symbol)
1096 "Display a pretty listing of SYMBOL's plist."
caa8e7aa 1097 (help-setup-xref (list 'apropos-describe-plist symbol) (interactive-p))
c6808785 1098 (with-help-window (help-buffer)
3925e76d
KH
1099 (set-buffer standard-output)
1100 (princ "Symbol ")
1101 (prin1 symbol)
1102 (princ "'s plist is\n (")
645c4f6a 1103 (if apropos-symbol-face
caa8e7aa
SM
1104 (put-text-property (+ (point-min) 7) (- (point) 14)
1105 'face apropos-symbol-face))
3925e76d 1106 (insert (apropos-format-plist symbol "\n "))
c6808785 1107 (princ ")")))
6f8e447f 1108
e517f56d 1109
896546cd
RS
1110(provide 'apropos)
1111
cbee283d 1112;; arch-tag: d56fa2ac-e56b-4ce3-84ff-852f9c0dc66e
c0274f38 1113;;; apropos.el ends here