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