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