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