(A-GT-K02849): New abstract node; unify A-U+8FB0-itaiji-001.
[chise/xemacs-chise.git.1] / lisp / apropos.el
1 ;;; apropos.el --- apropos commands for users and programmers.
2
3 ;; Copyright (C) 1989, 1994, 1995 Free Software Foundation, Inc.
4
5 ;; Author: Joe Wells <jbw@bigbird.bu.edu>
6 ;; Rewritten: Daniel.Pfeiffer@Informatik.START.dbp.de, fax (+49 69) 7588-2389
7 ;; Maintainer: SL Baur <steve@xemacs.org>
8 ;; Keywords: help
9
10 ;; This file is part of XEmacs.
11
12 ;; XEmacs is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; XEmacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26
27 ;;; Synched up with: Last synched with FSF 19.34, diverged since.
28
29 ;;; Commentary:
30
31 ;; The ideas for this package were derived from the C code in
32 ;; src/keymap.c and elsewhere.  The functions in this file should
33 ;; always be byte-compiled for speed.  Someone should rewrite this in
34 ;; C (as part of src/keymap.c) for speed.
35
36 ;; The idea for super-apropos is based on the original implementation
37 ;; by Lynn Slater <lrs@esl.com>.
38
39 ;;; ChangeLog:
40
41 ;; Fixed bug, current-local-map can return nil.
42 ;; Change, doesn't calculate key-bindings unless needed.
43 ;; Added super-apropos capability, changed print functions.
44 ;;; Made fast-apropos and super-apropos share code.
45 ;;; Sped up fast-apropos again.
46 ;; Added apropos-do-all option.
47 ;;; Added fast-command-apropos.
48 ;; Changed doc strings to comments for helping functions.
49 ;;; Made doc file buffer read-only, buried it.
50 ;; Only call substitute-command-keys if do-all set.
51
52 ;; Optionally use configurable faces to make the output more legible.
53 ;; Differentiate between command, function and macro.
54 ;; Apropos-command (ex command-apropos) does cmd and optionally user var.
55 ;; Apropos shows all 3 aspects of symbols (fn, var and plist)
56 ;; Apropos-documentation (ex super-apropos) now finds all it should.
57 ;; New apropos-value snoops through all values and optionally plists.
58 ;; Reading DOC file doesn't load nroff.
59 ;; Added hypertext following of documentation, mouse-2 on variable gives value
60 ;;   from buffer in active window.
61
62 ;;; Code:
63
64 ;; I see a degradation of maybe 10-20% only.
65 ;; [sb -- FSF protects the face declarations with `if window-system'
66 ;;  I see no reason why we should do so]
67 (defvar apropos-do-all nil
68   "*Whether the apropos commands should do more.
69 Slows them down more or less.  Set this non-nil if you have a fast machine.")
70
71 ;; XEmacs addition
72 (defvar apropos-symbol-face (if (boundp 'font-lock-keyword-face)
73                                 font-lock-keyword-face
74                               'bold)
75   "*Face for symbol name in apropos output or `nil'.
76 This looks good, but slows down the commands several times.")
77
78 ;; XEmacs addition
79 (defvar apropos-keybinding-face (if (boundp 'font-lock-string-face)
80                                     font-lock-string-face
81                                   'underline)
82   "*Face for keybinding display in apropos output or `nil'.
83 This looks good, but slows down the commands several times.")
84
85 ;; XEmacs addition
86 (defvar apropos-label-face (if (boundp 'font-lock-comment-face)
87                                font-lock-comment-face
88                              'italic)
89   "*Face for label (Command, Variable ...) in apropos output or `nil'.
90 If this is `nil' no mouse highlighting occurs.
91 This looks good, but slows down the commands several times.
92 When this is a face name, as it is initially, it gets transformed to a
93 text-property list for efficiency.")
94
95 ;; XEmacs addition
96 (defvar apropos-property-face (if (boundp 'font-lock-variable-name-face)
97                                   font-lock-variable-name-face
98                                 'bold-italic)
99   "*Face for property name in apropos output or `nil'.
100 This looks good, but slows down the commands several times.")
101
102 (defvar apropos-match-face 'secondary-selection
103   "*Face for matching part in apropos-documentation/value output or `nil'.
104 This looks good, but slows down the commands several times.")
105
106
107 (defvar apropos-mode-map
108   (let ((map (make-sparse-keymap)))
109     (define-key map [(control m)] 'apropos-follow)
110     (define-key map [return] 'apropos-follow)
111     (define-key map [(button2up)] 'apropos-mouse-follow)
112     (define-key map [(button2)] 'undefined)
113     map)
114   "Keymap used in Apropos mode.")
115
116
117 (defvar apropos-regexp nil
118   "Regexp used in current apropos run.")
119
120 (defvar apropos-files-scanned ()
121   "List of elc files already scanned in current run of `apropos-documentation'.")
122
123 (defvar apropos-accumulator ()
124   "Alist of symbols already found in current apropos run.")
125
126 (defvar apropos-item ()
127   "Current item in or for apropos-accumulator.")
128 \f
129 (defvar apropos-mode-hook nil) ; XEmacs
130
131 (defun apropos-mode ()
132   "Major mode for following hyperlinks in output of apropos commands.
133
134 \\{apropos-mode-map}"
135   (interactive)
136   (kill-all-local-variables)
137   (use-local-map apropos-mode-map)
138   (setq major-mode 'apropos-mode
139         mode-name "Apropos")
140   (run-hooks 'apropos-mode-hook)) ; XEmacs
141
142
143 ;; For auld lang syne:
144 ;;;###autoload
145 (fset 'command-apropos 'apropos-command)
146
147 ;;;###autoload
148 (defun apropos-command (apropos-regexp &optional do-all)
149   "Shows commands (interactively callable functions) that match REGEXP.
150 With optional prefix ARG or if `apropos-do-all' is non-nil, also show
151 variables."
152   ;; XEmacs: All code related to special treatment of buffer has been removed
153   (interactive (list (read-string (concat "Apropos command "
154                                           (if (or current-prefix-arg
155                                                   apropos-do-all)
156                                               "or variable ")
157                                           "(regexp): "))
158                      current-prefix-arg))
159   (or do-all (setq do-all apropos-do-all))
160   (setq apropos-accumulator
161         (apropos-internal apropos-regexp
162                           (if do-all
163                               (lambda (symbol) (or (commandp symbol)
164                                                    (user-variable-p symbol)))
165                             'commandp)))
166   (apropos-print
167    t
168    (lambda (p)
169      (let (doc symbol)
170        (while p
171          (setcar p (list
172                     (setq symbol (car p))
173                     (if (commandp symbol)
174                         (if (setq doc
175                                   ;; XEmacs change: if obsolete,
176                                   ;; only mention that.
177                                   (or (function-obsoleteness-doc symbol)
178                                       (condition-case nil
179                                           (documentation symbol t)
180                                         (void-function "(aliased to undefined function)")
181                                         (error "(unexpected error from `documention')"))))
182                             (substring doc 0 (string-match "\n" doc))
183                           "(not documented)"))
184                     (and do-all
185                          (user-variable-p symbol)
186                          (if (setq doc
187                                    (or
188                                     ;; XEmacs change: if obsolete,
189                                     ;; only mention that.
190                                     (variable-obsoleteness-doc symbol)
191                                     (documentation-property
192                                      symbol 'variable-documentation t)))
193                              (substring doc 0
194                                             (string-match "\n" doc))))))
195          (setq p (cdr p)))))
196    nil))
197
198
199 ;;;###autoload
200 (defun apropos (apropos-regexp &optional do-all)
201   "Show all bound symbols whose names match REGEXP.
202 With optional prefix ARG or if `apropos-do-all' is non-nil, also show unbound
203 symbols and key bindings, which is a little more time-consuming.
204 Returns list of symbols and documentation found."
205   (interactive "sApropos symbol (regexp): \nP")
206   ;; XEmacs change: hitting ENTER by mistake is a common mess-up and
207   ;; shouldn't make Emacs hang for a long time trying to list all symbols.
208   (or (> (length apropos-regexp) 0)
209       (error "Must pass non-empty regexp to `apropos'"))
210   (setq apropos-accumulator
211         (apropos-internal apropos-regexp
212                           (and (not do-all)
213                                (not apropos-do-all)
214                                (lambda (symbol)
215                                  (or (fboundp symbol)
216                                      (boundp symbol)
217                                      (find-face symbol)
218                                      (symbol-plist symbol))))))
219   (apropos-print
220    (or do-all apropos-do-all)
221    (lambda (p)
222      (let (symbol doc)
223        (while p
224          (setcar p (list
225                     (setq symbol (car p))
226                     (if (fboundp symbol)
227                         (if (setq doc
228                                   ;; XEmacs change: if obsolete,
229                                   ;; only mention that.
230                                   (or (function-obsoleteness-doc symbol)
231                                       (condition-case nil
232                                           (documentation symbol t)
233                                         (void-function "(aliased to undefined function)")
234                                         (error "(unexpected error from `documention')"))))
235                             (substring doc 0 (string-match "\n" doc))
236                           "(not documented)"))
237                     (if (boundp symbol)
238                         (if (setq doc
239                                   (or
240                                    ;; XEmacs change: if obsolete,
241                                    ;; only mention that.
242                                    (variable-obsoleteness-doc symbol)
243                                    (documentation-property
244                                     symbol 'variable-documentation t)))
245                             (substring doc 0
246                                        (string-match "\n" doc))
247                           "(not documented)"))
248                     (if (setq doc (symbol-plist symbol))
249                         (if (eq (/ (length doc) 2) 1)
250                             (format "1 property (%s)" (car doc))
251                           (format "%d properties" (/ (length doc) 2))))
252                     (if (get symbol 'widget-type)
253                         (if (setq doc (documentation-property
254                                        symbol 'widget-documentation t))
255                             (substring doc 0
256                                        (string-match "\n" doc))
257                           "(not documented)"))
258                     (if (find-face symbol)
259                         (if (setq doc (face-doc-string symbol))
260                             (substring doc 0
261                                        (string-match "\n" doc))
262                           "(not documented)"))
263                     (when (get symbol 'custom-group)
264                       (if (setq doc (documentation-property
265                                      symbol 'group-documentation t))
266                           (substring doc 0
267                                      (string-match "\n" doc))
268                         "(not documented)"))))
269          (setq p (cdr p)))))
270    nil))
271
272
273 ;;;###autoload
274 (defun apropos-value (apropos-regexp &optional do-all)
275   "Show all symbols whose value's printed image matches REGEXP.
276 With optional prefix ARG or if `apropos-do-all' is non-nil, also looks
277 at the function and at the names and values of properties.
278 Returns list of symbols and values found."
279   (interactive "sApropos value (regexp): \nP")
280   (or do-all (setq do-all apropos-do-all))
281   (setq apropos-accumulator ())
282    (let (f v p)
283      (mapatoms
284       (lambda (symbol)
285         (setq f nil v nil p nil)
286         (or (memq symbol '(apropos-regexp do-all apropos-accumulator
287                                           symbol f v p))
288             (setq v (apropos-value-internal 'boundp symbol 'symbol-value)))
289         (if do-all
290             (setq f (apropos-value-internal 'fboundp symbol 'symbol-function)
291                   p (apropos-format-plist symbol "\n    " t)))
292         (if (or f v p)
293             (setq apropos-accumulator (cons (list symbol f v p)
294                                             apropos-accumulator))))))
295   (apropos-print nil nil t))
296
297
298 ;;;###autoload
299 (defun apropos-documentation (apropos-regexp &optional do-all)
300   "Show symbols whose documentation contain matches for REGEXP.
301 With optional prefix ARG or if `apropos-do-all' is non-nil, also use
302 documentation that is not stored in the documentation file and show key
303 bindings.
304 Returns list of symbols and documentation found."
305   (interactive "sApropos documentation (regexp): \nP")
306   (or do-all (setq do-all apropos-do-all))
307   (setq apropos-accumulator () apropos-files-scanned ())
308   (let ((standard-input (get-buffer-create " apropos-temp"))
309         f v)
310     (unwind-protect
311         (save-excursion
312           (set-buffer standard-input)
313           (apropos-documentation-check-doc-file)
314           (if do-all
315               (mapatoms
316                (lambda (symbol)
317                  (setq f (apropos-safe-documentation symbol)
318                        v (get symbol 'variable-documentation))
319                  (when (integerp v) (setq v nil))
320                  (setq f (apropos-documentation-internal f)
321                        v (apropos-documentation-internal v))
322                  (if (or f v)
323                      (if (setq apropos-item
324                                (cdr (assq symbol apropos-accumulator)))
325                          (progn
326                            (if f
327                                (setcar apropos-item f))
328                            (if v
329                                (setcar (cdr apropos-item) v)))
330                        (setq apropos-accumulator
331                              (cons (list symbol f v)
332                                    apropos-accumulator)))))))
333           (apropos-print nil nil t))
334       (kill-buffer standard-input))))
335
336 \f
337 (defun apropos-value-internal (predicate symbol function)
338   (if (funcall predicate symbol)
339       (progn
340         (setq symbol (prin1-to-string (funcall function symbol)))
341         (if (string-match apropos-regexp symbol)
342             (progn
343               (if apropos-match-face
344                   (put-text-property (match-beginning 0) (match-end 0)
345                                      'face apropos-match-face
346                                      symbol))
347               symbol)))))
348
349 (defun apropos-documentation-internal (doc)
350   (if (consp doc)
351       (apropos-documentation-check-elc-file (car doc))
352     (and doc
353          (string-match apropos-regexp doc)
354          (progn
355            (if apropos-match-face
356                (put-text-property (match-beginning 0)
357                                   (match-end 0)
358                                   'face apropos-match-face
359                                   (setq doc (copy-sequence doc))))
360            doc))))
361
362 (defun apropos-format-plist (pl sep &optional compare)
363   (setq pl (symbol-plist pl))
364   (let (p p-out)
365     (while pl
366       (setq p (format "%s %S" (car pl) (nth 1 pl)))
367       (if (or (not compare) (string-match apropos-regexp p))
368           (if apropos-property-face
369               (put-text-property 0 (length (symbol-name (car pl)))
370                                  'face apropos-property-face p))
371         (setq p nil))
372       (if p
373           (progn
374             (and compare apropos-match-face
375                  (put-text-property (match-beginning 0) (match-end 0)
376                                     'face apropos-match-face
377                                     p))
378             (setq p-out (concat p-out (if p-out sep) p))))
379       (setq pl (nthcdr 2 pl)))
380     p-out))
381
382
383 ;; Finds all documentation related to APROPOS-REGEXP in internal-doc-file-name.
384
385 (defun apropos-documentation-check-doc-file ()
386   (let (type symbol (sepa 2) sepb start end doc)
387     (insert ?\^_)
388     (backward-char)
389     (insert-file-contents (concat doc-directory internal-doc-file-name))
390     (forward-char)
391     (while (save-excursion
392              (setq sepb (search-forward "\^_"))
393              (not (eobp)))
394       (beginning-of-line 2)
395       (if (save-restriction
396             (narrow-to-region (point) (1- sepb))
397             (re-search-forward apropos-regexp nil t))
398           (progn
399             (setq start (match-beginning 0)
400                   end (point))
401             (goto-char (1+ sepa))
402             (or (setq type (if (eq ?F (preceding-char))
403                                1        ; function documentation
404                              2)         ; variable documentation
405                       symbol (read)
406                       start (- start (point) 1)
407                       end (- end (point) 1)
408                       doc (buffer-substring (1+ (point)) (1- sepb))
409                       apropos-item (assq symbol apropos-accumulator))
410                 (setq apropos-item (list symbol nil nil)
411                       apropos-accumulator (cons apropos-item
412                                                 apropos-accumulator)))
413             (if apropos-match-face
414                 (put-text-property start end 'face apropos-match-face doc))
415             (setcar (nthcdr type apropos-item) doc)))
416       (setq sepa (goto-char sepb)))))
417
418 (defun apropos-documentation-check-elc-file (file)
419   (if (member file apropos-files-scanned)
420       nil
421     (let (symbol doc start end this-is-a-variable)
422       (setq apropos-files-scanned (cons file apropos-files-scanned))
423       (erase-buffer)
424       (insert-file-contents file)
425       (while (search-forward "\n#@" nil t)
426         ;; Read the comment length, and advance over it.
427         (setq end (read)
428               start (1+ (point))
429               end (+ (point) end -1))
430         (forward-char)
431         (if (save-restriction
432               ;; match ^ and $ relative to doc string
433               (narrow-to-region start end)
434               (re-search-forward apropos-regexp nil t))
435             (progn
436               (goto-char (+ end 2))
437               (setq doc (buffer-substring start end)
438                     end (- (match-end 0) start)
439                     start (- (match-beginning 0) start)
440                     this-is-a-variable (looking-at "(def\\(var\\|const\\) ")
441                     symbol (progn
442                              (skip-chars-forward "(a-z")
443                              (forward-char)
444                              (read))
445                     symbol (if (consp symbol)
446                                (nth 1 symbol)
447                              symbol))
448               (if (if this-is-a-variable
449                       (get symbol 'variable-documentation)
450                     (and (fboundp symbol) (apropos-safe-documentation symbol)))
451                   (progn
452                     (or (setq apropos-item (assq symbol apropos-accumulator))
453                         (setq apropos-item (list symbol nil nil)
454                               apropos-accumulator (cons apropos-item
455                                                         apropos-accumulator)))
456                     (if apropos-match-face
457                         (put-text-property start end 'face apropos-match-face
458                                            doc))
459                     (setcar (nthcdr (if this-is-a-variable 2 1)
460                                     apropos-item)
461                             doc)))))))))
462
463
464
465 (defun apropos-safe-documentation (function)
466   "Like documentation, except it avoids calling `get_doc_string'.
467 Will return nil instead."
468   (while (and function (symbolp function))
469     (setq function (if (fboundp function)
470                        (symbol-function function))))
471   (if (eq (car-safe function) 'macro)
472       (setq function (cdr function)))
473   ;; XEmacs change from: (setq function (if (byte-code-function-p function)
474   (setq function (if (compiled-function-p function)
475                      (if (fboundp 'compiled-function-doc-string)
476                          (compiled-function-doc-string function)
477                        (if (> (length function) 4)
478                            (aref function 4)))
479                    (if (eq (car-safe function) 'autoload)
480                        (nth 2 function)
481                      (if (eq (car-safe function) 'lambda)
482                          (if (stringp (nth 2 function))
483                              (nth 2 function)
484                            (if (stringp (nth 3 function))
485                                (nth 3 function)))))))
486   (if (integerp function)
487       nil
488     function))
489
490
491
492 (defun apropos-print (do-keys doc-fn spacing)
493   "Output result of various apropos commands with `apropos-regexp'.
494 APROPOS-ACCUMULATOR is a list.  Optional DOC-FN is called for each element
495 of apropos-accumulator and may modify it resulting in (symbol fn-doc
496 var-doc [plist-doc]).  Returns sorted list of symbols and documentation
497 found."
498   (if (null apropos-accumulator)
499       (message "No apropos matches for `%s'" apropos-regexp)
500     (if doc-fn
501         (funcall doc-fn apropos-accumulator))
502     (setq apropos-accumulator
503           (sort apropos-accumulator (lambda (a b)
504                                       (string-lessp (car a) (car b)))))
505     (and apropos-label-face
506          (or (symbolp apropos-label-face)
507              (facep apropos-label-face)) ; XEmacs
508          (setq apropos-label-face `(face ,apropos-label-face
509                                          mouse-face highlight)))
510     (let ((help-buffer-prefix-string "Apropos"))
511       (with-displaying-help-buffer
512        (lambda ()
513          (with-current-buffer standard-output
514            (run-hooks 'apropos-mode-hook)
515            (let ((p apropos-accumulator)
516                  (old-buffer (current-buffer))
517                  symbol item point1 point2)
518              ;; Mostly useless but to provide better keymap
519              ;; explanation. help-mode-map will be used instead.
520              (use-local-map apropos-mode-map)
521              ;; XEmacs change from (if window-system
522              (if (device-on-window-system-p)
523                  (progn
524                    (princ "If you move the mouse over text that changes color,\n")
525                    (princ (substitute-command-keys
526                            "you can click \\[apropos-mouse-follow] to get more information.\n"))))
527              (princ (substitute-command-keys
528                      "Type \\[apropos-follow] in this buffer to get full documentation.\n\n"))
529              (while (consp p)
530                (or (not spacing) (bobp) (terpri))
531                (setq apropos-item (car p)
532                      symbol (car apropos-item)
533                      p (cdr p)
534                      point1 (point))
535                (princ symbol)           ; print symbol name
536                (setq point2 (point))
537                ;; Calculate key-bindings if we want them.
538                (and do-keys
539                     (commandp symbol)
540                     (indent-to 30 1)
541                     (if (let ((keys
542                                (save-excursion
543                                  (set-buffer old-buffer)
544                                  (where-is-internal symbol)))
545                               filtered)
546                           ;; Copy over the list of key sequences,
547                           ;; omitting any that contain a buffer or a frame.
548                           (while keys
549                             (let ((key (car keys))
550                                   (i 0)
551                                   loser)
552                               (while (< i (length key))
553                                 (if (or (framep (aref key i))
554                                         (bufferp (aref key i)))
555                                     (setq loser t))
556                                 (setq i (1+ i)))
557                               (or loser
558                                   (setq filtered (cons key filtered))))
559                             (setq keys (cdr keys)))
560                           (setq item filtered))
561                         ;; Convert the remaining keys to a string and insert.
562                         (princ
563                          (mapconcat
564                           (lambda (key)
565                             (setq key (key-description key))
566                             (if apropos-keybinding-face
567                                 (put-text-property 0 (length key)
568                                                    'face apropos-keybinding-face
569                                                    key))
570                             key)
571                           item ", "))
572                       (princ "Type ")
573                       (princ "M-x")
574                       (put-text-property (- (point) 3) (point)
575                                          'face apropos-keybinding-face)
576                       (princ (format " %s " (symbol-name symbol)))
577                       (princ "RET")
578                       (put-text-property (- (point) 3) (point)
579                                          'face apropos-keybinding-face)))
580                (terpri)
581                ;; only now so we don't propagate text attributes all over
582                (put-text-property point1 point2 'item
583                                   (if (eval `(or ,@(cdr apropos-item)))
584                                       (car apropos-item)
585                                     apropos-item))
586                (if apropos-symbol-face
587                    (put-text-property point1 point2 'face apropos-symbol-face))
588                ;; Add text-property on symbol, too.
589                (put-text-property point1 point2 'keymap apropos-mode-map)
590                (apropos-print-doc 'describe-function 1
591                                   (if (commandp symbol)
592                                       "Command"
593                                     (if (apropos-macrop symbol)
594                                         "Macro"
595                                       "Function"))
596                                   do-keys)
597                (if (get symbol 'custom-type)
598                    (apropos-print-doc 'customize-variable-other-window 2
599                                       "User Option" do-keys)
600                  (apropos-print-doc 'describe-variable 2
601                                     "Variable" do-keys))
602                (apropos-print-doc 'customize-other-window 6 "Group" do-keys)
603                (apropos-print-doc 'customize-face-other-window 5 "Face" do-keys)
604                (apropos-print-doc 'widget-browse-other-window 4 "Widget" do-keys)
605                (apropos-print-doc 'apropos-describe-plist 3
606                                   "Plist" nil)))))
607        apropos-regexp))
608     (prog1 apropos-accumulator
609       (setq apropos-accumulator ()))))  ; permit gc
610
611
612 (defun apropos-macrop (symbol)
613   "Return t if SYMBOL is a Lisp macro."
614   (and (fboundp symbol)
615        (consp (setq symbol
616                     (symbol-function symbol)))
617        (or (eq (car symbol) 'macro)
618            (if (eq (car symbol) 'autoload)
619                (memq (nth 4 symbol)
620                      '(macro t))))))
621
622
623 (defun apropos-print-doc (action i str do-keys)
624   (with-current-buffer standard-output
625     (if (stringp (setq i (nth i apropos-item)))
626         (progn
627           (insert "  ")
628           (put-text-property (- (point) 2) (1- (point))
629                              'action action)
630           (insert str ": ")
631           (if apropos-label-face
632               (add-text-properties (- (point) (length str) 2)
633                                    (1- (point))
634                                    apropos-label-face))
635           (add-text-properties (- (point) (length str) 2)
636                                (1- (point))
637                                (list 'keymap apropos-mode-map))
638           (insert (if do-keys (substitute-command-keys i) i))
639           (or (bolp) (terpri))))))
640
641 (defun apropos-mouse-follow (event)
642   (interactive "e")
643   ;; XEmacs change:  We're using the standard help buffer code now, don't
644   ;; do special tricks about trying to preserve current-buffer about mouse
645   ;; clicks.
646
647   (save-excursion
648     ;; XEmacs change from:
649     ;; (set-buffer (window-buffer (posn-window (event-start event))))
650     ;; (goto-char (posn-point (event-start event)))
651     (set-buffer (event-buffer event))
652     (goto-char (event-closest-point event))
653     ;; XEmacs change: following code seems useless
654     ;;(or (and (not (eobp)) (get-text-property (point) 'mouse-face))
655     ;;    (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
656     ;;    (error "There is nothing to follow here"))
657     (apropos-follow)))
658
659
660 (defun apropos-follow (&optional other)
661   (interactive)
662   (let* (;; Properties are always found at the beginning of the line.
663          (bol (save-excursion (beginning-of-line) (point)))
664          ;; If there is no `item' property here, look behind us.
665          (item (get-text-property bol 'item))
666          (item-at (if item nil (previous-single-property-change bol 'item)))
667          ;; Likewise, if there is no `action' property here, look in front.
668          (action (get-text-property bol 'action))
669          (action-at (if action nil (next-single-property-change bol 'action))))
670     (and (null item) item-at
671          (setq item (get-text-property (1- item-at) 'item)))
672     (and (null action) action-at
673          (setq action (get-text-property action-at 'action)))
674     (if (not (and item action))
675         (error "There is nothing to follow here"))
676     (if (consp item) (error "There is nothing to follow in `%s'" (car item)))
677     (if other (set-buffer other))
678     (funcall action item)))
679
680
681
682 (defun apropos-describe-plist (symbol)
683   "Display a pretty listing of SYMBOL's plist."
684   (let ((help-buffer-prefix-string "Apropos-plist"))
685     (with-displaying-help-buffer
686      (lambda ()
687        (run-hooks 'apropos-mode-hook)
688        (princ "Symbol ")
689        (prin1 symbol)
690        (princ "'s plist is\n (")
691        (with-current-buffer standard-output
692          (if apropos-symbol-face
693              (put-text-property 8 (- (point) 14) 'face apropos-symbol-face)))
694        (princ (apropos-format-plist symbol "\n  "))
695        (princ ")")
696        (terpri)
697        (print-help-return-message))
698      (symbol-name symbol))))
699
700 (provide 'apropos) ; XEmacs
701
702 ;;; apropos.el ends here