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