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