(dired-at-point-prompter): Improve prompt in
[bpt/emacs.git] / lisp / help-mode.el
CommitLineData
f4ed5b19
MB
1;;; help-mode.el --- `help-mode' used by *Help* buffers
2
0d30b337 3;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000, 2001, 2002,
d7a0267c 4;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
f4ed5b19
MB
5
6;; Maintainer: FSF
7;; Keywords: help, internal
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
f4ed5b19
MB
25
26;;; Commentary:
27
28;; Defines `help-mode', which is the mode used by *Help* buffers, and
29;; associated support machinery, such as adding hyperlinks, etc.,
30
31;;; Code:
32
33(require 'button)
410e58b5 34(require 'view)
f4ed5b19
MB
35
36(defvar help-mode-map (make-sparse-keymap)
37 "Keymap for help mode.")
38
39(set-keymap-parent help-mode-map button-buffer-map)
40
89f5b33f 41(define-key help-mode-map [mouse-2] 'help-follow-mouse)
f4ed5b19 42(define-key help-mode-map "\C-c\C-b" 'help-go-back)
95f731db 43(define-key help-mode-map "\C-c\C-f" 'help-go-forward)
8a31f813 44(define-key help-mode-map "\C-c\C-c" 'help-follow-symbol)
f4ed5b19
MB
45;; Documentation only, since we use minor-mode-overriding-map-alist.
46(define-key help-mode-map "\r" 'help-follow)
47
48(defvar help-xref-stack nil
49 "A stack of ways by which to return to help buffers after following xrefs.
50Used by `help-follow' and `help-xref-go-back'.
89f5b33f
SM
51An element looks like (POSITION FUNCTION ARGS...).
52To use the element, do (apply FUNCTION ARGS) then goto the point.")
f4ed5b19 53(put 'help-xref-stack 'permanent-local t)
89f5b33f 54(make-variable-buffer-local 'help-xref-stack)
f4ed5b19 55
95f731db
NR
56(defvar help-xref-forward-stack nil
57 "The stack of used to navigate help forwards after using the back button.
58Used by `help-follow' and `help-xref-go-forward'.
59An element looks like (POSITION FUNCTION ARGS...).
60To use the element, do (apply FUNCTION ARGS) then goto the point.")
61(put 'help-xref-forward-stack 'permanent-local t)
62(make-variable-buffer-local 'help-xref-forward-stack)
63
f4ed5b19
MB
64(defvar help-xref-stack-item nil
65 "An item for `help-follow' in this buffer to push onto `help-xref-stack'.
66The format is (FUNCTION ARGS...).")
67(put 'help-xref-stack-item 'permanent-local t)
89f5b33f 68(make-variable-buffer-local 'help-xref-stack-item)
f4ed5b19 69
95f731db
NR
70(defvar help-xref-stack-forward-item nil
71 "An item for `help-go-back' to push onto `help-xref-forward-stack'.
72The format is (FUNCTION ARGS...).")
73(put 'help-xref-stack-forward-item 'permanent-local t)
74(make-variable-buffer-local 'help-xref-stack-forward-item)
75
f4ed5b19 76(setq-default help-xref-stack nil help-xref-stack-item nil)
95f731db 77(setq-default help-xref-forward-stack nil help-xref-forward-stack-item nil)
f4ed5b19 78
1700f41d
RS
79(defcustom help-mode-hook nil
80 "Hook run by `help-mode'."
81 :type 'hook
82 :group 'help)
f4ed5b19
MB
83\f
84;; Button types used by help
85
6e881567 86(define-button-type 'help-xref
54d761b3 87 'follow-link t
6e881567
MB
88 'action #'help-button-action)
89
90(defun help-button-action (button)
91 "Call BUTTON's help function."
92 (help-do-xref (button-start button)
93 (button-get button 'help-function)
94 (button-get button 'help-args)))
95
7e2a83df
RS
96;; These 6 calls to define-button-type were generated in a dolist
97;; loop, but that is bad because it means these button types don't
98;; have an easily found definition.
99
100(define-button-type 'help-function
101 :supertype 'help-xref
102 'help-function 'describe-function
103 'help-echo (purecopy "mouse-2, RET: describe this function"))
104
105(define-button-type 'help-variable
106 :supertype 'help-xref
107 'help-function 'describe-variable
108 'help-echo (purecopy "mouse-2, RET: describe this variable"))
109
110(define-button-type 'help-face
111 :supertype 'help-xref
112 'help-function 'describe-face
113 'help-echo (purecopy "mouse-2, RET: describe this face"))
114
115(define-button-type 'help-coding-system
116 :supertype 'help-xref
117 'help-function 'describe-coding-system
118 'help-echo (purecopy "mouse-2, RET: describe this coding system"))
119
120(define-button-type 'help-input-method
121 :supertype 'help-xref
122 'help-function 'describe-input-method
123 'help-echo (purecopy "mouse-2, RET: describe this input method"))
124
125(define-button-type 'help-character-set
126 :supertype 'help-xref
127 'help-function 'describe-character-set
128 'help-echo (purecopy "mouse-2, RET: describe this character set"))
f4ed5b19
MB
129
130;; make some more ideosyncratic button types
131
132(define-button-type 'help-symbol
6e881567 133 :supertype 'help-xref
f4ed5b19 134 'help-function #'help-xref-interned
6e881567 135 'help-echo (purecopy "mouse-2, RET: describe this symbol"))
f4ed5b19
MB
136
137(define-button-type 'help-back
6e881567 138 :supertype 'help-xref
f4ed5b19 139 'help-function #'help-xref-go-back
6e881567 140 'help-echo (purecopy "mouse-2, RET: go back to previous help buffer"))
f4ed5b19 141
95f731db
NR
142(define-button-type 'help-forward
143 :supertype 'help-xref
144 'help-function #'help-xref-go-forward
145 'help-echo (purecopy "mouse-2, RET: move forward to next help buffer"))
146
f4ed5b19 147(define-button-type 'help-info
6e881567 148 :supertype 'help-xref
f4ed5b19 149 'help-function #'info
5c825567
BW
150 'help-echo (purecopy "mouse-2, RET: read this Info node"))
151
152(define-button-type 'help-url
153 :supertype 'help-xref
154 'help-function #'browse-url
155 'help-echo (purecopy "mouse-2, RET: view this URL in a browser"))
f4ed5b19
MB
156
157(define-button-type 'help-customize-variable
6e881567 158 :supertype 'help-xref
f4ed5b19 159 'help-function (lambda (v)
f4ed5b19 160 (customize-variable v))
6e881567 161 'help-echo (purecopy "mouse-2, RET: customize variable"))
f4ed5b19 162
07f904a3 163(define-button-type 'help-customize-face
6e881567 164 :supertype 'help-xref
07f904a3 165 'help-function (lambda (v)
07f904a3 166 (customize-face v))
6e881567 167 'help-echo (purecopy "mouse-2, RET: customize face"))
07f904a3 168
f4ed5b19 169(define-button-type 'help-function-def
6e881567 170 :supertype 'help-xref
f4ed5b19
MB
171 'help-function (lambda (fun file)
172 (require 'find-func)
2ea0f8fd
SM
173 (when (eq file 'C-source)
174 (setq file
175 (help-C-file-name (indirect-function fun) 'fun)))
410e58b5 176 ;; Don't use find-function-noselect because it follows
f4ed5b19 177 ;; aliases (which fails for built-in functions).
410e58b5 178 (let ((location
2ea0f8fd 179 (find-function-search-for-symbol fun nil file)))
f4ed5b19 180 (pop-to-buffer (car location))
46ab7691
NR
181 (if (cdr location)
182 (goto-char (cdr location))
183 (message "Unable to find location in file"))))
6e881567 184 'help-echo (purecopy "mouse-2, RET: find function's definition"))
f4ed5b19
MB
185
186(define-button-type 'help-variable-def
6e881567 187 :supertype 'help-xref
f4ed5b19 188 'help-function (lambda (var &optional file)
2ea0f8fd
SM
189 (when (eq file 'C-source)
190 (setq file (help-C-file-name var 'var)))
191 (let ((location (find-variable-noselect var file)))
f4ed5b19 192 (pop-to-buffer (car location))
46ab7691
NR
193 (if (cdr location)
194 (goto-char (cdr location))
195 (message "Unable to find location in file"))))
27313250 196 'help-echo (purecopy "mouse-2, RET: find variable's definition"))
f4ed5b19 197
12b42b71
RS
198(define-button-type 'help-face-def
199 :supertype 'help-xref
200 'help-function (lambda (fun file)
201 (require 'find-func)
202 ;; Don't use find-function-noselect because it follows
203 ;; aliases (which fails for built-in functions).
204 (let ((location
205 (find-function-search-for-symbol fun 'defface file)))
206 (pop-to-buffer (car location))
46ab7691
NR
207 (if (cdr location)
208 (goto-char (cdr location))
209 (message "Unable to find location in file"))))
12b42b71
RS
210 'help-echo (purecopy "mouse-2, RET: find face's definition"))
211
f4ed5b19
MB
212\f
213;;;###autoload
1700f41d 214(defun help-mode ()
f4ed5b19
MB
215 "Major mode for viewing help text and navigating references in it.
216Entry to this mode runs the normal hook `help-mode-hook'.
217Commands:
218\\{help-mode-map}"
1700f41d
RS
219 (interactive)
220 (kill-all-local-variables)
221 (use-local-map help-mode-map)
222 (setq mode-name "Help")
223 (setq major-mode 'help-mode)
f4ed5b19
MB
224 (view-mode)
225 (make-local-variable 'view-no-disable-on-exit)
1700f41d 226 (setq view-no-disable-on-exit t)
4bc1b836
RS
227 (setq view-exit-action (lambda (buffer)
228 (or (window-minibuffer-p (selected-window))
229 (one-window-p t)
230 (delete-window))))
40bd2cfb 231 (run-mode-hooks 'help-mode-hook))
f4ed5b19
MB
232
233;;;###autoload
234(defun help-mode-setup ()
235 (help-mode)
236 (setq buffer-read-only nil))
237
238;;;###autoload
239(defun help-mode-finish ()
69e73dd3 240 (let ((entry (assq (selected-window) view-return-to-alist)))
eac88b3b
RS
241 (if entry
242 ;; When entering Help mode from the Help window,
243 ;; such as by following a link, preserve the same
244 ;; meaning for the q command.
245 ;; (setcdr entry (cons (selected-window) help-return-method))
246 nil
69e73dd3
RS
247 (setq view-return-to-alist
248 (cons (cons (selected-window) help-return-method)
249 view-return-to-alist))))
f4ed5b19
MB
250 (when (eq major-mode 'help-mode)
251 ;; View mode's read-only status of existing *Help* buffer is lost
252 ;; by with-output-to-temp-buffer.
253 (toggle-read-only 1)
69e73dd3 254 (help-make-xrefs (current-buffer))))
f4ed5b19 255\f
410e58b5
SM
256;; Grokking cross-reference information in doc strings and
257;; hyperlinking it.
f4ed5b19
MB
258
259;; This may have some scope for extension and the same or something
260;; similar should be done for widget doc strings, which currently use
261;; another mechanism.
262
f4ed5b19
MB
263(defvar help-back-label (purecopy "[back]")
264 "Label to use by `help-make-xrefs' for the go-back reference.")
265
95f731db
NR
266(defvar help-forward-label (purecopy "[forward]")
267 "Label to use by `help-make-xrefs' for the go-forward reference.")
268
f4ed5b19 269(defconst help-xref-symbol-regexp
8a31f813 270 (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|" ; Link to var
a79d3474
NR
271 "\\(function\\|command\\)\\|" ; Link to function
272 "\\(face\\)\\|" ; Link to face
273 "\\(symbol\\|program\\|property\\)\\|" ; Don't link
040b2fa3
LT
274 "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)"
275 "[ \t\n]+\\)?"
f4ed5b19
MB
276 ;; Note starting with word-syntax character:
277 "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))
278 "Regexp matching doc string references to symbols.
279
280The words preceding the quoted symbol can be used in doc strings to
281distinguish references to variables, functions and symbols.")
282
410e58b5 283(defvar help-xref-mule-regexp nil
f4ed5b19
MB
284 "Regexp matching doc string references to MULE-related keywords.
285
286It is usually nil, and is temporarily bound to an appropriate regexp
287when help commands related to multilingual environment (e.g.,
288`describe-coding-system') are invoked.")
289
290
291(defconst help-xref-info-regexp
2e10efeb 292 (purecopy "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+`\\([^']+\\)'")
f4ed5b19
MB
293 "Regexp matching doc string references to an Info node.")
294
5c825567
BW
295(defconst help-xref-url-regexp
296 (purecopy "\\<[Uu][Rr][Ll][ \t\n]+`\\([^']+\\)'")
297 "Regexp matching doc string references to a URL.")
298
f4ed5b19
MB
299;;;###autoload
300(defun help-setup-xref (item interactive-p)
301 "Invoked from commands using the \"*Help*\" buffer to install some xref info.
302
303ITEM is a (FUNCTION . ARGS) pair appropriate for recreating the help
304buffer after following a reference. INTERACTIVE-P is non-nil if the
305calling command was invoked interactively. In this case the stack of
89f5b33f
SM
306items for help buffer \"back\" buttons is cleared.
307
308This should be called very early, before the output buffer is cleared,
309because we want to record the \"previous\" position of point so we can
310restore it properly when going back."
311 (with-current-buffer (help-buffer)
410e58b5 312 (when help-xref-stack-item
95f731db
NR
313 (push (cons (point) help-xref-stack-item) help-xref-stack)
314 (setq help-xref-forward-stack nil))
410e58b5
SM
315 (when interactive-p
316 (let ((tail (nthcdr 10 help-xref-stack)))
317 ;; Truncate the stack.
318 (if tail (setcdr tail nil))))
89f5b33f 319 (setq help-xref-stack-item item)))
f4ed5b19
MB
320
321(defvar help-xref-following nil
322 "Non-nil when following a help cross-reference.")
323
89f5b33f 324(defun help-buffer ()
89f5b33f
SM
325 (buffer-name ;for with-output-to-temp-buffer
326 (if help-xref-following
327 (current-buffer)
328 (get-buffer-create "*Help*"))))
329
410e58b5
SM
330(defvar help-xref-override-view-map
331 (let ((map (make-sparse-keymap)))
332 (set-keymap-parent map view-mode-map)
333 (define-key map "\r" nil)
334 map)
335 "Replacement keymap for `view-mode' in help buffers.")
336
f4ed5b19
MB
337;;;###autoload
338(defun help-make-xrefs (&optional buffer)
339 "Parse and hyperlink documentation cross-references in the given BUFFER.
340
d1282401
CW
341Find cross-reference information in a buffer and activate such cross
342references for selection with `help-follow'. Cross-references have
343the canonical form `...' and the type of reference may be
344disambiguated by the preceding word(s) used in
040b2fa3
LT
345`help-xref-symbol-regexp'. Faces only get cross-referenced if
346preceded or followed by the word `face'. Variables without
347variable documentation do not get cross-referenced, unless
9315fc34 348preceded by the word `variable' or `option'.
f4ed5b19
MB
349
350If the variable `help-xref-mule-regexp' is non-nil, find also
351cross-reference information related to multilingual environment
352\(e.g., coding-systems). This variable is also used to disambiguate
353the type of reference as the same way as `help-xref-symbol-regexp'.
354
355A special reference `back' is made to return back through a stack of
356help buffers. Variable `help-back-label' specifies the text for
357that."
358 (interactive "b")
359 (save-excursion
360 (set-buffer (or buffer (current-buffer)))
361 (goto-char (point-min))
362 ;; Skip the header-type info, though it might be useful to parse
363 ;; it at some stage (e.g. "function in `library'").
364 (forward-paragraph)
365 (let ((old-modified (buffer-modified-p)))
366 (let ((stab (syntax-table))
367 (case-fold-search t)
368 (inhibit-read-only t))
369 (set-syntax-table emacs-lisp-mode-syntax-table)
370 ;; The following should probably be abstracted out.
371 (unwind-protect
372 (progn
373 ;; Info references
374 (save-excursion
375 (while (re-search-forward help-xref-info-regexp nil t)
2e10efeb 376 (let ((data (match-string 2)))
f4ed5b19
MB
377 (save-match-data
378 (unless (string-match "^([^)]+)" data)
379 (setq data (concat "(emacs)" data))))
2e10efeb 380 (help-xref-button 2 'help-info data))))
5c825567
BW
381 ;; URLs
382 (save-excursion
383 (while (re-search-forward help-xref-url-regexp nil t)
384 (let ((data (match-string 1)))
385 (help-xref-button 1 'help-url data))))
f4ed5b19
MB
386 ;; Mule related keywords. Do this before trying
387 ;; `help-xref-symbol-regexp' because some of Mule
388 ;; keywords have variable or function definitions.
389 (if help-xref-mule-regexp
390 (save-excursion
391 (while (re-search-forward help-xref-mule-regexp nil t)
392 (let* ((data (match-string 7))
393 (sym (intern-soft data)))
394 (cond
395 ((match-string 3) ; coding system
396 (and sym (coding-system-p sym)
397 (help-xref-button 6 'help-coding-system sym)))
398 ((match-string 4) ; input method
399 (and (assoc data input-method-alist)
400 (help-xref-button 7 'help-input-method data)))
401 ((or (match-string 5) (match-string 6)) ; charset
402 (and sym (charsetp sym)
403 (help-xref-button 7 'help-character-set sym)))
404 ((assoc data input-method-alist)
405 (help-xref-button 7 'help-character-set data))
406 ((and sym (coding-system-p sym))
407 (help-xref-button 7 'help-coding-system sym))
408 ((and sym (charsetp sym))
409 (help-xref-button 7 'help-character-set sym)))))))
410 ;; Quoted symbols
411 (save-excursion
412 (while (re-search-forward help-xref-symbol-regexp nil t)
413 (let* ((data (match-string 8))
414 (sym (intern-soft data)))
415 (if sym
416 (cond
040b2fa3 417 ((match-string 3) ; `variable' &c
e715d9b4 418 (and (or (boundp sym) ; `variable' doesn't ensure
f4ed5b19 419 ; it's actually bound
e715d9b4 420 (get sym 'variable-documentation))
f4ed5b19 421 (help-xref-button 8 'help-variable sym)))
040b2fa3 422 ((match-string 4) ; `function' &c
f4ed5b19
MB
423 (and (fboundp sym) ; similarly
424 (help-xref-button 8 'help-function sym)))
425 ((match-string 5) ; `face'
426 (and (facep sym)
427 (help-xref-button 8 'help-face sym)))
428 ((match-string 6)) ; nothing for `symbol'
429 ((match-string 7)
040b2fa3
LT
430;;; this used:
431;;; #'(lambda (arg)
432;;; (let ((location
433;;; (find-function-noselect arg)))
434;;; (pop-to-buffer (car location))
435;;; (goto-char (cdr location))))
f4ed5b19 436 (help-xref-button 8 'help-function-def sym))
a1ef2eab
JB
437 ((and
438 (facep sym)
439 (save-match-data (looking-at "[ \t\n]+face\\W")))
440 (help-xref-button 8 'help-face sym))
e715d9b4
LT
441 ((and (or (boundp sym)
442 (get sym 'variable-documentation))
443 (fboundp sym))
f4ed5b19
MB
444 ;; We can't intuit whether to use the
445 ;; variable or function doc -- supply both.
446 (help-xref-button 8 'help-symbol sym))
040b2fa3 447 ((and
e715d9b4
LT
448 (or (boundp sym)
449 (get sym 'variable-documentation))
1d0a6ebb
JH
450 (or
451 (documentation-property
452 sym 'variable-documentation)
453 (condition-case nil
454 (documentation-property
455 (indirect-variable sym)
456 'variable-documentation)
457 (cyclic-variable-indirection nil))))
f4ed5b19
MB
458 (help-xref-button 8 'help-variable sym))
459 ((fboundp sym)
b1664339 460 (help-xref-button 8 'help-function sym)))))))
f4ed5b19
MB
461 ;; An obvious case of a key substitution:
462 (save-excursion
463 (while (re-search-forward
464 ;; Assume command name is only word characters
465 ;; and dashes to get things like `use M-x foo.'.
466 "\\<M-x\\s-+\\(\\sw\\(\\sw\\|-\\)+\\)" nil t)
467 (let ((sym (intern-soft (match-string 1))))
468 (if (fboundp sym)
469 (help-xref-button 1 'help-function sym)))))
470 ;; Look for commands in whole keymap substitutions:
471 (save-excursion
472 ;; Make sure to find the first keymap.
473 (goto-char (point-min))
474 ;; Find a header and the column at which the command
475 ;; name will be found.
ad4888e4
RS
476
477 ;; If the keymap substitution isn't the last thing in
478 ;; the doc string, and if there is anything on the
479 ;; same line after it, this code won't recognize the end of it.
f4ed5b19
MB
480 (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
481 nil t)
482 (let ((col (- (match-end 1) (match-beginning 1))))
483 (while
ad4888e4
RS
484 (and (not (eobp))
485 ;; Stop at a pair of blank lines.
486 (not (looking-at "\n\\s-*\n")))
487 ;; Skip a single blank line.
488 (and (eolp) (forward-line))
489 (end-of-line)
490 (skip-chars-backward "^\t\n")
491 (if (and (>= (current-column) col)
492 (looking-at "\\(\\sw\\|-\\)+$"))
493 (let ((sym (intern-soft (match-string 0))))
494 (if (fboundp sym)
495 (help-xref-button 0 'help-function sym))))
043dcdee
JPW
496 (forward-line))))))
497 (set-syntax-table stab))
f4ed5b19
MB
498 ;; Delete extraneous newlines at the end of the docstring
499 (goto-char (point-max))
500 (while (and (not (bobp)) (bolp))
501 (delete-char -1))
478eb46b 502 (insert "\n")
ea3da5b9
MR
503 (when (or help-xref-stack help-xref-forward-stack)
504 (insert "\n"))
f4ed5b19 505 ;; Make a back-reference in this buffer if appropriate.
89f5b33f 506 (when help-xref-stack
f4ed5b19 507 (help-insert-xref-button help-back-label 'help-back
ea3da5b9 508 (current-buffer)))
95f731db
NR
509 ;; Make a forward-reference in this buffer if appropriate.
510 (when help-xref-forward-stack
ea3da5b9
MR
511 (when help-xref-stack
512 (insert "\t"))
95f731db 513 (help-insert-xref-button help-forward-label 'help-forward
ea3da5b9
MR
514 (current-buffer)))
515 (when (or help-xref-stack help-xref-forward-stack)
478eb46b 516 (insert "\n")))
f4ed5b19
MB
517 ;; View mode steals RET from us.
518 (set (make-local-variable 'minor-mode-overriding-map-alist)
410e58b5 519 (list (cons 'view-mode help-xref-override-view-map)))
f4ed5b19
MB
520 (set-buffer-modified-p old-modified))))
521
522;;;###autoload
523(defun help-xref-button (match-number type &rest args)
524 "Make a hyperlink for cross-reference text previously matched.
525MATCH-NUMBER is the subexpression of interest in the last matched
526regexp. TYPE is the type of button to use. Any remaining arguments are
527passed to the button's help-function when it is invoked.
528See `help-make-xrefs'."
529 ;; Don't mung properties we've added specially in some instances.
530 (unless (button-at (match-beginning match-number))
531 (make-text-button (match-beginning match-number)
532 (match-end match-number)
533 'type type 'help-args args)))
534
535;;;###autoload
536(defun help-insert-xref-button (string type &rest args)
537 "Insert STRING and make a hyperlink from cross-reference text on it.
538TYPE is the type of button to use. Any remaining arguments are passed
539to the button's help-function when it is invoked.
540See `help-make-xrefs'."
541 (unless (button-at (point))
542 (insert-text-button string 'type type 'help-args args)))
543
544;;;###autoload
545(defun help-xref-on-pp (from to)
546 "Add xrefs for symbols in `pp's output between FROM and TO."
22f5d492
SM
547 (if (> (- to from) 5000) nil
548 (with-syntax-table emacs-lisp-mode-syntax-table
549 (save-excursion
550 (save-restriction
551 (narrow-to-region from to)
552 (goto-char (point-min))
553 (condition-case nil
554 (while (not (eobp))
555 (cond
556 ((looking-at "\"") (forward-sexp 1))
557 ((looking-at "#<") (search-forward ">" nil 'move))
558 ((looking-at "\\(\\(\\sw\\|\\s_\\)+\\)")
559 (let* ((sym (intern-soft (match-string 1)))
560 (type (cond ((fboundp sym) 'help-function)
561 ((or (memq sym '(t nil))
562 (keywordp sym))
563 nil)
e715d9b4
LT
564 ((and sym
565 (or (boundp sym)
566 (get sym
567 'variable-documentation)))
22f5d492
SM
568 'help-variable))))
569 (when type (help-xref-button 1 type sym)))
570 (goto-char (match-end 1)))
571 (t (forward-char 1))))
572 (error nil)))))))
f4ed5b19
MB
573
574\f
575;; Additional functions for (re-)creating types of help buffers.
576(defun help-xref-interned (symbol)
577 "Follow a hyperlink which appeared to be an arbitrary interned SYMBOL.
89f5b33f 578Both variable, function and face documentation are extracted into a single
f4ed5b19 579help buffer."
89f5b33f
SM
580 (with-current-buffer (help-buffer)
581 ;; Push the previous item on the stack before clobbering the output buffer.
774784f6 582 (help-setup-xref nil nil)
89f5b33f
SM
583 (let ((facedoc (when (facep symbol)
584 ;; Don't record the current entry in the stack.
585 (setq help-xref-stack-item nil)
586 (describe-face symbol)))
587 (fdoc (when (fboundp symbol)
588 ;; Don't record the current entry in the stack.
589 (setq help-xref-stack-item nil)
590 (describe-function symbol)))
e715d9b4
LT
591 (sdoc (when (or (boundp symbol)
592 (get symbol 'variable-documentation))
89f5b33f
SM
593 ;; Don't record the current entry in the stack.
594 (setq help-xref-stack-item nil)
595 (describe-variable symbol))))
596 (cond
597 (sdoc
598 ;; We now have a help buffer on the variable.
599 ;; Insert the function and face text before it.
ea127bf4 600 (when (or fdoc facedoc)
f4ed5b19
MB
601 (goto-char (point-min))
602 (let ((inhibit-read-only t))
603 (when fdoc
89f5b33f 604 (insert fdoc "\n\n")
ea127bf4
RS
605 (when facedoc
606 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
89f5b33f
SM
607 " is also a " "face." "\n\n")))
608 (when facedoc
609 (insert facedoc "\n\n"))
f4ed5b19
MB
610 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
611 " is also a " "variable." "\n\n"))
89f5b33f
SM
612 ;; Don't record the `describe-variable' item in the stack.
613 (setq help-xref-stack-item nil)
614 (help-setup-xref (list #'help-xref-interned symbol) nil)))
615 (fdoc
616 ;; We now have a help buffer on the function.
617 ;; Insert face text before it.
618 (when facedoc
619 (goto-char (point-max))
620 (let ((inhibit-read-only t))
621 (insert "\n\n" (make-string 30 ?-) "\n\n" (symbol-name symbol)
622 " is also a " "face." "\n\n" facedoc))
623 ;; Don't record the `describe-function' item in the stack.
624 (setq help-xref-stack-item nil)
625 (help-setup-xref (list #'help-xref-interned symbol) nil)))))))
f4ed5b19
MB
626
627\f
410e58b5 628;; Navigation/hyperlinking with xrefs
f4ed5b19
MB
629
630(defun help-xref-go-back (buffer)
631 "From BUFFER, go back to previous help buffer text using `help-xref-stack'."
632 (let (item position method args)
633 (with-current-buffer buffer
95f731db 634 (push (cons (point) help-xref-stack-item) help-xref-forward-stack)
f4ed5b19 635 (when help-xref-stack
f4ed5b19 636 (setq item (pop help-xref-stack)
89f5b33f
SM
637 ;; Clear the current item so that it won't get pushed
638 ;; by the function we're about to call. TODO: We could also
639 ;; push it onto a "forward" stack and add a `forw' button.
640 help-xref-stack-item nil
f4ed5b19
MB
641 position (car item)
642 method (cadr item)
643 args (cddr item))))
644 (apply method args)
77144ebc
RS
645 (with-current-buffer buffer
646 (if (get-buffer-window buffer)
647 (set-window-point (get-buffer-window buffer) position)
648 (goto-char position)))))
f4ed5b19 649
95f731db
NR
650(defun help-xref-go-forward (buffer)
651 "From BUFFER, go forward to next help buffer."
652 (let (item position method args)
653 (with-current-buffer buffer
654 (push (cons (point) help-xref-stack-item) help-xref-stack)
655 (when help-xref-forward-stack
656 (setq item (pop help-xref-forward-stack)
657 ;; Clear the current item so that it won't get pushed
658 ;; by the function we're about to call. TODO: We could also
659 ;; push it onto a "forward" stack and add a `forw' button.
660 help-xref-stack-item nil
661 position (car item)
662 method (cadr item)
663 args (cddr item))))
664 (apply method args)
665 (with-current-buffer buffer
666 (if (get-buffer-window buffer)
667 (set-window-point (get-buffer-window buffer) position)
668 (goto-char position)))))
669
f4ed5b19 670(defun help-go-back ()
933cd61e 671 "Go back to previous topic in this help buffer."
f4ed5b19 672 (interactive)
933cd61e
SM
673 (if help-xref-stack
674 (help-xref-go-back (current-buffer))
fdeadcd1 675 (error "No previous help buffer")))
95f731db
NR
676
677(defun help-go-forward ()
678 "Go back to next topic in this help buffer."
679 (interactive)
680 (if help-xref-forward-stack
681 (help-xref-go-forward (current-buffer))
682 (error "No next help buffer")))
f4ed5b19
MB
683
684(defun help-do-xref (pos function args)
685 "Call the help cross-reference function FUNCTION with args ARGS.
686Things are set up properly so that the resulting help-buffer has
687a proper [back] button."
f4ed5b19
MB
688 ;; There is a reference at point. Follow it.
689 (let ((help-xref-following t))
690 (apply function args)))
691
8a31f813
LT
692;; The doc string is meant to explain what buttons do.
693(defun help-follow-mouse ()
694 "Follow the cross-reference that you click on."
695 (interactive)
696 (error "No cross-reference here"))
697
698;; The doc string is meant to explain what buttons do.
699(defun help-follow ()
700 "Follow cross-reference at point.
f4ed5b19
MB
701
702For the cross-reference format, see `help-make-xrefs'."
8a31f813
LT
703 (interactive)
704 (error "No cross-reference here"))
705
706(defun help-follow-symbol (&optional pos)
707 "In help buffer, show docs for symbol at POS, defaulting to point.
708Show all docs for that symbol as either a variable, function or face."
f4ed5b19
MB
709 (interactive "d")
710 (unless pos
711 (setq pos (point)))
8a31f813
LT
712 ;; check if the symbol under point is a function, variable or face
713 (let ((sym
714 (intern
715 (save-excursion
716 (goto-char pos) (skip-syntax-backward "w_")
717 (buffer-substring (point)
718 (progn (skip-syntax-forward "w_")
719 (point)))))))
720 (when (or (boundp sym)
721 (get sym 'variable-documentation)
722 (fboundp sym) (facep sym))
723 (help-do-xref pos #'help-xref-interned (list sym)))))
f4ed5b19 724
ee90fe92
NR
725(defun help-insert-string (string)
726 "Insert STRING to the help buffer and install xref info for it.
727This function can be used to restore the old contents of the help buffer
728when going back to the previous topic in the xref stack. It is needed
729in case when it is impossible to recompute the old contents of the
730help buffer by other means."
731 (setq help-xref-stack-item (list #'help-insert-string string))
732 (with-output-to-temp-buffer (help-buffer)
733 (insert string)))
f4ed5b19
MB
734
735(provide 'help-mode)
736
65dd6275 737;; arch-tag: 850954ae-3725-4cb4-8e91-0bf6d52d6b0b
f4ed5b19 738;;; help-mode.el ends here