(vc-register): Allow registering a file passed as a
[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
b4aa6026 13;; the Free Software Foundation; either version 3, or (at your option)
f4ed5b19
MB
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)
91dc07f3 224
f4ed5b19 225 (view-mode)
91dc07f3
MR
226 (set (make-local-variable 'view-no-disable-on-exit) t)
227 ;; With Emacs 22 `view-exit-action' could delete the selected window
228 ;; disregarding whether the help buffer was shown in that window at
229 ;; all. Since `view-exit-action' is called with the help buffer as
230 ;; argument it seems more appropriate to have it work on the buffer
231 ;; only and leave it to `view-mode-exit' to delete any associated
232 ;; window(s).
233 (setq view-exit-action
234 (lambda (buffer)
235 ;; Use `with-current-buffer' to make sure that `bury-buffer'
236 ;; also removes BUFFER from the selected window.
237 (with-current-buffer buffer
238 (bury-buffer))))
239
40bd2cfb 240 (run-mode-hooks 'help-mode-hook))
f4ed5b19
MB
241
242;;;###autoload
243(defun help-mode-setup ()
244 (help-mode)
245 (setq buffer-read-only nil))
246
247;;;###autoload
248(defun help-mode-finish ()
91dc07f3
MR
249 (if (eq help-window t)
250 ;; If `help-window' is t, `view-return-to-alist' is handled by
251 ;; `with-help-window'. In this case set `help-window' to the
252 ;; selected window since now is the only moment where we can
253 ;; unambiguously identify it.
254 (setq help-window (selected-window))
255 (let ((entry (assq (selected-window) view-return-to-alist)))
256 (if entry
257 ;; When entering Help mode from the Help window,
258 ;; such as by following a link, preserve the same
259 ;; meaning for the q command.
260 ;; (setcdr entry (cons (selected-window) help-return-method))
261 nil
262 (setq view-return-to-alist
263 (cons (cons (selected-window) help-return-method)
264 view-return-to-alist)))))
265
f4ed5b19
MB
266 (when (eq major-mode 'help-mode)
267 ;; View mode's read-only status of existing *Help* buffer is lost
268 ;; by with-output-to-temp-buffer.
269 (toggle-read-only 1)
69e73dd3 270 (help-make-xrefs (current-buffer))))
f4ed5b19 271\f
410e58b5
SM
272;; Grokking cross-reference information in doc strings and
273;; hyperlinking it.
f4ed5b19
MB
274
275;; This may have some scope for extension and the same or something
276;; similar should be done for widget doc strings, which currently use
277;; another mechanism.
278
f4ed5b19
MB
279(defvar help-back-label (purecopy "[back]")
280 "Label to use by `help-make-xrefs' for the go-back reference.")
281
95f731db
NR
282(defvar help-forward-label (purecopy "[forward]")
283 "Label to use by `help-make-xrefs' for the go-forward reference.")
284
f4ed5b19 285(defconst help-xref-symbol-regexp
8a31f813 286 (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|" ; Link to var
a79d3474
NR
287 "\\(function\\|command\\)\\|" ; Link to function
288 "\\(face\\)\\|" ; Link to face
289 "\\(symbol\\|program\\|property\\)\\|" ; Don't link
040b2fa3
LT
290 "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)"
291 "[ \t\n]+\\)?"
f4ed5b19
MB
292 ;; Note starting with word-syntax character:
293 "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))
294 "Regexp matching doc string references to symbols.
295
296The words preceding the quoted symbol can be used in doc strings to
297distinguish references to variables, functions and symbols.")
298
410e58b5 299(defvar help-xref-mule-regexp nil
f4ed5b19
MB
300 "Regexp matching doc string references to MULE-related keywords.
301
302It is usually nil, and is temporarily bound to an appropriate regexp
303when help commands related to multilingual environment (e.g.,
304`describe-coding-system') are invoked.")
305
306
307(defconst help-xref-info-regexp
2e10efeb 308 (purecopy "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+`\\([^']+\\)'")
f4ed5b19
MB
309 "Regexp matching doc string references to an Info node.")
310
5c825567
BW
311(defconst help-xref-url-regexp
312 (purecopy "\\<[Uu][Rr][Ll][ \t\n]+`\\([^']+\\)'")
313 "Regexp matching doc string references to a URL.")
314
f4ed5b19
MB
315;;;###autoload
316(defun help-setup-xref (item interactive-p)
317 "Invoked from commands using the \"*Help*\" buffer to install some xref info.
318
319ITEM is a (FUNCTION . ARGS) pair appropriate for recreating the help
320buffer after following a reference. INTERACTIVE-P is non-nil if the
321calling command was invoked interactively. In this case the stack of
89f5b33f
SM
322items for help buffer \"back\" buttons is cleared.
323
324This should be called very early, before the output buffer is cleared,
325because we want to record the \"previous\" position of point so we can
326restore it properly when going back."
327 (with-current-buffer (help-buffer)
410e58b5 328 (when help-xref-stack-item
95f731db
NR
329 (push (cons (point) help-xref-stack-item) help-xref-stack)
330 (setq help-xref-forward-stack nil))
410e58b5
SM
331 (when interactive-p
332 (let ((tail (nthcdr 10 help-xref-stack)))
333 ;; Truncate the stack.
334 (if tail (setcdr tail nil))))
89f5b33f 335 (setq help-xref-stack-item item)))
f4ed5b19
MB
336
337(defvar help-xref-following nil
338 "Non-nil when following a help cross-reference.")
339
91dc07f3 340;;;###autoload
89f5b33f 341(defun help-buffer ()
89f5b33f
SM
342 (buffer-name ;for with-output-to-temp-buffer
343 (if help-xref-following
344 (current-buffer)
345 (get-buffer-create "*Help*"))))
346
410e58b5
SM
347(defvar help-xref-override-view-map
348 (let ((map (make-sparse-keymap)))
349 (set-keymap-parent map view-mode-map)
350 (define-key map "\r" nil)
351 map)
352 "Replacement keymap for `view-mode' in help buffers.")
353
f4ed5b19
MB
354;;;###autoload
355(defun help-make-xrefs (&optional buffer)
356 "Parse and hyperlink documentation cross-references in the given BUFFER.
357
d1282401
CW
358Find cross-reference information in a buffer and activate such cross
359references for selection with `help-follow'. Cross-references have
360the canonical form `...' and the type of reference may be
361disambiguated by the preceding word(s) used in
040b2fa3
LT
362`help-xref-symbol-regexp'. Faces only get cross-referenced if
363preceded or followed by the word `face'. Variables without
364variable documentation do not get cross-referenced, unless
9315fc34 365preceded by the word `variable' or `option'.
f4ed5b19
MB
366
367If the variable `help-xref-mule-regexp' is non-nil, find also
368cross-reference information related to multilingual environment
369\(e.g., coding-systems). This variable is also used to disambiguate
370the type of reference as the same way as `help-xref-symbol-regexp'.
371
372A special reference `back' is made to return back through a stack of
373help buffers. Variable `help-back-label' specifies the text for
374that."
375 (interactive "b")
376 (save-excursion
377 (set-buffer (or buffer (current-buffer)))
378 (goto-char (point-min))
379 ;; Skip the header-type info, though it might be useful to parse
380 ;; it at some stage (e.g. "function in `library'").
381 (forward-paragraph)
382 (let ((old-modified (buffer-modified-p)))
383 (let ((stab (syntax-table))
384 (case-fold-search t)
385 (inhibit-read-only t))
386 (set-syntax-table emacs-lisp-mode-syntax-table)
387 ;; The following should probably be abstracted out.
388 (unwind-protect
389 (progn
390 ;; Info references
391 (save-excursion
392 (while (re-search-forward help-xref-info-regexp nil t)
2e10efeb 393 (let ((data (match-string 2)))
f4ed5b19
MB
394 (save-match-data
395 (unless (string-match "^([^)]+)" data)
396 (setq data (concat "(emacs)" data))))
2e10efeb 397 (help-xref-button 2 'help-info data))))
5c825567
BW
398 ;; URLs
399 (save-excursion
400 (while (re-search-forward help-xref-url-regexp nil t)
401 (let ((data (match-string 1)))
402 (help-xref-button 1 'help-url data))))
f4ed5b19
MB
403 ;; Mule related keywords. Do this before trying
404 ;; `help-xref-symbol-regexp' because some of Mule
405 ;; keywords have variable or function definitions.
406 (if help-xref-mule-regexp
407 (save-excursion
408 (while (re-search-forward help-xref-mule-regexp nil t)
409 (let* ((data (match-string 7))
410 (sym (intern-soft data)))
411 (cond
412 ((match-string 3) ; coding system
413 (and sym (coding-system-p sym)
414 (help-xref-button 6 'help-coding-system sym)))
415 ((match-string 4) ; input method
416 (and (assoc data input-method-alist)
417 (help-xref-button 7 'help-input-method data)))
418 ((or (match-string 5) (match-string 6)) ; charset
419 (and sym (charsetp sym)
420 (help-xref-button 7 'help-character-set sym)))
421 ((assoc data input-method-alist)
422 (help-xref-button 7 'help-character-set data))
423 ((and sym (coding-system-p sym))
424 (help-xref-button 7 'help-coding-system sym))
425 ((and sym (charsetp sym))
426 (help-xref-button 7 'help-character-set sym)))))))
427 ;; Quoted symbols
428 (save-excursion
429 (while (re-search-forward help-xref-symbol-regexp nil t)
430 (let* ((data (match-string 8))
431 (sym (intern-soft data)))
432 (if sym
433 (cond
040b2fa3 434 ((match-string 3) ; `variable' &c
e715d9b4 435 (and (or (boundp sym) ; `variable' doesn't ensure
f4ed5b19 436 ; it's actually bound
e715d9b4 437 (get sym 'variable-documentation))
f4ed5b19 438 (help-xref-button 8 'help-variable sym)))
040b2fa3 439 ((match-string 4) ; `function' &c
f4ed5b19
MB
440 (and (fboundp sym) ; similarly
441 (help-xref-button 8 'help-function sym)))
442 ((match-string 5) ; `face'
443 (and (facep sym)
444 (help-xref-button 8 'help-face sym)))
445 ((match-string 6)) ; nothing for `symbol'
446 ((match-string 7)
040b2fa3
LT
447;;; this used:
448;;; #'(lambda (arg)
449;;; (let ((location
450;;; (find-function-noselect arg)))
451;;; (pop-to-buffer (car location))
452;;; (goto-char (cdr location))))
f4ed5b19 453 (help-xref-button 8 'help-function-def sym))
a1ef2eab
JB
454 ((and
455 (facep sym)
456 (save-match-data (looking-at "[ \t\n]+face\\W")))
457 (help-xref-button 8 'help-face sym))
e715d9b4
LT
458 ((and (or (boundp sym)
459 (get sym 'variable-documentation))
460 (fboundp sym))
f4ed5b19
MB
461 ;; We can't intuit whether to use the
462 ;; variable or function doc -- supply both.
463 (help-xref-button 8 'help-symbol sym))
040b2fa3 464 ((and
e715d9b4
LT
465 (or (boundp sym)
466 (get sym 'variable-documentation))
1d0a6ebb
JH
467 (or
468 (documentation-property
469 sym 'variable-documentation)
470 (condition-case nil
471 (documentation-property
472 (indirect-variable sym)
473 'variable-documentation)
474 (cyclic-variable-indirection nil))))
f4ed5b19
MB
475 (help-xref-button 8 'help-variable sym))
476 ((fboundp sym)
b1664339 477 (help-xref-button 8 'help-function sym)))))))
f4ed5b19
MB
478 ;; An obvious case of a key substitution:
479 (save-excursion
480 (while (re-search-forward
22ce475b 481 ;; Assume command name is only word and symbol
123437b4 482 ;; characters to get things like `use M-x foo->bar'.
22ce475b
GM
483 ;; Command required to end with word constituent
484 ;; to avoid `.' at end of a sentence.
485 "\\<M-x\\s-+\\(\\sw\\(\\sw\\|\\s_\\)*\\sw\\)" nil t)
f4ed5b19
MB
486 (let ((sym (intern-soft (match-string 1))))
487 (if (fboundp sym)
488 (help-xref-button 1 'help-function sym)))))
489 ;; Look for commands in whole keymap substitutions:
490 (save-excursion
491 ;; Make sure to find the first keymap.
492 (goto-char (point-min))
493 ;; Find a header and the column at which the command
494 ;; name will be found.
ad4888e4
RS
495
496 ;; If the keymap substitution isn't the last thing in
497 ;; the doc string, and if there is anything on the
498 ;; same line after it, this code won't recognize the end of it.
f4ed5b19
MB
499 (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
500 nil t)
501 (let ((col (- (match-end 1) (match-beginning 1))))
502 (while
ad4888e4
RS
503 (and (not (eobp))
504 ;; Stop at a pair of blank lines.
505 (not (looking-at "\n\\s-*\n")))
506 ;; Skip a single blank line.
507 (and (eolp) (forward-line))
508 (end-of-line)
e8749da6 509 (skip-chars-backward "^ \t\n")
ad4888e4 510 (if (and (>= (current-column) col)
123437b4 511 (looking-at "\\(\\sw\\|\\s_\\)+$"))
ad4888e4
RS
512 (let ((sym (intern-soft (match-string 0))))
513 (if (fboundp sym)
514 (help-xref-button 0 'help-function sym))))
043dcdee
JPW
515 (forward-line))))))
516 (set-syntax-table stab))
f4ed5b19
MB
517 ;; Delete extraneous newlines at the end of the docstring
518 (goto-char (point-max))
519 (while (and (not (bobp)) (bolp))
520 (delete-char -1))
478eb46b 521 (insert "\n")
ea3da5b9
MR
522 (when (or help-xref-stack help-xref-forward-stack)
523 (insert "\n"))
f4ed5b19 524 ;; Make a back-reference in this buffer if appropriate.
89f5b33f 525 (when help-xref-stack
f4ed5b19 526 (help-insert-xref-button help-back-label 'help-back
ea3da5b9 527 (current-buffer)))
95f731db
NR
528 ;; Make a forward-reference in this buffer if appropriate.
529 (when help-xref-forward-stack
ea3da5b9
MR
530 (when help-xref-stack
531 (insert "\t"))
95f731db 532 (help-insert-xref-button help-forward-label 'help-forward
ea3da5b9
MR
533 (current-buffer)))
534 (when (or help-xref-stack help-xref-forward-stack)
478eb46b 535 (insert "\n")))
f4ed5b19
MB
536 ;; View mode steals RET from us.
537 (set (make-local-variable 'minor-mode-overriding-map-alist)
410e58b5 538 (list (cons 'view-mode help-xref-override-view-map)))
f4ed5b19
MB
539 (set-buffer-modified-p old-modified))))
540
541;;;###autoload
542(defun help-xref-button (match-number type &rest args)
543 "Make a hyperlink for cross-reference text previously matched.
544MATCH-NUMBER is the subexpression of interest in the last matched
545regexp. TYPE is the type of button to use. Any remaining arguments are
546passed to the button's help-function when it is invoked.
547See `help-make-xrefs'."
548 ;; Don't mung properties we've added specially in some instances.
549 (unless (button-at (match-beginning match-number))
550 (make-text-button (match-beginning match-number)
551 (match-end match-number)
552 'type type 'help-args args)))
553
554;;;###autoload
555(defun help-insert-xref-button (string type &rest args)
556 "Insert STRING and make a hyperlink from cross-reference text on it.
557TYPE is the type of button to use. Any remaining arguments are passed
558to the button's help-function when it is invoked.
559See `help-make-xrefs'."
560 (unless (button-at (point))
561 (insert-text-button string 'type type 'help-args args)))
562
563;;;###autoload
564(defun help-xref-on-pp (from to)
565 "Add xrefs for symbols in `pp's output between FROM and TO."
22f5d492
SM
566 (if (> (- to from) 5000) nil
567 (with-syntax-table emacs-lisp-mode-syntax-table
568 (save-excursion
569 (save-restriction
570 (narrow-to-region from to)
571 (goto-char (point-min))
572 (condition-case nil
573 (while (not (eobp))
574 (cond
575 ((looking-at "\"") (forward-sexp 1))
576 ((looking-at "#<") (search-forward ">" nil 'move))
577 ((looking-at "\\(\\(\\sw\\|\\s_\\)+\\)")
578 (let* ((sym (intern-soft (match-string 1)))
579 (type (cond ((fboundp sym) 'help-function)
580 ((or (memq sym '(t nil))
581 (keywordp sym))
582 nil)
e715d9b4
LT
583 ((and sym
584 (or (boundp sym)
585 (get sym
586 'variable-documentation)))
22f5d492
SM
587 'help-variable))))
588 (when type (help-xref-button 1 type sym)))
589 (goto-char (match-end 1)))
590 (t (forward-char 1))))
591 (error nil)))))))
f4ed5b19
MB
592
593\f
594;; Additional functions for (re-)creating types of help buffers.
595(defun help-xref-interned (symbol)
596 "Follow a hyperlink which appeared to be an arbitrary interned SYMBOL.
89f5b33f 597Both variable, function and face documentation are extracted into a single
f4ed5b19 598help buffer."
89f5b33f
SM
599 (with-current-buffer (help-buffer)
600 ;; Push the previous item on the stack before clobbering the output buffer.
774784f6 601 (help-setup-xref nil nil)
89f5b33f
SM
602 (let ((facedoc (when (facep symbol)
603 ;; Don't record the current entry in the stack.
604 (setq help-xref-stack-item nil)
605 (describe-face symbol)))
606 (fdoc (when (fboundp symbol)
607 ;; Don't record the current entry in the stack.
608 (setq help-xref-stack-item nil)
609 (describe-function symbol)))
e715d9b4
LT
610 (sdoc (when (or (boundp symbol)
611 (get symbol 'variable-documentation))
89f5b33f
SM
612 ;; Don't record the current entry in the stack.
613 (setq help-xref-stack-item nil)
614 (describe-variable symbol))))
615 (cond
616 (sdoc
617 ;; We now have a help buffer on the variable.
618 ;; Insert the function and face text before it.
ea127bf4 619 (when (or fdoc facedoc)
f4ed5b19
MB
620 (goto-char (point-min))
621 (let ((inhibit-read-only t))
622 (when fdoc
89f5b33f 623 (insert fdoc "\n\n")
ea127bf4
RS
624 (when facedoc
625 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
89f5b33f
SM
626 " is also a " "face." "\n\n")))
627 (when facedoc
628 (insert facedoc "\n\n"))
f4ed5b19
MB
629 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
630 " is also a " "variable." "\n\n"))
89f5b33f
SM
631 ;; Don't record the `describe-variable' item in the stack.
632 (setq help-xref-stack-item nil)
633 (help-setup-xref (list #'help-xref-interned symbol) nil)))
634 (fdoc
635 ;; We now have a help buffer on the function.
636 ;; Insert face text before it.
637 (when facedoc
638 (goto-char (point-max))
639 (let ((inhibit-read-only t))
640 (insert "\n\n" (make-string 30 ?-) "\n\n" (symbol-name symbol)
641 " is also a " "face." "\n\n" facedoc))
642 ;; Don't record the `describe-function' item in the stack.
643 (setq help-xref-stack-item nil)
644 (help-setup-xref (list #'help-xref-interned symbol) nil)))))))
f4ed5b19
MB
645
646\f
410e58b5 647;; Navigation/hyperlinking with xrefs
f4ed5b19
MB
648
649(defun help-xref-go-back (buffer)
650 "From BUFFER, go back to previous help buffer text using `help-xref-stack'."
651 (let (item position method args)
652 (with-current-buffer buffer
95f731db 653 (push (cons (point) help-xref-stack-item) help-xref-forward-stack)
f4ed5b19 654 (when help-xref-stack
f4ed5b19 655 (setq item (pop help-xref-stack)
89f5b33f
SM
656 ;; Clear the current item so that it won't get pushed
657 ;; by the function we're about to call. TODO: We could also
658 ;; push it onto a "forward" stack and add a `forw' button.
659 help-xref-stack-item nil
f4ed5b19
MB
660 position (car item)
661 method (cadr item)
662 args (cddr item))))
663 (apply method args)
77144ebc
RS
664 (with-current-buffer buffer
665 (if (get-buffer-window buffer)
666 (set-window-point (get-buffer-window buffer) position)
667 (goto-char position)))))
f4ed5b19 668
95f731db
NR
669(defun help-xref-go-forward (buffer)
670 "From BUFFER, go forward to next help buffer."
671 (let (item position method args)
672 (with-current-buffer buffer
673 (push (cons (point) help-xref-stack-item) help-xref-stack)
674 (when help-xref-forward-stack
675 (setq item (pop help-xref-forward-stack)
676 ;; Clear the current item so that it won't get pushed
677 ;; by the function we're about to call. TODO: We could also
678 ;; push it onto a "forward" stack and add a `forw' button.
679 help-xref-stack-item nil
680 position (car item)
681 method (cadr item)
682 args (cddr item))))
683 (apply method args)
684 (with-current-buffer buffer
685 (if (get-buffer-window buffer)
686 (set-window-point (get-buffer-window buffer) position)
687 (goto-char position)))))
91dc07f3 688
f4ed5b19 689(defun help-go-back ()
933cd61e 690 "Go back to previous topic in this help buffer."
f4ed5b19 691 (interactive)
933cd61e
SM
692 (if help-xref-stack
693 (help-xref-go-back (current-buffer))
fdeadcd1 694 (error "No previous help buffer")))
91dc07f3 695
95f731db
NR
696(defun help-go-forward ()
697 "Go back to next topic in this help buffer."
698 (interactive)
699 (if help-xref-forward-stack
700 (help-xref-go-forward (current-buffer))
701 (error "No next help buffer")))
f4ed5b19
MB
702
703(defun help-do-xref (pos function args)
704 "Call the help cross-reference function FUNCTION with args ARGS.
705Things are set up properly so that the resulting help-buffer has
706a proper [back] button."
f4ed5b19
MB
707 ;; There is a reference at point. Follow it.
708 (let ((help-xref-following t))
709 (apply function args)))
710
8a31f813
LT
711;; The doc string is meant to explain what buttons do.
712(defun help-follow-mouse ()
713 "Follow the cross-reference that you click on."
714 (interactive)
715 (error "No cross-reference here"))
716
717;; The doc string is meant to explain what buttons do.
718(defun help-follow ()
719 "Follow cross-reference at point.
f4ed5b19
MB
720
721For the cross-reference format, see `help-make-xrefs'."
8a31f813
LT
722 (interactive)
723 (error "No cross-reference here"))
724
725(defun help-follow-symbol (&optional pos)
726 "In help buffer, show docs for symbol at POS, defaulting to point.
727Show all docs for that symbol as either a variable, function or face."
f4ed5b19
MB
728 (interactive "d")
729 (unless pos
730 (setq pos (point)))
8a31f813
LT
731 ;; check if the symbol under point is a function, variable or face
732 (let ((sym
733 (intern
734 (save-excursion
735 (goto-char pos) (skip-syntax-backward "w_")
736 (buffer-substring (point)
737 (progn (skip-syntax-forward "w_")
738 (point)))))))
739 (when (or (boundp sym)
740 (get sym 'variable-documentation)
741 (fboundp sym) (facep sym))
742 (help-do-xref pos #'help-xref-interned (list sym)))))
f4ed5b19 743
ee90fe92
NR
744(defun help-insert-string (string)
745 "Insert STRING to the help buffer and install xref info for it.
746This function can be used to restore the old contents of the help buffer
747when going back to the previous topic in the xref stack. It is needed
748in case when it is impossible to recompute the old contents of the
749help buffer by other means."
750 (setq help-xref-stack-item (list #'help-insert-string string))
751 (with-output-to-temp-buffer (help-buffer)
752 (insert string)))
f4ed5b19
MB
753
754(provide 'help-mode)
755
65dd6275 756;; arch-tag: 850954ae-3725-4cb4-8e91-0bf6d52d6b0b
f4ed5b19 757;;; help-mode.el ends here