*** empty log message ***
[bpt/emacs.git] / lisp / help.el
CommitLineData
1a06eabd
ER
1;;; help.el --- help commands for Emacs
2
d77dae5c 3;; Copyright (C) 1985, 1986, 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc.
3a801d0c 4
e5167999 5;; Maintainer: FSF
fd7fa35a 6;; Keywords: help, internal
e5167999 7
433ae6f6
RS
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
e5167999 12;; the Free Software Foundation; either version 2, or (at your option)
433ae6f6
RS
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b578f267
EN
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
433ae6f6 24
d9ecc911
ER
25;;; Commentary:
26
a1c9f209 27;; This code implements GNU Emacs' on-line help system, the one invoked by
95ac0a6f 28;; `M-x help-for-help'.
d9ecc911 29
e5167999
ER
30;;; Code:
31
8aa3a187
RS
32;; Get the macro make-help-screen when this is compiled,
33;; or run interpreted, but not when the compiled code is loaded.
b1fe9304 34(eval-when-compile (require 'help-macro))
4a8adb0b 35(eval-when-compile (require 'view))
41b8542b 36
433ae6f6
RS
37(defvar help-map (make-sparse-keymap)
38 "Keymap for characters following the Help key.")
39
afaa65e4
KH
40(defvar help-mode-map (make-sparse-keymap)
41 "Keymap for help mode.")
42
e17d2fd1 43(define-key global-map (char-to-string help-char) 'help-command)
0af3df1c
RS
44(define-key global-map [help] 'help-command)
45(define-key global-map [f1] 'help-command)
433ae6f6
RS
46(fset 'help-command help-map)
47
e17d2fd1 48(define-key help-map (char-to-string help-char) 'help-for-help)
0af3df1c
RS
49(define-key help-map [help] 'help-for-help)
50(define-key help-map [f1] 'help-for-help)
433ae6f6
RS
51(define-key help-map "?" 'help-for-help)
52
53(define-key help-map "\C-c" 'describe-copying)
54(define-key help-map "\C-d" 'describe-distribution)
55(define-key help-map "\C-w" 'describe-no-warranty)
76766f2d 56(define-key help-map "\C-p" 'describe-project)
122955bf 57(define-key help-map "a" 'apropos-command)
433ae6f6
RS
58
59(define-key help-map "b" 'describe-bindings)
60
61(define-key help-map "c" 'describe-key-briefly)
62(define-key help-map "k" 'describe-key)
63
64(define-key help-map "d" 'describe-function)
65(define-key help-map "f" 'describe-function)
66
7ee71cf1
RS
67(define-key help-map "F" 'view-emacs-FAQ)
68
433ae6f6 69(define-key help-map "i" 'info)
4b08b7ed 70(define-key help-map "4i" 'info-other-window)
e5d77022
JB
71(define-key help-map "\C-f" 'Info-goto-emacs-command-node)
72(define-key help-map "\C-k" 'Info-goto-emacs-key-command-node)
32884eab 73(define-key help-map "\C-i" 'info-lookup-symbol)
433ae6f6
RS
74
75(define-key help-map "l" 'view-lossage)
76
77(define-key help-map "m" 'describe-mode)
78
79(define-key help-map "\C-n" 'view-emacs-news)
80(define-key help-map "n" 'view-emacs-news)
81
06b98c51 82(define-key help-map "p" 'finder-by-keyword)
3e9c095d
RS
83(autoload 'finder-by-keyword "finder"
84 "Find packages matching a given keyword." t)
06b98c51 85
4cbff657
DL
86(define-key help-map "P" 'view-emacs-problems)
87
433ae6f6
RS
88(define-key help-map "s" 'describe-syntax)
89
90(define-key help-map "t" 'help-with-tutorial)
91
92(define-key help-map "w" 'where-is)
93
94(define-key help-map "v" 'describe-variable)
95
2fc9d9f4
RS
96(define-key help-map "q" 'help-quit)
97
400a1b1f
RS
98(define-key help-mode-map [mouse-2] 'help-follow-mouse)
99(define-key help-mode-map "\C-c\C-b" 'help-go-back)
100(define-key help-mode-map "\C-c\C-c" 'help-follow)
101(define-key help-mode-map "\t" 'help-next-ref)
102(define-key help-mode-map [backtab] 'help-previous-ref)
306a5e68 103(define-key help-mode-map [(shift tab)] 'help-previous-ref)
400a1b1f
RS
104;; Documentation only, since we use minor-mode-overriding-map-alist.
105(define-key help-mode-map "\r" 'help-follow)
106
400a1b1f
RS
107(defvar help-xref-stack nil
108 "A stack of ways by which to return to help buffers after following xrefs.
4c45295b 109Used by `help-follow' and `help-xref-go-back'.
376b2a24
DL
110An element looks like (POSITION FUNCTION ARGS...), where POSITION is
111`(POINT . BUFFER-NAME)'.
112To use the element, do (apply FUNCTION ARGS) then goto the point in
113the named buffer.")
400a1b1f
RS
114(put 'help-xref-stack 'permanent-local t)
115
116(defvar help-xref-stack-item nil
4c45295b
KH
117 "An item for `help-follow' in this buffer to push onto `help-xref-stack'.
118The format is (FUNCTION ARGS...).")
400a1b1f
RS
119(put 'help-xref-stack-item 'permanent-local t)
120
121(setq-default help-xref-stack nil help-xref-stack-item nil)
507fb916 122
73ea6d94
DL
123(defcustom help-mode-hook nil
124 "Hook run by `help-mode'."
125 :type 'hook
126 :group 'help)
127
afaa65e4 128(defun help-mode ()
400a1b1f 129 "Major mode for viewing help text and navigating references in it.
afaa65e4
KH
130Entry to this mode runs the normal hook `help-mode-hook'.
131Commands:
132\\{help-mode-map}"
133 (interactive)
134 (kill-all-local-variables)
135 (use-local-map help-mode-map)
136 (setq mode-name "Help")
137 (setq major-mode 'help-mode)
507fb916 138 (make-local-variable 'font-lock-defaults)
400a1b1f 139 (setq font-lock-defaults nil) ; font-lock would defeat xref
42499979 140 (view-mode)
f90b6922
RS
141 (make-local-variable 'view-no-disable-on-exit)
142 (setq view-no-disable-on-exit t)
400a1b1f
RS
143 ;; `help-make-xrefs' would be run here if not invoked from
144 ;; `help-mode-maybe'.
afaa65e4
KH
145 (run-hooks 'help-mode-hook))
146
e48143f0
RS
147(defun help-mode-setup ()
148 (help-mode)
149 (setq buffer-read-only nil))
150
3d02beed 151(add-hook 'temp-buffer-setup-hook 'help-mode-setup)
e48143f0
RS
152
153(defun help-mode-finish ()
400a1b1f
RS
154 (when (eq major-mode 'help-mode)
155 ;; View mode's read-only status of existing *Help* buffer is lost
156 ;; by with-output-to-temp-buffer.
157 (toggle-read-only 1)
158 (help-make-xrefs (current-buffer)))
01364a75
RS
159 (setq view-return-to-alist
160 (list (cons (selected-window) help-return-method))))
21de5941 161
3d02beed 162(add-hook 'temp-buffer-show-hook 'help-mode-finish)
21de5941 163
2fc9d9f4 164(defun help-quit ()
3120a677 165 "Just exit from the Help command's command loop."
2fc9d9f4
RS
166 (interactive)
167 nil)
168
0634ea78
KH
169(defun help-with-tutorial (&optional arg)
170 "Select the Emacs learn-by-doing tutorial.
da412772 171If there is a tutorial version written in the language
71e9bd71 172of the selected language environment, that version is used.
da412772 173If there's no tutorial in that language, `TUTORIAL' is selected.
c822b44b 174With arg, you are asked to choose which language."
0634ea78 175 (interactive "P")
3060bf83
KH
176 (let ((lang (if arg
177 (read-language-name 'tutorial "Language: " "English")
178 (if (get-language-info current-language-environment 'tutorial)
179 current-language-environment
ad21fa07
RS
180 "English")))
181 file filename)
3060bf83 182 (setq filename (get-language-info lang 'tutorial))
7c9b148e 183 (setq file (expand-file-name (concat "~/" filename)))
433ae6f6
RS
184 (delete-other-windows)
185 (if (get-file-buffer file)
186 (switch-to-buffer (get-file-buffer file))
187 (switch-to-buffer (create-file-buffer file))
188 (setq buffer-file-name file)
189 (setq default-directory (expand-file-name "~/"))
79058860 190 (setq buffer-auto-save-file-name nil)
0634ea78 191 (insert-file-contents (expand-file-name filename data-directory))
433ae6f6
RS
192 (goto-char (point-min))
193 (search-forward "\n<<")
194 (beginning-of-line)
195 (delete-region (point) (progn (end-of-line) (point)))
857a1de6 196 (let ((n (- (window-height (selected-window))
433ae6f6 197 (count-lines (point-min) (point))
857a1de6 198 6)))
d0da2301 199 (if (< n 12)
857a1de6
KH
200 (newline n)
201 ;; Some people get confused by the large gap.
202 (newline (/ n 2))
203 (insert "[Middle of page left blank for didactic purposes. "
204 "Text continues below]")
205 (newline (- n (/ n 2)))))
433ae6f6
RS
206 (goto-char (point-min))
207 (set-buffer-modified-p nil))))
208
35831732
GM
209(defun mode-line-key-binding (key)
210 "Value is the binding of KEY in the mode line or nil if none."
211 (let (string-info defn)
212 (when (and (eq 'mode-line (aref key 0))
213 (consp (setq string-info (nth 4 (event-start (aref key 1))))))
214 (let* ((string (car string-info))
215 (pos (cdr string-info))
216 (local-map (and (> pos 0)
217 (< pos (length string))
218 (get-text-property pos 'local-map string))))
219 (setq defn (and local-map (lookup-key local-map key)))))
220 defn))
221
e88a2c59
RS
222(defun describe-key-briefly (key &optional insert)
223 "Print the name of the function KEY invokes. KEY is a string.
224If INSERT (the prefix arg) is non-nil, insert the message in the buffer."
225 (interactive "kDescribe key briefly: \nP")
fc558e4d
RS
226 (save-excursion
227 (let ((modifiers (event-modifiers (aref key 0)))
e88a2c59 228 (standard-output (if insert (current-buffer) t))
fc558e4d
RS
229 window position)
230 ;; For a mouse button event, go to the button it applies to
231 ;; to get the right key bindings. And go to the right place
232 ;; in case the keymap depends on where you clicked.
233 (if (or (memq 'click modifiers) (memq 'down modifiers)
234 (memq 'drag modifiers))
235 (setq window (posn-window (event-start (aref key 0)))
236 position (posn-point (event-start (aref key 0)))))
237 (if (windowp window)
238 (progn
239 (set-buffer (window-buffer window))
240 (goto-char position)))
241 ;; Ok, now look up the key and name the command.
35831732
GM
242 (let ((defn (or (mode-line-key-binding key)
243 (key-binding key)))
e88a2c59 244 (key-desc (key-description key)))
fc558e4d 245 (if (or (null defn) (integerp defn))
e88a2c59
RS
246 (princ (format "%s is undefined" key-desc))
247 (princ (format (if insert
0f2aa0e1 248 "`%s' (`%s')"
e88a2c59
RS
249 (if (windowp window)
250 "%s at that spot runs the command %s"
251 "%s runs the command %s"))
252 key-desc
253 (if (symbolp defn) defn (prin1-to-string defn)))))))))
433ae6f6 254
01364a75
RS
255(defvar help-return-method nil
256 "What to do to \"exit\" the help buffer.
257This is a list
258 (WINDOW . t) delete the selected window, go to WINDOW.
259 (WINDOW . quit-window) do quit-window, then select WINDOW.
260 (WINDOW BUF START POINT) display BUF at START, POINT, then select WINDOW.")
261
433ae6f6
RS
262(defun print-help-return-message (&optional function)
263 "Display or return message saying how to restore windows after help command.
264Computes a message and applies the optional argument FUNCTION to it.
265If FUNCTION is nil, applies `message' to it, thus printing it."
266 (and (not (get-buffer-window standard-output))
d536293f 267 (let ((first-message
a1c9f209 268 (cond ((special-display-p (buffer-name standard-output))
01364a75 269 (setq help-return-method (cons (selected-window) t))
d536293f
RS
270 ;; If the help output buffer is a special display buffer,
271 ;; don't say anything about how to get rid of it.
272 ;; First of all, the user will do that with the window
273 ;; manager, not with Emacs.
274 ;; Secondly, the buffer has not been displayed yet,
275 ;; so we don't know whether its frame will be selected.
d536293f
RS
276 nil)
277 ((not (one-window-p t))
01364a75
RS
278 (setq help-return-method
279 (cons (selected-window) 'quit-window))
d536293f
RS
280 "Type \\[switch-to-buffer-other-window] RET to restore the other window.")
281 (pop-up-windows
01364a75 282 (setq help-return-method (cons (selected-window) t))
d536293f
RS
283 "Type \\[delete-other-windows] to remove help window.")
284 (t
01364a75
RS
285 (setq help-return-method
286 (list (selected-window) (window-buffer)
287 (window-start) (window-point)))
d536293f
RS
288 "Type \\[switch-to-buffer] RET to remove help window."))))
289 (funcall (or function 'message)
290 (concat
291 (if first-message
376b2a24
DL
292 (substitute-command-keys first-message))
293 (if first-message " ")
125a8d70
RS
294 ;; If the help buffer will go in a separate frame,
295 ;; it's no use mentioning a command to scroll, so don't.
a1c9f209 296 (if (special-display-p (buffer-name standard-output))
125a8d70 297 nil
a1c9f209 298 (if (same-window-p (buffer-name standard-output))
125a8d70
RS
299 ;; Say how to scroll this window.
300 (substitute-command-keys
301 "\\[scroll-up] to scroll the help.")
302 ;; Say how to scroll some other window.
6e7f5182 303 (substitute-command-keys
125a8d70 304 "\\[scroll-other-window] to scroll the help."))))))))
433ae6f6
RS
305
306(defun describe-key (key)
307 "Display documentation of the function invoked by KEY. KEY is a string."
308 (interactive "kDescribe key: ")
fc558e4d
RS
309 (save-excursion
310 (let ((modifiers (event-modifiers (aref key 0)))
311 window position)
312 ;; For a mouse button event, go to the button it applies to
313 ;; to get the right key bindings. And go to the right place
314 ;; in case the keymap depends on where you clicked.
315 (if (or (memq 'click modifiers) (memq 'down modifiers)
316 (memq 'drag modifiers))
317 (setq window (posn-window (event-start (aref key 0)))
318 position (posn-point (event-start (aref key 0)))))
319 (if (windowp window)
320 (progn
321 (set-buffer (window-buffer window))
322 (goto-char position)))
35831732 323 (let ((defn (or (mode-line-key-binding key) (key-binding key))))
fc558e4d
RS
324 (if (or (null defn) (integerp defn))
325 (message "%s is undefined" (key-description key))
326 (with-output-to-temp-buffer "*Help*"
327 (princ (key-description key))
328 (if (windowp window)
329 (princ " at that spot"))
330 (princ " runs the command ")
331 (prin1 defn)
05f6170c 332 (princ "\n which is ")
0ab0e672 333 (describe-function-1 defn nil (interactive-p))
fc558e4d 334 (print-help-return-message)))))))
433ae6f6 335
ad023904
RS
336(defun describe-mode ()
337 "Display documentation of current major mode and minor modes.
40b3bdc1
RS
338The major mode description comes first, followed by the minor modes,
339each on a separate page.
340
433ae6f6 341For this to work correctly for a minor mode, the mode's indicator variable
61c6b658 342\(listed in `minor-mode-alist') must also be a function whose documentation
433ae6f6 343describes the minor mode."
7192540b 344 (interactive)
433ae6f6 345 (with-output-to-temp-buffer "*Help*"
40b3bdc1
RS
346 (when minor-mode-alist
347 (princ "The major mode is described first.
348For minor modes, see following pages.\n\n"))
349 (princ mode-name)
350 (princ " mode:\n")
351 (princ (documentation major-mode))
352 (help-setup-xref (list #'help-xref-mode (current-buffer)) (interactive-p))
353 (let ((minor-modes minor-mode-alist))
7192540b
RS
354 (while minor-modes
355 (let* ((minor-mode (car (car minor-modes)))
ddbe99e0 356 (indicator (car (cdr (car minor-modes)))))
7192540b
RS
357 ;; Document a minor mode if it is listed in minor-mode-alist,
358 ;; bound locally in this buffer, non-nil, and has a function
359 ;; definition.
ddbe99e0 360 (if (and (symbol-value minor-mode)
7192540b
RS
361 (fboundp minor-mode))
362 (let ((pretty-minor-mode minor-mode))
363 (if (string-match "-mode$" (symbol-name minor-mode))
364 (setq pretty-minor-mode
365 (capitalize
366 (substring (symbol-name minor-mode)
367 0 (match-beginning 0)))))
e95419a6
RS
368 (while (and indicator (symbolp indicator)
369 (boundp indicator)
370 (not (eq indicator (symbol-value indicator))))
7192540b 371 (setq indicator (symbol-value indicator)))
40b3bdc1 372 (princ "\n\f\n")
2ef581f3
RS
373 (princ (format "%s minor mode (%s):\n"
374 pretty-minor-mode
375 (if indicator
376 (format "indicator%s" indicator)
377 "no indicator")))
40b3bdc1 378 (princ (documentation minor-mode)))))
7192540b 379 (setq minor-modes (cdr minor-modes))))
433ae6f6
RS
380 (print-help-return-message)))
381
382;; So keyboard macro definitions are documented correctly
383(fset 'defining-kbd-macro (symbol-function 'start-kbd-macro))
384
385(defun describe-distribution ()
386 "Display info on how to obtain the latest version of GNU Emacs."
387 (interactive)
388 (find-file-read-only
1e6dacf6 389 (expand-file-name "DISTRIB" data-directory)))
433ae6f6
RS
390
391(defun describe-copying ()
392 "Display info on how you may redistribute copies of GNU Emacs."
393 (interactive)
394 (find-file-read-only
1e6dacf6 395 (expand-file-name "COPYING" data-directory))
433ae6f6
RS
396 (goto-char (point-min)))
397
76766f2d
RS
398(defun describe-project ()
399 "Display info on the GNU project."
400 (interactive)
401 (find-file-read-only
402 (expand-file-name "GNU" data-directory))
403 (goto-char (point-min)))
404
433ae6f6
RS
405(defun describe-no-warranty ()
406 "Display info on all the kinds of warranty Emacs does NOT have."
407 (interactive)
408 (describe-copying)
409 (let (case-fold-search)
410 (search-forward "NO WARRANTY")
411 (recenter 0)))
412
61c6b658 413(defun describe-prefix-bindings ()
c7cba9cb
RS
414 "Describe the bindings of the prefix used to reach this command.
415The prefix described consists of all but the last event
416of the key sequence that ran this command."
61c6b658 417 (interactive)
ccc06dcc
KH
418 (let* ((key (this-command-keys)))
419 (describe-bindings
420 (if (stringp key)
421 (substring key 0 (1- (length key)))
422 (let ((prefix (make-vector (1- (length key)) nil))
423 (i 0))
424 (while (< i (length prefix))
425 (aset prefix i (aref key i))
426 (setq i (1+ i)))
427 prefix)))))
c7cba9cb
RS
428;; Make C-h after a prefix, when not specifically bound,
429;; run describe-prefix-bindings.
61c6b658
RS
430(setq prefix-help-command 'describe-prefix-bindings)
431
382d018a
RS
432(defun view-emacs-news (&optional arg)
433 "Display info on recent changes to Emacs.
434With numeric argument display information on correspondingly older changes."
435 (interactive "P")
436 (let* ((arg (if arg (prefix-numeric-value arg) 0)))
437 (find-file-read-only
438 (expand-file-name (concat (make-string arg ?O) "NEWS")
439 data-directory))))
433ae6f6 440
7ee71cf1
RS
441(defun view-emacs-FAQ ()
442 "Display the Emacs Frequently Asked Questions (FAQ) file."
443 (interactive)
4a8adb0b 444;;; (find-file-read-only (expand-file-name "FAQ" data-directory))
279b772d 445 (info "(efaq)"))
7ee71cf1 446
4cbff657
DL
447(defun view-emacs-problems ()
448 "Display info on known problems with Emacs and possible workarounds."
449 (interactive)
450 (view-file (expand-file-name "PROBLEMS" data-directory)))
451
433ae6f6
RS
452(defun view-lossage ()
453 "Display last 100 input keystrokes."
454 (interactive)
455 (with-output-to-temp-buffer "*Help*"
298a7c8c
RS
456 (princ (mapconcat (function (lambda (key)
457 (if (or (integerp key)
458 (symbolp key)
459 (listp key))
460 (single-key-description key)
461 (prin1-to-string key nil))))
462 (recent-keys)
463 " "))
433ae6f6
RS
464 (save-excursion
465 (set-buffer standard-output)
466 (goto-char (point-min))
467 (while (progn (move-to-column 50) (not (eobp)))
468 (search-forward " " nil t)
613a39b9
RS
469 (insert "\n"))
470 (setq help-xref-stack nil
471 help-xref-stack-item nil))
433ae6f6
RS
472 (print-help-return-message)))
473
2fc9d9f4 474(defalias 'help 'help-for-help)
41b8542b 475(make-help-screen help-for-help
a30a106b 476 "a b c C f F C-f i I k C-k l L m n p s t v w C-c C-d C-n C-p C-w; ? for help:"
a82e9c01 477 "You have typed %THIS-KEY%, the help character. Type a Help option:
efcce2d2 478\(Use SPC or DEL to scroll through this text. Type \\<help-map>\\[help-quit] to exit the Help command.)
433ae6f6 479
21ee8c42
RM
480a command-apropos. Give a substring, and see a list of commands
481 (functions interactively callable) that contain
482 that substring. See also the apropos command.
af6a9de9
RS
483b describe-bindings. Display table of all key bindings.
484c describe-key-briefly. Type a command key sequence;
21ee8c42 485 it prints the function name that sequence runs.
a30a106b
RS
486C describe-coding-system. This describes either a specific coding system
487 (if you type its name) or the coding systems currently in use
488 (if you type just RET).
af6a9de9 489f describe-function. Type a function name and get documentation of it.
21ee8c42
RM
490C-f Info-goto-emacs-command-node. Type a function name;
491 it takes you to the Info node for that command.
af6a9de9 492i info. The info documentation reader.
a30a106b
RS
493I describe-input-method. Describe a specific input method (if you type
494 its name) or the current input method (if you type just RET).
90a56040
KH
495C-i info-lookup-symbol. Display the definition of a specific symbol
496 as found in the manual for the language this buffer is written in.
af6a9de9 497k describe-key. Type a command key sequence;
21ee8c42
RM
498 it displays the full documentation.
499C-k Info-goto-emacs-key-command-node. Type a command key sequence;
500 it takes you to the Info node for the command bound to that key.
90a56040 501l view-lossage. Show last 100 characters you typed.
a30a106b
RS
502L describe-language-environment. This describes either the a
503 specific language environment (if you type its name)
504 or the current language environment (if you type just RET).
ed13681f
KH
505m describe-mode. Print documentation of current minor modes,
506 and the current major mode, including their special commands.
90a56040 507n view-emacs-news. Display news of recent Emacs changes.
af6a9de9
RS
508p finder-by-keyword. Find packages matching a given topic keyword.
509s describe-syntax. Display contents of syntax table, plus explanations
510t help-with-tutorial. Select the Emacs learn-by-doing tutorial.
511v describe-variable. Type name of a variable;
21ee8c42 512 it displays the variable's documentation and value.
af6a9de9 513w where-is. Type command name; it prints which keystrokes
21ee8c42 514 invoke that command.
a30a106b
RS
515
516F Display the frequently asked questions file.
517h Display the HELLO file which illustrates various scripts.
518C-c Display Emacs copying permission (General Public License).
519C-d Display Emacs ordering information.
520C-n Display news of recent Emacs changes.
521C-p Display information about the GNU project.
522C-w Display information on absence of warranty for GNU Emacs."
41b8542b 523 help-map)
433ae6f6 524
433ae6f6 525(defun function-called-at-point ()
b2c85790
DL
526 "Return a function around point or else called by the list containing point.
527If that doesn't give a function, return nil."
11267867
KH
528 (let ((stab (syntax-table)))
529 (set-syntax-table emacs-lisp-mode-syntax-table)
530 (unwind-protect
531 (or (condition-case ()
82cb9133
RS
532 (save-excursion
533 (or (not (zerop (skip-syntax-backward "_w")))
534 (eq (char-syntax (following-char)) ?w)
535 (eq (char-syntax (following-char)) ?_)
536 (forward-sexp -1))
537 (skip-chars-forward "'")
538 (let ((obj (read (current-buffer))))
539 (and (symbolp obj) (fboundp obj) obj)))
540 (error nil))
541 (condition-case ()
11267867
KH
542 (save-excursion
543 (save-restriction
544 (narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
545 ;; Move up to surrounding paren, then after the open.
546 (backward-up-list 1)
547 (forward-char 1)
548 ;; If there is space here, this is probably something
549 ;; other than a real Lisp function call, so ignore it.
550 (if (looking-at "[ \t]")
551 (error "Probably not a Lisp function call"))
552 (let (obj)
553 (setq obj (read (current-buffer)))
554 (and (symbolp obj) (fboundp obj) obj))))
11267867
KH
555 (error nil)))
556 (set-syntax-table stab))))
433ae6f6 557
0f619a41
KH
558(defvar symbol-file-load-history-loaded nil
559 "Non-nil means we have loaded the file `fns-VERSION.el' in `exec-directory'.
560That file records the part of `load-history' for preloaded files,
561which is cleared out before dumping to make Emacs smaller.")
562
563(defun symbol-file (function)
b2c85790 564 "Return the input source from which FUNCTION was loaded.
0f619a41
KH
565The value is normally a string that was passed to `load':
566either an absolute file name, or a library name
567\(with no directory name and no `.el' or `.elc' at the end).
568It can also be nil, if the definition is not associated with any file."
569 (unless symbol-file-load-history-loaded
570 (load (expand-file-name
571 ;; fns-XX.YY.ZZ.el does not work on DOS filesystem.
572 (if (eq system-type 'ms-dos)
573 "fns.el"
574 (format "fns-%s.el" emacs-version))
575 exec-directory)
576 ;; The file name fns-%s.el already has a .el extension.
577 nil nil t)
578 (setq symbol-file-load-history-loaded t))
ca5ed196
RS
579 (let ((files load-history)
580 file functions)
581 (while files
582 (if (memq function (cdr (car files)))
583 (setq file (car (car files)) files nil))
584 (setq files (cdr files)))
585 file))
586
433ae6f6
RS
587(defun describe-function (function)
588 "Display the full documentation of FUNCTION (a symbol)."
589 (interactive
590 (let ((fn (function-called-at-point))
591 (enable-recursive-minibuffers t)
592 val)
593 (setq val (completing-read (if fn
594 (format "Describe function (default %s): " fn)
595 "Describe function: ")
1bacc93e 596 obarray 'fboundp t nil nil (symbol-name fn)))
433ae6f6
RS
597 (list (if (equal val "")
598 fn (intern val)))))
00d3de8e
RS
599 (if function
600 (with-output-to-temp-buffer "*Help*"
601 (prin1 function)
eea844b2
RS
602 ;; Use " is " instead of a colon so that
603 ;; it is easier to get out the function name using forward-sexp.
604 (princ " is ")
0ab0e672 605 (describe-function-1 function nil (interactive-p))
00d3de8e
RS
606 (print-help-return-message)
607 (save-excursion
608 (set-buffer standard-output)
00d3de8e
RS
609 ;; Return the text we displayed.
610 (buffer-string)))
611 (message "You didn't specify a function")))
612
0ab0e672 613(defun describe-function-1 (function parens interactive-p)
6016b6e4
RS
614 (let* ((def (if (symbolp function)
615 (symbol-function function)
616 function))
05f6170c
KH
617 file-name string need-close
618 (beg (if (commandp def) "an interactive " "a ")))
619 (setq string
620 (cond ((or (stringp def)
621 (vectorp def))
622 "a keyboard macro")
623 ((subrp def)
d16296bb
DL
624 (if (eq 'unevalled (cdr (subr-arity def)))
625 (concat beg "special form")
626 (concat beg "built-in function")))
05f6170c
KH
627 ((byte-code-function-p def)
628 (concat beg "compiled Lisp function"))
629 ((symbolp def)
3f8309db
RS
630 (while (symbolp (symbol-function def))
631 (setq def (symbol-function def)))
213f4eae 632 (format "an alias for `%s'" def))
05f6170c
KH
633 ((eq (car-safe def) 'lambda)
634 (concat beg "Lisp function"))
635 ((eq (car-safe def) 'macro)
636 "a Lisp macro")
637 ((eq (car-safe def) 'mocklisp)
638 "a mocklisp function")
639 ((eq (car-safe def) 'autoload)
640 (setq file-name (nth 1 def))
aed2b2cd 641 (format "%s autoloaded %s"
05f6170c 642 (if (commandp def) "an interactive" "an")
aed2b2cd
AS
643 (if (eq (nth 4 def) 'keymap) "keymap"
644 (if (nth 4 def) "Lisp macro" "Lisp function"))
05f6170c 645 ))
b89d72a1
RS
646 ;; perhaps use keymapp here instead
647 ((eq (car-safe def) 'keymap)
648 (let ((is-full nil)
649 (elts (cdr-safe def)))
650 (while elts
651 (if (char-table-p (car-safe elts))
652 (setq is-full t
653 elts nil))
654 (setq elts (cdr-safe elts)))
655 (if is-full
656 "a full keymap"
657 "a sparse keymap")))
05f6170c
KH
658 (t "")))
659 (when (and parens (not (equal string "")))
660 (setq need-close t)
661 (princ "("))
662 (princ string)
b2c85790
DL
663 (with-current-buffer "*Help*"
664 (save-excursion
665 (save-match-data
666 (if (re-search-backward "alias for `\\([^`']+\\)'" nil t)
d77dae5c
DL
667 (help-xref-button 1 #'describe-function def
668 "mouse-2, RET: describe this function")))))
05f6170c 669 (or file-name
0f619a41 670 (setq file-name (symbol-file function)))
05f6170c
KH
671 (if file-name
672 (progn
673 (princ " in `")
674 ;; We used to add .el to the file name,
675 ;; but that's completely wrong when the user used load-file.
676 (princ file-name)
2676e099
DL
677 (princ "'")
678 ;; Make a hyperlink to the library.
679 (with-current-buffer "*Help*"
680 (save-excursion
681 (re-search-backward "`\\([^`']+\\)'" nil t)
7dcf1127
RS
682 (help-xref-button 1 #'(lambda (arg)
683 (let ((location
684 (find-function-noselect arg)))
582b6241
RS
685 (pop-to-buffer (car location))
686 (goto-char (cdr location))))
d77dae5c
DL
687 function
688 "mouse-2, RET: find function's definition")))))
05f6170c
KH
689 (if need-close (princ ")"))
690 (princ ".")
691 (terpri)
3f8309db
RS
692 ;; Handle symbols aliased to other symbols.
693 (setq def (indirect-function def))
694 ;; If definition is a macro, find the function inside it.
695 (if (eq (car-safe def) 'macro)
696 (setq def (cdr def)))
697 (let ((arglist (cond ((byte-code-function-p def)
698 (car (append def nil)))
699 ((eq (car-safe def) 'lambda)
700 (nth 1 def))
f0d0fb19
DL
701 ((and (eq (car-safe def) 'autoload)
702 (not (eq (nth 4 def) 'keymap)))
703 (concat "[Arg list not available until "
704 "function definition is loaded.]"))
3f8309db 705 (t t))))
f0d0fb19
DL
706 (cond ((listp arglist)
707 (princ (cons (if (symbolp function) function "anonymous")
708 (mapcar (lambda (arg)
709 (if (memq arg '(&optional &rest))
710 arg
711 (intern (upcase (symbol-name arg)))))
712 arglist)))
713 (terpri))
714 ((stringp arglist)
715 (princ arglist)
716 (terpri))))
05f6170c
KH
717 (let ((doc (documentation function)))
718 (if doc
719 (progn (terpri)
720 (princ doc)
d16296bb
DL
721 (if (subrp (symbol-function function))
722 (with-current-buffer standard-output
723 (beginning-of-line)
724 ;; Builtins get the calling sequence at the end of
725 ;; the doc string. Move it to the same place as
726 ;; for other functions.
9c50afce
DL
727
728 ;; In cases where `function' has been fset to a
729 ;; subr we can't search for function's name in
730 ;; the doc string. Kluge round that using the
731 ;; printed representation. The arg list then
732 ;; shows the wrong function name, but that
733 ;; might be a useful hint.
734 (let* ((rep (prin1-to-string def))
735 (name (progn
736 (string-match " \\([^ ]+\\)>$" rep)
737 (match-string 1 rep))))
738 (if (looking-at (format "(%s[ )]" name))
739 (let ((start (point-marker)))
740 (goto-char (point-min))
741 (forward-paragraph)
742 (insert-buffer-substring (current-buffer) start)
743 (insert ?\n)
744 (delete-region (1- start) (point-max)))
745 (goto-char (point-min))
746 (forward-paragraph)
747 (insert
748 "[Missing arglist. Please make a bug report.]\n")))
d16296bb 749 (goto-char (point-max))))
f0d0fb19
DL
750 (help-setup-xref (list #'describe-function function)
751 interactive-p))
05f6170c
KH
752 (princ "not documented")))))
753
433ae6f6 754(defun variable-at-point ()
b2c85790
DL
755 "Return the bound variable symbol found around point.
756Return 0 if there is no such symbol."
433ae6f6 757 (condition-case ()
914a48d0
RS
758 (let ((stab (syntax-table)))
759 (unwind-protect
760 (save-excursion
761 (set-syntax-table emacs-lisp-mode-syntax-table)
762 (or (not (zerop (skip-syntax-backward "_w")))
763 (eq (char-syntax (following-char)) ?w)
764 (eq (char-syntax (following-char)) ?_)
765 (forward-sexp -1))
766 (skip-chars-forward "'")
767 (let ((obj (read (current-buffer))))
00d3de8e
RS
768 (or (and (symbolp obj) (boundp obj) obj)
769 0)))
914a48d0 770 (set-syntax-table stab)))
00d3de8e 771 (error 0)))
433ae6f6 772
2e48ba18
GM
773(defun help-xref-on-pp (from to)
774 "Add xrefs for symbols in `pp's output between FROM and TO."
775 (let ((ost (syntax-table)))
776 (unwind-protect
777 (save-excursion
778 (save-restriction
779 (set-syntax-table emacs-lisp-mode-syntax-table)
780 (narrow-to-region from to)
781 (goto-char (point-min))
782 (while (not (eobp))
783 (cond
784 ((looking-at "\"") (forward-sexp 1))
785 ((looking-at "#<") (search-forward ">" nil 'move))
786 ((looking-at "\\(\\(\\sw\\|\\s_\\)+\\)")
787 (let* ((sym (intern-soft
820ad5e7
DL
788 (buffer-substring (match-beginning 1)
789 (match-end 1))))
2e48ba18 790 (fn (cond ((fboundp sym) #'describe-function)
820ad5e7
DL
791 ((or (memq sym '(t nil))
792 (keywordp sym))
793 nil)
794 ((and sym (boundp sym))
795 #'describe-variable))))
2e48ba18
GM
796 (when fn (help-xref-button 1 fn sym)))
797 (goto-char (match-end 1)))
798 (t (forward-char 1))))))
799 (set-syntax-table ost))))
800
433ae6f6
RS
801(defun describe-variable (variable)
802 "Display the full documentation of VARIABLE (a symbol).
803Returns the documentation as a string, also."
804 (interactive
805 (let ((v (variable-at-point))
806 (enable-recursive-minibuffers t)
807 val)
00d3de8e 808 (setq val (completing-read (if (symbolp v)
820ad5e7
DL
809 (format
810 "Describe variable (default %s): " v)
433ae6f6 811 "Describe variable: ")
d5645846
KH
812 obarray 'boundp t nil nil
813 (if (symbolp v) (symbol-name v))))
433ae6f6
RS
814 (list (if (equal val "")
815 v (intern val)))))
00d3de8e 816 (if (symbolp variable)
9a656d19
RS
817 (let (valvoid)
818 (with-output-to-temp-buffer "*Help*"
819 (prin1 variable)
820 (if (not (boundp variable))
821 (progn
822 (princ " is void")
9a656d19 823 (setq valvoid t))
2e48ba18
GM
824 (let ((val (symbol-value variable)))
825 (with-current-buffer standard-output
826 (princ "'s value is ")
827 (terpri)
828 (let ((from (point)))
829 (pp val)
830 (help-xref-on-pp from (point))))))
831 (terpri)
9a656d19
RS
832 (if (local-variable-p variable)
833 (progn
834 (princ (format "Local in buffer %s; " (buffer-name)))
835 (if (not (default-boundp variable))
836 (princ "globally void")
2e48ba18
GM
837 (let ((val (default-value variable)))
838 (with-current-buffer standard-output
839 (princ "global value is ")
840 (terpri)
841 (let ((from (point)))
842 (pp val)
843 (help-xref-on-pp from (point))))))
9a656d19
RS
844 (terpri)))
845 (terpri)
846 (save-current-buffer
847 (set-buffer standard-output)
848 (if (> (count-lines (point-min) (point-max)) 10)
849 (progn
d365421f
GM
850 ;; Note that setting the syntax table like below
851 ;; makes forward-sexp move over a `'s' at the end
852 ;; of a symbol.
14cc00ad 853 (set-syntax-table emacs-lisp-mode-syntax-table)
9a656d19
RS
854 (goto-char (point-min))
855 (if valvoid
856 (forward-line 1)
857 (forward-sexp 1)
858 (delete-region (point) (progn (end-of-line) (point)))
d365421f 859 (insert " value is shown below.\n\n")
9a656d19
RS
860 (save-excursion
861 (insert "\n\nValue:"))))))
862 (princ "Documentation:")
863 (terpri)
864 (let ((doc (documentation-property variable 'variable-documentation)))
865 (princ (or doc "not documented as a variable.")))
4c45295b 866 (help-setup-xref (list #'describe-variable variable) (interactive-p))
7e824765
RS
867
868 ;; Make a link to customize if this variable can be customized.
be66e132 869 ;; Note, it is not reliable to test only for a custom-type property
4f103eaa
RS
870 ;; because those are only present after the var's definition
871 ;; has been loaded.
96757035
DL
872 (if (or (get variable 'custom-type) ; after defcustom
873 (get variable 'custom-loads) ; from loaddefs.el
874 (get variable 'standard-value)) ; from cus-start.el
7e824765
RS
875 (let ((customize-label "customize"))
876 (terpri)
877 (terpri)
878 (princ (concat "You can " customize-label " this variable."))
879 (with-current-buffer "*Help*"
880 (save-excursion
881 (re-search-backward
882 (concat "\\(" customize-label "\\)") nil t)
950cf06f
DL
883 (help-xref-button 1 (lambda (v)
884 (if help-xref-stack
885 (pop help-xref-stack))
886 (customize-variable v))
d77dae5c 887 variable
950cf06f 888 "mouse-2, RET: customize variable")))))
3476e159
DL
889 ;; Make a hyperlink to the library if appropriate. (Don't
890 ;; change the format of the buffer's initial line in case
891 ;; anything expects the current format.)
0f619a41 892 (let ((file-name (symbol-file variable)))
3476e159 893 (when file-name
5f373960 894 (princ "\n\nDefined in `")
3476e159 895 (princ file-name)
5f373960 896 (princ "'.")
3476e159
DL
897 (with-current-buffer "*Help*"
898 (save-excursion
5f373960 899 (re-search-backward "`\\([^`']+\\)'" nil t)
d77dae5c
DL
900 (help-xref-button
901 1 (lambda (arg)
902 (let ((location
903 (find-variable-noselect arg)))
904 (pop-to-buffer (car location))
905 (goto-char (cdr location))))
906 variable "mouse-2, RET: find variable's definition")))))
7e824765 907
9a656d19
RS
908 (print-help-return-message)
909 (save-excursion
910 (set-buffer standard-output)
9a656d19
RS
911 ;; Return the text we displayed.
912 (buffer-string))))
00d3de8e 913 (message "You did not specify a variable")))
433ae6f6 914
4c45295b 915(defun describe-bindings (&optional prefix buffer)
a8ad43aa
RS
916 "Show a list of all defined keys, and their definitions.
917We put that list in a buffer, and display the buffer.
918
919The optional argument PREFIX, if non-nil, should be a key sequence;
4c45295b
KH
920then we display only bindings that start with that prefix.
921The optional argument BUFFER specifies which buffer's bindings
922to display (default, the current buffer)."
a249d3a0 923 (interactive "P")
4c45295b
KH
924 (or buffer (setq buffer (current-buffer)))
925 (with-current-buffer buffer
926 (describe-bindings-internal nil prefix))
613a39b9 927 (with-current-buffer "*Help*"
4c45295b
KH
928 (help-setup-xref (list #'describe-bindings prefix buffer)
929 (interactive-p))))
a8ad43aa 930
e88a2c59 931(defun where-is (definition &optional insert)
b2c85790 932 "Print message listing key sequences that invoke the command DEFINITION.
e88a2c59
RS
933Argument is a command definition, usually a symbol with a function definition.
934If INSERT (the prefix arg) is non-nil, insert the message in the buffer."
54c0b967
RS
935 (interactive
936 (let ((fn (function-called-at-point))
937 (enable-recursive-minibuffers t)
938 val)
939 (setq val (completing-read (if fn
940 (format "Where is command (default %s): " fn)
941 "Where is command: ")
d5f65532 942 obarray 'commandp t))
54c0b967 943 (list (if (equal val "")
e88a2c59
RS
944 fn (intern val))
945 current-prefix-arg)))
54c0b967 946 (let* ((keys (where-is-internal definition overriding-local-map nil nil))
e88a2c59
RS
947 (keys1 (mapconcat 'key-description keys ", "))
948 (standard-output (if insert (current-buffer) t)))
949 (if insert
950 (if (> (length keys1) 0)
951 (princ (format "%s (%s)" keys1 definition))
952 (princ (format "M-x %s RET" definition)))
953 (if (> (length keys1) 0)
954 (princ (format "%s is on %s" definition keys1))
955 (princ (format "%s is not on any key" definition)))))
54c0b967
RS
956 nil)
957
a130d829 958(defun locate-library (library &optional nosuffix path interactive-call)
2747503c 959 "Show the precise file name of Emacs library LIBRARY.
433ae6f6
RS
960This command searches the directories in `load-path' like `M-x load-library'
961to find the file that `M-x load-library RET LIBRARY RET' would load.
962Optional second arg NOSUFFIX non-nil means don't add suffixes `.elc' or `.el'
9dc176a0
RS
963to the specified name LIBRARY.
964
965If the optional third arg PATH is specified, that list of directories
b2c85790
DL
966is used instead of `load-path'.
967
968When called from a program, the file name is normaly returned as a
969string. When run interactively, the argument INTERACTIVE-CALL is t,
970and the file name is displayed in the echo area."
a130d829
RS
971 (interactive (list (read-string "Locate library: ")
972 nil nil
973 t))
dd557bb8 974 (let (result)
a130d829 975 (catch 'answer
e3e36d74 976 (mapc
a1c9f209 977 (lambda (dir)
e3e36d74 978 (mapc
a1c9f209
EN
979 (lambda (suf)
980 (let ((try (expand-file-name (concat library suf) dir)))
981 (and (file-readable-p try)
982 (null (file-directory-p try))
983 (progn
984 (setq result try)
985 (throw 'answer try)))))
986 (if nosuffix
987 '("")
dd557bb8
KH
988 '(".elc" ".el" "")
989;;; load doesn't handle this yet.
990;;; (let ((basic '(".elc" ".el" ""))
991;;; (compressed '(".Z" ".gz" "")))
992;;; ;; If autocompression mode is on,
993;;; ;; consider all combinations of library suffixes
994;;; ;; and compression suffixes.
995;;; (if (rassq 'jka-compr-handler file-name-handler-alist)
996;;; (apply 'nconc
997;;; (mapcar (lambda (compelt)
998;;; (mapcar (lambda (baselt)
999;;; (concat baselt compelt))
1000;;; basic))
1001;;; compressed))
1002;;; basic))
1003 )))
a130d829
RS
1004 (or path load-path)))
1005 (and interactive-call
1006 (if result
1007 (message "Library is file %s" result)
1008 (message "No library %s in search path" library)))
1009 result))
1a06eabd 1010
400a1b1f
RS
1011\f
1012;;; Grokking cross-reference information in doc strings and
1013;;; hyperlinking it.
1014
1015;; This may have some scope for extension and the same or something
1016;; similar should be done for widget doc strings, which currently use
1017;; another mechanism.
1018
1019(defcustom help-highlight-p t
1020 "*If non-nil, `help-make-xrefs' highlight cross-references.
1021Under a window system it highlights them with face defined by
510df933 1022`help-highlight-face'."
400a1b1f
RS
1023 :group 'help
1024 :version "20.3"
1025 :type 'boolean)
1026
1027(defcustom help-highlight-face 'underline
1028 "Face used by `help-make-xrefs' to highlight cross-references.
1029Must be previously-defined."
1030 :group 'help
1031 :version "20.3"
7f082394 1032 :type 'face)
400a1b1f 1033
4607e12b 1034(defvar help-back-label (purecopy "[back]")
400a1b1f
RS
1035 "Label to use by `help-make-xrefs' for the go-back reference.")
1036
4607e12b
DL
1037(defconst help-xref-symbol-regexp
1038 (purecopy (concat "\\(\\<\\(\\(variable\\|option\\)\\|"
1039 "\\(function\\|command\\)\\|"
950cf06f 1040 "\\(face\\)\\|"
4607e12b
DL
1041 "\\(symbol\\)\\)\\s-+\\)?"
1042 ;; Note starting with word-syntax character:
1043 "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))
400a1b1f
RS
1044 "Regexp matching doc string references to symbols.
1045
1046The words preceding the quoted symbol can be used in doc strings to
1047distinguish references to variables, functions and symbols.")
1048
4607e12b
DL
1049(defconst help-xref-info-regexp
1050 (purecopy "\\<[Ii]nfo[ \t\n]+node[ \t\n]+`\\([^']+\\)'")
400a1b1f
RS
1051 "Regexp matching doc string references to an Info node.")
1052
1053(defun help-setup-xref (item interactive-p)
1054 "Invoked from commands using the \"*Help*\" buffer to install some xref info.
1055
4c45295b 1056ITEM is a (FUNCTION . ARGS) pair appropriate for recreating the help
400a1b1f
RS
1057buffer after following a reference. INTERACTIVE-P is non-nil if the
1058calling command was invoked interactively. In this case the stack of
1059items for help buffer \"back\" buttons is cleared."
1060 (if interactive-p
1061 (setq help-xref-stack nil))
1062 (setq help-xref-stack-item item))
1063
376b2a24
DL
1064(defvar help-xref-following nil
1065 "Non-nil when following a help cross-reference.")
1066
400a1b1f
RS
1067(defun help-make-xrefs (&optional buffer)
1068 "Parse and hyperlink documentation cross-references in the given BUFFER.
1069
1070Find cross-reference information in a buffer and, if
1071`help-highlight-p' is non-nil, highlight it with face defined by
1072`help-highlight-face'; activate such cross references for selection
1073with `help-follow'. Cross-references have the canonical form `...'
1074and the type of reference may be disambiguated by the preceding
1075word(s) used in `help-xref-symbol-regexp'.
1076
1077A special reference `back' is made to return back through a stack of
1078help buffers. Variable `help-back-label' specifies the text for
1079that."
1080 (interactive "b")
1081 (save-excursion
1082 (set-buffer (or buffer (current-buffer)))
1083 (goto-char (point-min))
1084 ;; Skip the header-type info, though it might be useful to parse
1085 ;; it at some stage (e.g. "function in `library'").
1086 (forward-paragraph)
1087 (let ((old-modified (buffer-modified-p)))
1088 (let ((stab (syntax-table))
1089 (case-fold-search t)
1090 (inhibit-read-only t))
1091 (set-syntax-table emacs-lisp-mode-syntax-table)
1092 ;; The following should probably be abstracted out.
1093 (unwind-protect
1094 (progn
f58790da
RS
1095 ;; Info references
1096 (save-excursion
1097 (while (re-search-forward help-xref-info-regexp nil t)
1098 (let ((data (match-string 1)))
1099 (save-match-data
1100 (unless (string-match "^([^)]+)" data)
1101 (setq data (concat "(emacs)" data))))
d77dae5c
DL
1102 (help-xref-button 1 #'info data
1103 "mouse-2, RET: read this Info node"))))
400a1b1f
RS
1104 ;; Quoted symbols
1105 (save-excursion
1106 (while (re-search-forward help-xref-symbol-regexp nil t)
950cf06f 1107 (let* ((data (match-string 7))
400a1b1f
RS
1108 (sym (intern-soft data)))
1109 (if sym
1110 (cond
1111 ((match-string 3) ; `variable' &c
1112 (and (boundp sym) ; `variable' doesn't ensure
1113 ; it's actually bound
d77dae5c 1114 (help-xref-button
950cf06f 1115 7 #'describe-variable sym
d77dae5c 1116 "mouse-2, RET: describe this variable")))
400a1b1f
RS
1117 ((match-string 4) ; `function' &c
1118 (and (fboundp sym) ; similarly
d77dae5c 1119 (help-xref-button
950cf06f 1120 7 #'describe-function sym
d77dae5c 1121 "mouse-2, RET: describe this function")))
950cf06f
DL
1122 ((match-string 5) ; `face'
1123 (and (facep sym)
1124 (help-xref-button 7 #'describe-face sym
1125 "mouse-2, RET: describe this face")))
1126 ((match-string 6)) ; nothing for symbol
d77dae5c 1127 ((and (boundp sym) (fboundp sym))
400a1b1f
RS
1128 ;; We can't intuit whether to use the
1129 ;; variable or function doc -- supply both.
d77dae5c 1130 (help-xref-button
950cf06f 1131 7 #'help-xref-interned sym
d77dae5c
DL
1132 "mouse-2, RET: describe this symbol"))
1133 ((boundp sym)
1134 (help-xref-button
950cf06f 1135 7 #'describe-variable sym
d77dae5c
DL
1136 "mouse-2, RET: describe this variable"))
1137 ((fboundp sym)
1138 (help-xref-button
950cf06f
DL
1139 7 #'describe-function sym
1140 "mouse-2, RET: describe this function"))
1141 ((facep sym)
1142 (help-xref-button
1143 7 #'describe-face sym)))))))
400a1b1f
RS
1144 ;; An obvious case of a key substitution:
1145 (save-excursion
b2c85790
DL
1146 (while (re-search-forward
1147 ;; Assume command name is only word characters
1148 ;; and dashes to get things like `use M-x foo.'.
1149 "\\<M-x\\s-+\\(\\sw\\(\\sw\\|-\\)+\\)" nil t)
400a1b1f
RS
1150 (let ((sym (intern-soft (match-string 1))))
1151 (if (fboundp sym)
d77dae5c
DL
1152 (help-xref-button
1153 1 #'describe-function sym
1154 "mouse-2, RET: describe this command")))))
ff3453e4
DL
1155 ;; Look for commands in whole keymap substitutions:
1156 (save-excursion
9b49f910
RS
1157 ;; Make sure to find the first keymap.
1158 (goto-char (point-min))
ff3453e4
DL
1159 ;; Find a header and the column at which the command
1160 ;; name will be found.
1161 (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
1162 nil t)
1163 (let ((col (- (match-end 1) (match-beginning 1))))
1164 (while
1165 ;; Ignore single blank lines in table, but not
1166 ;; double ones, which should terminate it.
95ac0a6f 1167 (and (not (looking-at "\n\\s-*\n"))
ff3453e4 1168 (progn
657cca97
AS
1169 (and (eolp) (forward-line))
1170 (end-of-line)
1171 (skip-chars-backward "^\t\n")
1172 (if (and (>= (current-column) col)
377d15d9 1173 (looking-at "\\(\\sw\\|-\\)+$"))
ff3453e4
DL
1174 (let ((sym (intern-soft (match-string 0))))
1175 (if (fboundp sym)
1176 (help-xref-button
d77dae5c
DL
1177 0 #'describe-function sym
1178 "mouse-2, RET: describe this function"))))
657cca97 1179 (zerop (forward-line)))))))))
400a1b1f
RS
1180 (set-syntax-table stab))
1181 ;; Make a back-reference in this buffer if appropriate.
376b2a24 1182 (when (and help-xref-following help-xref-stack)
400a1b1f
RS
1183 (goto-char (point-max))
1184 (save-excursion
1185 (insert "\n\n" help-back-label))
1186 ;; Just to provide the match data:
1187 (looking-at (concat "\n\n\\(" (regexp-quote help-back-label) "\\)"))
613a39b9 1188 (help-xref-button 1 #'help-xref-go-back (current-buffer))))
400a1b1f
RS
1189 ;; View mode steals RET from us.
1190 (set (make-local-variable 'minor-mode-overriding-map-alist)
1191 (list (cons 'view-mode
1192 (let ((map (make-sparse-keymap)))
ff3453e4 1193 (set-keymap-parent map view-mode-map)
400a1b1f
RS
1194 (define-key map "\r" 'help-follow)
1195 map))))
1196 (set-buffer-modified-p old-modified))))
1197
d77dae5c 1198(defun help-xref-button (match-number function data &optional help-echo)
400a1b1f
RS
1199 "Make a hyperlink for cross-reference text previously matched.
1200
1201MATCH-NUMBER is the subexpression of interest in the last matched
1202regexp. FUNCTION is a function to invoke when the button is
1203activated, applied to DATA. DATA may be a single value or a list.
d77dae5c
DL
1204See `help-make-xrefs'.
1205If optional arg HELP-ECHO is supplied, it is used as a help string."
5f373960
RS
1206 ;; Don't mung properties we've added specially in some instances.
1207 (unless (get-text-property (match-beginning match-number) 'help-xref)
1208 (add-text-properties (match-beginning match-number)
1209 (match-end match-number)
1210 (list 'mouse-face 'highlight
1211 'help-xref (cons function
1212 (if (listp data)
1213 data
1214 (list data)))))
d77dae5c
DL
1215 (if help-echo
1216 (put-text-property (match-beginning match-number)
1217 (match-end match-number)
1218 'help-echo help-echo))
5f373960
RS
1219 (if help-highlight-p
1220 (put-text-property (match-beginning match-number)
1221 (match-end match-number)
1222 'face help-highlight-face))))
400a1b1f
RS
1223
1224\f
1225;; Additional functions for (re-)creating types of help buffers.
1226(defun help-xref-interned (symbol)
1227 "Follow a hyperlink which appeared to be an arbitrary interned SYMBOL.
1228
1229Both variable and function documentation are extracted into a single
1230help buffer."
950cf06f
DL
1231 (let ((fdoc (when (fboundp symbol) (describe-function symbol)))
1232 (facedoc (when (facep symbol) (describe-face symbol))))
accd1266
SM
1233 (when (or (boundp symbol) (not fdoc))
1234 (describe-variable symbol)
1235 ;; We now have a help buffer on the variable. Insert the function
1236 ;; text before it.
950cf06f 1237 (when (or fdoc facedoc)
accd1266
SM
1238 (with-current-buffer "*Help*"
1239 (goto-char (point-min))
1240 (let ((inhibit-read-only t))
950cf06f
DL
1241 (when fdoc
1242 (insert fdoc "\n\n"))
1243 (when facedoc
1244 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
1245 " is also a " "face." "\n\n" facedoc "\n\n"))
1246 (insert (make-string 30 ?-) "\n\n" (symbol-name symbol)
1247 " is also a " "variable." "\n\n"))
accd1266 1248 (help-setup-xref (list #'help-xref-interned symbol) nil))))))
400a1b1f
RS
1249
1250(defun help-xref-mode (buffer)
1251 "Do a `describe-mode' for the specified BUFFER."
1252 (save-excursion
1253 (set-buffer buffer)
1254 (describe-mode)))
1255\f
1256;;; Navigation/hyperlinking with xrefs
1257
1258(defun help-follow-mouse (click)
1259 "Follow the cross-reference that you click on."
1260 (interactive "e")
9b49f910
RS
1261 (let* ((start (event-start click))
1262 (window (car start))
1263 (pos (car (cdr start))))
1264 (with-current-buffer (window-buffer window)
400a1b1f
RS
1265 (help-follow pos))))
1266
613a39b9 1267(defun help-xref-go-back (buffer)
b2c85790 1268 "From BUFFER, go back to previous help buffer text using `help-xref-stack'."
4c45295b 1269 (let (item position method args)
613a39b9
RS
1270 (with-current-buffer buffer
1271 (when help-xref-stack
1272 (setq help-xref-stack (cdr help-xref-stack)) ; due to help-follow
376b2a24 1273 (setq item (pop help-xref-stack)
4c45295b
KH
1274 position (car item)
1275 method (cadr item)
376b2a24 1276 args (cddr item))))
4c45295b 1277 (apply method args)
376b2a24
DL
1278 ;; We assume that the buffer we just recreated has the saved name,
1279 ;; which might not always be true.
1280 (when (get-buffer (cdr position))
1281 (with-current-buffer (cdr position)
1282 (goto-char (car position))))))
400a1b1f
RS
1283
1284(defun help-go-back ()
b2c85790 1285 "Invoke the [back] button (if any) in the Help mode buffer."
400a1b1f
RS
1286 (interactive)
1287 (help-follow (1- (point-max))))
1288
400c12fd 1289(defun help-follow (&optional pos)
400a1b1f
RS
1290 "Follow cross-reference at POS, defaulting to point.
1291
1292For the cross-reference format, see `help-make-xrefs'."
1293 (interactive "d")
400c12fd
DL
1294 (unless pos
1295 (setq pos (point)))
accd1266
SM
1296 (let* ((help-data
1297 (or (and (not (= pos (point-max)))
1298 (get-text-property pos 'help-xref))
1299 (and (not (= pos (point-min)))
1300 (get-text-property (1- pos) 'help-xref))
1301 ;; check if the symbol under point is a function or variable
1302 (let ((sym
1303 (intern
1304 (save-excursion
1305 (goto-char pos) (skip-syntax-backward "w_")
1306 (buffer-substring (point)
1307 (progn (skip-syntax-forward "w_")
1308 (point)))))))
1309 (when (or (boundp sym) (fboundp sym))
1310 (list #'help-xref-interned sym)))))
400a1b1f
RS
1311 (method (car help-data))
1312 (args (cdr help-data)))
400a1b1f 1313 (when help-data
376b2a24
DL
1314 (setq help-xref-stack (cons (cons (cons pos (buffer-name))
1315 help-xref-stack-item)
accd1266
SM
1316 help-xref-stack))
1317 (setq help-xref-stack-item nil)
400a1b1f 1318 ;; There is a reference at point. Follow it.
376b2a24
DL
1319 (let ((help-xref-following t))
1320 (apply method args)))))
400a1b1f
RS
1321
1322;; For tabbing through buffer.
1323(defun help-next-ref ()
1324 "Find the next help cross-reference in the buffer."
1325 (interactive)
1326 (let (pos)
1327 (while (not pos)
1328 (if (get-text-property (point) 'help-xref) ; move off reference
ff3453e4
DL
1329 (goto-char (or (next-single-property-change (point) 'help-xref)
1330 (point))))
400a1b1f
RS
1331 (cond ((setq pos (next-single-property-change (point) 'help-xref))
1332 (if pos (goto-char pos)))
1333 ((bobp)
1334 (message "No cross references in the buffer.")
1335 (setq pos t))
1336 (t ; be circular
1337 (goto-char (point-min)))))))
1338
1339(defun help-previous-ref ()
1340 "Find the previous help cross-reference in the buffer."
1341 (interactive)
1342 (let (pos)
1343 (while (not pos)
1344 (if (get-text-property (point) 'help-xref) ; move off reference
1345 (goto-char (or (previous-single-property-change (point) 'help-xref)
1346 (point))))
1347 (cond ((setq pos (previous-single-property-change (point) 'help-xref))
1348 (if pos (goto-char pos)))
1349 ((bobp)
1350 (message "No cross references in the buffer.")
1351 (setq pos t))
1352 (t ; be circular
1353 (goto-char (point-max)))))))
1354
48ce3c22
RS
1355\f
1356;;; Automatic resizing of temporary buffers.
1357
4483ddc5 1358(defcustom temp-buffer-resize-mode nil
48ce3c22 1359 "Non-nil means resize windows displaying temporary buffers.
ae29cb0c
KH
1360This makes the window the right height for its contents, but never
1361more than `temp-buffer-max-height' nor less than `window-min-height'.
1362This applies to `help', `apropos' and `completion' buffers, and some others.
48ce3c22 1363
e4aece0e
DL
1364Setting this variable directly does not take effect;
1365use either \\[customize] or the function `temp-buffer-resize-mode'."
48ce3c22
RS
1366 :get (lambda (symbol)
1367 (and (memq 'resize-temp-buffer-window temp-buffer-show-hook) t))
1368 :set (lambda (symbol value)
4483ddc5 1369 (temp-buffer-resize-mode (if value 1 -1)))
48ce3c22
RS
1370 :initialize 'custom-initialize-default
1371 :type 'boolean
1372 :group 'help
1373 :version "20.4")
1374
4483ddc5 1375(defcustom temp-buffer-max-height (lambda (buffer) (/ (- (frame-height) 2) 2))
48ce3c22
RS
1376 "*Maximum height of a window displaying a temporary buffer.
1377This is the maximum height (in text lines) which `resize-temp-buffer-window'
1378will give to a window displaying a temporary buffer.
1379It can also be a function which will be called with the object corresponding
1380to the buffer to be displayed as argument and should return an integer
1381positive number."
1382 :type '(choice integer function)
1383 :group 'help
1384 :version "20.4")
1385
4483ddc5
RS
1386(defun temp-buffer-resize-mode (arg)
1387 "Toggle the mode which that makes windows smaller for temporary buffers.
48ce3c22
RS
1388With prefix argument ARG, turn the resizing of windows displaying temporary
1389buffers on if ARG is positive or off otherwise.
4483ddc5 1390See the documentation of the variable `temp-buffer-resize-mode' for
48ce3c22
RS
1391more information."
1392 (interactive "P")
1393 (let ((turn-it-on
1394 (if (null arg)
1395 (not (memq 'resize-temp-buffer-window temp-buffer-show-hook))
1396 (> (prefix-numeric-value arg) 0))))
1397 (if turn-it-on
1398 (progn
1399 ;; `help-mode-maybe' may add a `back' button and thus increase the
1400 ;; text size, so `resize-temp-buffer-window' must be run *after* it.
1401 (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
4483ddc5 1402 (setq temp-buffer-resize-mode t))
48ce3c22 1403 (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)
4483ddc5 1404 (setq temp-buffer-resize-mode nil))))
48ce3c22
RS
1405
1406(defun resize-temp-buffer-window ()
1407 "Resize the current window to fit its contents.
4483ddc5 1408Will not make it higher than `temp-buffer-max-height' nor smaller than
b2c85790 1409`window-min-height'. Do nothing if it is the only window on its frame, if it
48ce3c22
RS
1410is not as wide as the frame or if some of the window's contents are scrolled
1411out of view."
1412 (unless (or (one-window-p 'nomini)
1413 (not (pos-visible-in-window-p (point-min)))
1414 (/= (frame-width) (window-width)))
4483ddc5
RS
1415 (let* ((max-height (if (functionp temp-buffer-max-height)
1416 (funcall temp-buffer-max-height (current-buffer))
1417 temp-buffer-max-height))
48ce3c22
RS
1418 (win-height (1- (window-height)))
1419 (min-height (1- window-min-height))
586b3759 1420 (text-height (count-screen-lines))
48ce3c22
RS
1421 (new-height (max (min text-height max-height) min-height)))
1422 (enlarge-window (- new-height win-height)))))
1423
f0d0fb19
DL
1424;; `help-manyarg-func-alist' is defined primitively (in doc.c).
1425;; New primitives with `MANY' or `UNEVALLED' arglists should be added
1426;; to this alist.
1427;; The parens and function name are redundant, but it's messy to add
1428;; them in `documentation'.
1429(defconst help-manyarg-func-alist
1430 (purecopy
1431 '((list . "(list &rest OBJECTS)")
1432 (vector . "(vector &rest OBJECTS)")
1433 (make-byte-code . "(make-byte-code &rest ELEMENTS)")
1434 (call-process
1435 . "(call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)")
e3e36d74
DL
1436 (call-process-region
1437 . "(call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS)")
f0d0fb19
DL
1438 (string . "(string &rest CHARACTERS)")
1439 (+ . "(+ &rest NUMBERS-OR-MARKERS)")
1440 (- . "(- &optional NUMBER-OR-MARKER &rest MORE-NUMBERS-OR-MARKERS)")
1441 (* . "(* &rest NUMBERS-OR-MARKERS)")
1442 (/ . "(/ DIVIDEND DIVISOR &rest DIVISORS)")
1443 (max . "(max NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS)")
1444 (min . "(min NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS)")
1445 (logand . "(logand &rest INTS-OR-MARKERS)")
1446 (logior . "(logior &rest INTS-OR-MARKERS)")
1447 (logxor . "(logxor &rest INTS-OR-MARKERS)")
1448 (encode-time
1449 . "(encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE)")
1450 (insert . "(insert &rest ARGS)")
1451 (insert-before-markers . "(insert-before-markers &rest ARGS)")
1452 (message . "(message STRING &rest ARGUMENTS)")
1453 (message-box . "(message-box STRING &rest ARGUMENTS)")
1454 (message-or-box . "(message-or-box STRING &rest ARGUMENTS)")
1455 (propertize . "(propertize STRING &rest PROPERTIES)")
1456 (format . "(format STRING &rest OBJECTS)")
1457 (apply . "(apply FUNCTION &rest ARGUMENTS)")
1458 (run-hooks . "(run-hooks &rest HOOKS)")
2de47765
DL
1459 (run-hook-with-args . "(run-hook-with-args HOOK &rest ARGS)")
1460 (run-hook-with-args-until-failure
1461 . "(run-hook-with-args-until-failure HOOK &rest ARGS)")
1462 (run-hook-with-args-until-success
1463 . "(run-hook-with-args-until-success HOOK &rest ARGS)")
f0d0fb19
DL
1464 (funcall . "(funcall FUNCTION &rest ARGUMENTS)")
1465 (append . "(append &rest SEQUENCES)")
1466 (concat . "(concat &rest SEQUENCES)")
1467 (vconcat . "(vconcat vconcat)")
1468 (nconc . "(nconc &rest LISTS)")
1469 (widget-apply . "(widget-apply WIDGET PROPERTY &rest ARGS)")
1470 (make-hash-table . "(make-hash-table &rest KEYWORD-ARGS)")
1471 (insert-string . "(insert-string &rest ARGS)")
1472 (start-process . "(start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)")
1473 (setq-default . "(setq-default SYMBOL VALUE [SYMBOL VALUE...])")
1474 (save-excursion . "(save-excursion &rest BODY)")
1475 (save-current-buffer . "(save-current-buffer &rest BODY)")
1476 (save-restriction . "(save-restriction &rest BODY)")
1477 (or . "(or CONDITIONS ...)")
1478 (and . "(and CONDITIONS ...)")
1479 (if . "(if COND THEN ELSE...)")
1480 (cond . "(cond CLAUSES...)")
1481 (progn . "(progn BODY ...)")
1482 (prog1 . "(prog1 FIRST BODY...)")
1483 (prog2 . "(prog2 X Y BODY...)")
1484 (setq . "(setq SYM VAL SYM VAL ...)")
1485 (quote . "(quote ARG)")
1486 (function . "(function ARG)")
1487 (defun . "(defun NAME ARGLIST [DOCSTRING] BODY...)")
1488 (defmacro . "(defmacro NAME ARGLIST [DOCSTRING] BODY...)")
1489 (defvar . "(defvar SYMBOL [INITVALUE DOCSTRING])")
1490 (defconst . "(defconst SYMBOL INITVALUE [DOCSTRING])")
1491 (let* . "(let* VARLIST BODY...)")
1492 (let . "(let VARLIST BODY...)")
1493 (while . "(while TEST BODY...)")
1494 (catch . "(catch TAG BODY...)")
1495 (unwind-protect . "(unwind-protect BODYFORM UNWINDFORMS...)")
1496 (condition-case . "(condition-case VAR BODYFORM HANDLERS...)")
194959c7 1497 (track-mouse . "(track-mouse BODY ...)")
2de47765
DL
1498 (ml-if . "(ml-if COND THEN ELSE...)")
1499 (ml-provide-prefix-argument . "(ml-provide-prefix-argument ARG1 ARG2)")
1500 (with-output-to-temp-buffer
1501 . "(with-output-to-temp-buffer BUFFNAME BODY ...)")
1502 (save-window-excursion . "(save-window-excursion BODY ...)"))))
f0d0fb19 1503
1a06eabd 1504;;; help.el ends here