(syms_of_print): Doc fixes.
[bpt/emacs.git] / lisp / ehelp.el
CommitLineData
c0274f38
ER
1;;; ehelp.el --- bindings for electric-help mode
2
732be465 3;; Copyright (C) 1986, 1995 Free Software Foundation, Inc.
3a801d0c 4
e5167999 5;; Maintainer: FSF
fd7fa35a 6;; Keywords: help, extensions
e5167999 7
a2535589
JA
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)
a2535589
JA
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.
a2535589 24
e41b2db1
ER
25;;; Commentary:
26
27;; This package provides a pre-packaged `Electric Help Mode' for
28;; browsing on-line help screens. There is one entry point,
9dd2b34e 29;; `with-electric-help'; all you have to give it is a no-argument
1b3250ab 30;; function that generates the actual text of the help into the current
e41b2db1
ER
31;; buffer.
32
bbe2ecf6
RS
33;; To make this the default, you must do
34;; (require 'ehelp)
35;; (define-key global-map "\C-h" 'ehelp-command)
36;; (define-key global-map [help] 'ehelp-command)
37;; (define-key global-map [f1] 'ehelp-command)
38
e5167999
ER
39;;; Code:
40
a2535589 41(require 'electric)
a2535589 42(defvar electric-help-map ()
d5b9d1d8 43 "Keymap defining commands available in `electric-help-mode'.")
a2535589 44
db30b383
RS
45(defvar electric-help-form-to-execute nil)
46
d05c87ac
GM
47(defgroup electric-help ()
48 "Electric help facility."
49 :version "21.1"
50 :group 'help)
51
52(defcustom electric-help-shrink-window t
53 "If set, adjust help window sizes to buffer sizes when displaying help."
54 :type 'boolean
55 :group 'electric-help)
56
a2535589
JA
57(put 'electric-help-undefined 'suppress-keymap t)
58(if electric-help-map
59 ()
60 (let ((map (make-keymap)))
f98e758c
RS
61 ;; allow all non-self-inserting keys - search, scroll, etc, but
62 ;; let M-x and C-x exit ehelp mode and retain buffer:
e27ef4db 63 (suppress-keymap map)
f98e758c
RS
64 (define-key map "\C-u" 'electric-help-undefined)
65 (define-key map [?\C-0] 'electric-help-undefined)
66 (define-key map [?\C-1] 'electric-help-undefined)
67 (define-key map [?\C-2] 'electric-help-undefined)
68 (define-key map [?\C-3] 'electric-help-undefined)
69 (define-key map [?\C-4] 'electric-help-undefined)
70 (define-key map [?\C-5] 'electric-help-undefined)
71 (define-key map [?\C-6] 'electric-help-undefined)
72 (define-key map [?\C-7] 'electric-help-undefined)
73 (define-key map [?\C-8] 'electric-help-undefined)
74 (define-key map [?\C-9] 'electric-help-undefined)
a2535589
JA
75 (define-key map (char-to-string help-char) 'electric-help-help)
76 (define-key map "?" 'electric-help-help)
77 (define-key map " " 'scroll-up)
78 (define-key map "\^?" 'scroll-down)
79 (define-key map "." 'beginning-of-buffer)
80 (define-key map "<" 'beginning-of-buffer)
81 (define-key map ">" 'end-of-buffer)
82 ;(define-key map "\C-g" 'electric-help-exit)
83 (define-key map "q" 'electric-help-exit)
84 (define-key map "Q" 'electric-help-exit)
85 ;;a better key than this?
86 (define-key map "r" 'electric-help-retain)
e27ef4db 87 (define-key map "R" 'electric-help-retain)
f98e758c
RS
88 (define-key map "\ex" 'electric-help-execute-extended)
89 (define-key map "\C-x" 'electric-help-ctrl-x-prefix)
a2535589
JA
90
91 (setq electric-help-map map)))
f98e758c 92
a2535589 93(defun electric-help-mode ()
d5b9d1d8
JB
94 "`with-electric-help' temporarily places its buffer in this mode.
95\(On exit from `with-electric-help', the buffer is put in `default-major-mode'.)"
a2535589
JA
96 (setq buffer-read-only t)
97 (setq mode-name "Help")
98 (setq major-mode 'help)
99 (setq mode-line-buffer-identification '(" Help: %b"))
100 (use-local-map electric-help-map)
2e8174d2 101 (add-hook 'mouse-leave-buffer-hook 'electric-help-retain)
db30b383 102 (view-mode -1)
a2535589
JA
103 ;; this is done below in with-electric-help
104 ;(run-hooks 'electric-help-mode-hook)
105 )
106
9dd2b34e 107;;;###autoload
483a5ec0 108(defun with-electric-help (thunk &optional buffer noerase minheight)
bbe2ecf6 109 "Pop up an \"electric\" help buffer.
f98e758c
RS
110The arguments are THUNK &optional BUFFER NOERASE MINHEIGHT.
111THUNK is a function of no arguments which is called to initialize the
112contents of BUFFER. BUFFER defaults to `*Help*'. BUFFER will be
113erased before THUNK is called unless NOERASE is non-nil. THUNK will
114be called while BUFFER is current and with `standard-output' bound to
bbe2ecf6
RS
115the buffer specified by BUFFER.
116
117If THUNK returns nil, we display BUFFER starting at the top, and
118shrink the window to fit. If THUNK returns non-nil, we don't do those things.
a2535589
JA
119
120After THUNK has been called, this function \"electrically\" pops up a window
121in which BUFFER is displayed and allows the user to scroll through that buffer
f98e758c
RS
122in electric-help-mode. The window's height will be at least MINHEIGHT if
123this value is non-nil.
124
125If THUNK returns nil, we display BUFFER starting at the top, and
d05c87ac
GM
126shrink the window to fit if `electric-help-shrink-window' is non-nil.
127If THUNK returns non-nil, we don't do those things.
f98e758c 128
f55e4a7e
EZ
129When the user exits (with `electric-help-exit', or otherwise), the help
130buffer's window disappears (i.e., we use `save-window-excursion'), and
9dd2b34e 131BUFFER is put into `default-major-mode' (or `fundamental-mode') when we exit."
a2535589
JA
132 (setq buffer (get-buffer-create (or buffer "*Help*")))
133 (let ((one (one-window-p t))
88c269cb 134 (config (current-window-configuration))
f98e758c 135 (bury nil)
db30b383 136 (electric-help-form-to-execute nil))
88c269cb 137 (unwind-protect
138 (save-excursion
d05c87ac
GM
139 (when one
140 (goto-char (window-start (selected-window))))
88c269cb 141 (let ((pop-up-windows t))
142 (pop-to-buffer buffer))
143 (save-excursion
144 (set-buffer buffer)
d05c87ac
GM
145 (when (and minheight (< (window-height) minheight))
146 (enlarge-window (- minheight (window-height))))
88c269cb 147 (electric-help-mode)
e024a2f4 148 (setq buffer-read-only nil)
d05c87ac
GM
149 (unless noerase
150 (erase-buffer)))
88c269cb 151 (let ((standard-output buffer))
d05c87ac
GM
152 (unless (funcall thunk)
153 (set-buffer buffer)
154 (set-buffer-modified-p nil)
155 (goto-char (point-min))
156 (when (and one electric-help-shrink-window)
157 (shrink-window-if-larger-than-buffer))))
88c269cb 158 (set-buffer buffer)
159 (run-hooks 'electric-help-mode-hook)
e024a2f4 160 (setq buffer-read-only t)
d05c87ac 161 (if (eq (car-safe (electric-help-command-loop)) 'retain)
88c269cb 162 (setq config (current-window-configuration))
d05c87ac 163 (setq bury t))
9201fa06 164 ;; Remove the hook.
d05c87ac
GM
165 (when (memq 'electric-help-retain mouse-leave-buffer-hook)
166 (remove-hook 'mouse-leave-buffer-hook 'electric-help-retain)))
88c269cb 167 (message "")
168 (set-buffer buffer)
169 (setq buffer-read-only nil)
d05c87ac
GM
170
171 ;; We should really get a usable *Help* buffer when retaining
172 ;; the electric one with `r'. The problem is that a simple
f55e4a7e 173 ;; call to help-mode won't cut it; at least RET is bound wrong
d05c87ac
GM
174 ;; afterwards. It's also not clear that `help-mode' is always
175 ;; the right thing, maybe we should add an optional parameter.
88c269cb 176 (condition-case ()
177 (funcall (or default-major-mode 'fundamental-mode))
178 (error nil))
d05c87ac 179
88c269cb 180 (set-window-configuration config)
d05c87ac 181 (when bury
f55e4a7e 182 ;;>> Perhaps this shouldn't be done,
d05c87ac
GM
183 ;; so that when we say "Press space to bury" we mean it
184 (replace-buffer-in-windows buffer)
185 ;; must do this outside of save-window-excursion
186 (bury-buffer buffer))
db30b383 187 (eval electric-help-form-to-execute))))
a2535589
JA
188
189(defun electric-help-command-loop ()
190 (catch 'exit
191 (if (pos-visible-in-window-p (point-max))
7bccdfbc 192 (progn (message "%s" (substitute-command-keys "<<< Press Space to bury the help buffer, Press \\[electric-help-retain] to retain it >>>"))
70447f8c
RS
193 (if (equal (setq unread-command-events (list (read-event)))
194 '(?\ ))
dbc4e1c1 195 (progn (setq unread-command-events nil)
a2535589
JA
196 (throw 'exit t)))))
197 (let (up down both neither
198 (standard (and (eq (key-binding " ")
199 'scroll-up)
200 (eq (key-binding "\^?")
201 'scroll-down)
a2535589 202 (eq (key-binding "q")
e27ef4db
RS
203 'electric-help-exit)
204 (eq (key-binding "r")
205 'electric-help-retain))))
a2535589
JA
206 (Electric-command-loop
207 'exit
208 (function (lambda ()
f98e758c
RS
209 (sit-for 0) ;necessary if last command was end-of-buffer or
210 ;beginning-of-buffer - otherwise pos-visible-in-window-p
211 ;will yield a wrong result.
a2535589
JA
212 (let ((min (pos-visible-in-window-p (point-min)))
213 (max (pos-visible-in-window-p (point-max))))
f98e758c
RS
214 (cond (isearch-mode 'noprompt)
215 ((and min max)
e27ef4db 216 (cond (standard "Press q to exit, r to retain ")
a2535589 217 (neither)
e27ef4db 218 (t (setq neither (substitute-command-keys "Press \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 219 (min
e27ef4db 220 (cond (standard "Press SPC to scroll, q to exit, r to retain ")
a2535589 221 (up)
e27ef4db 222 (t (setq up (substitute-command-keys "Press \\[scroll-up] to scroll, \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 223 (max
f98e758c 224 (cond (standard "Press DEL to scroll back, q to exit, r to retain ")
a2535589 225 (down)
e27ef4db 226 (t (setq down (substitute-command-keys "Press \\[scroll-down] to scroll back, \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 227 (t
f98e758c 228 (cond (standard "Press SPC to scroll, DEL to scroll back, q to exit, r to retain ")
a2535589 229 (both)
e27ef4db 230 (t (setq both (substitute-command-keys "Press \\[scroll-up] to scroll, \\[scroll-down] to scroll back, \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))))))
a2535589
JA
231 t))))
232
233
234\f
235;(defun electric-help-scroll-up (arg)
236; ">>>Doc"
237; (interactive "P")
238; (if (and (null arg) (pos-visible-in-window-p (point-max)))
239; (electric-help-exit)
240; (scroll-up arg)))
241
242(defun electric-help-exit ()
9201fa06
RS
243 "Exit `electric-help', restoring the previous window/buffer configuration.
244\(The *Help* buffer will be buried.)"
a2535589 245 (interactive)
9201fa06
RS
246 ;; Make sure that we don't throw twice, even if two events cause
247 ;; calling this function:
248 (if (memq 'electric-help-retain mouse-leave-buffer-hook)
249 (progn
250 (remove-hook 'mouse-leave-buffer-hook 'electric-help-retain)
251 (throw 'exit t))))
a2535589
JA
252
253(defun electric-help-retain ()
d5b9d1d8 254 "Exit `electric-help', retaining the current window/buffer configuration.
a2535589
JA
255\(The *Help* buffer will not be selected, but \\[switch-to-buffer-other-window] RET
256will select it.)"
257 (interactive)
f98e758c
RS
258 ;; Make sure that we don't throw twice, even if two events cause
259 ;; calling this function:
2e8174d2
RS
260 (if (memq 'electric-help-retain mouse-leave-buffer-hook)
261 (progn
262 (remove-hook 'mouse-leave-buffer-hook 'electric-help-retain)
263 (throw 'exit '(retain)))))
a2535589
JA
264
265
a2535589
JA
266(defun electric-help-undefined ()
267 (interactive)
268 (error "%s is undefined -- Press %s to exit"
269 (mapconcat 'single-key-description (this-command-keys) " ")
f98e758c
RS
270 (if (eq (key-binding "q") 'electric-help-exit)
271 "q"
a2535589
JA
272 (substitute-command-keys "\\[electric-help-exit]"))))
273
274
275;>>> this needs to be hairified (recursive help, anybody?)
276(defun electric-help-help ()
277 (interactive)
e27ef4db 278 (if (and (eq (key-binding "q") 'electric-help-exit)
a2535589 279 (eq (key-binding " ") 'scroll-up)
e27ef4db
RS
280 (eq (key-binding "\^?") 'scroll-down)
281 (eq (key-binding "r") 'electric-help-retain))
282 (message "SPC scrolls up, DEL scrolls down, q exits burying help buffer, r exits")
283 (message "%s" (substitute-command-keys "\\[scroll-up] scrolls up, \\[scroll-down] scrolls down, \\[electric-help-exit] exits burying help buffer, \\[electric-help-retain] exits")))
a2535589
JA
284 (sit-for 2))
285
286\f
9dd2b34e 287;;;###autoload
1676b298
RS
288(defun electric-helpify (fun &optional name)
289 (let ((name (or name "*Help*")))
a2535589
JA
290 (if (save-window-excursion
291 ;; kludge-o-rama
292 (let* ((p (symbol-function 'print-help-return-message))
293 (b (get-buffer name))
294 (m (buffer-modified-p b)))
295 (and b (not (get-buffer-window b))
296 (setq b nil))
297 (unwind-protect
298 (progn
299 (message "%s..." (capitalize (symbol-name fun)))
300 ;; with-output-to-temp-buffer marks the buffer as unmodified.
301 ;; kludging excessively and relying on that as some sort
302 ;; of indication leads to the following abomination...
303 ;;>> This would be doable without such icky kludges if either
304 ;;>> (a) there were a function to read the interactive
305 ;;>> args for a command and return a list of those args.
306 ;;>> (To which one would then just apply the command)
307 ;;>> (The only problem with this is that interactive-p
308 ;;>> would break, but that is such a misfeature in
309 ;;>> any case that I don't care)
310 ;;>> It is easy to do this for emacs-lisp functions;
311 ;;>> the only problem is getting the interactive spec
312 ;;>> for subrs
313 ;;>> (b) there were a function which returned a
314 ;;>> modification-tick for a buffer. One could tell
315 ;;>> whether a buffer had changed by whether the
316 ;;>> modification-tick were different.
317 ;;>> (Presumably there would have to be a way to either
318 ;;>> restore the tick to some previous value, or to
319 ;;>> suspend updating of the tick in order to allow
320 ;;>> things like momentary-string-display)
321 (and b
322 (save-excursion
323 (set-buffer b)
324 (set-buffer-modified-p t)))
325 (fset 'print-help-return-message 'ignore)
326 (call-interactively fun)
327 (and (get-buffer name)
328 (get-buffer-window (get-buffer name))
329 (or (not b)
330 (not (eq b (get-buffer name)))
331 (not (buffer-modified-p b)))))
332 (fset 'print-help-return-message p)
333 (and b (buffer-name b)
334 (save-excursion
335 (set-buffer b)
336 (set-buffer-modified-p m))))))
337 (with-electric-help 'ignore name t))))
338
339\f
f98e758c
RS
340
341;; This is to be bound to M-x in ehelp mode. Retains ehelp buffer and then
342;; continues with execute-extended-command.
343(defun electric-help-execute-extended (prefixarg)
344 (interactive "p")
db30b383 345 (setq electric-help-form-to-execute '(execute-extended-command nil))
f98e758c
RS
346 (electric-help-retain))
347
348;; This is to be buond to C-x in ehelp mode. Retains ehelp buffer and then
349;; continues with ctrl-x prefix.
350(defun electric-help-ctrl-x-prefix (prefixarg)
351 (interactive "p")
db30b383 352 (setq electric-help-form-to-execute '(progn (message nil) (setq unread-command-char ?\C-x)))
f98e758c
RS
353 (electric-help-retain))
354
355\f
a2535589
JA
356(defun electric-describe-key ()
357 (interactive)
358 (electric-helpify 'describe-key))
359
360(defun electric-describe-mode ()
361 (interactive)
362 (electric-helpify 'describe-mode))
363
364(defun electric-view-lossage ()
365 (interactive)
366 (electric-helpify 'view-lossage))
367
368;(defun electric-help-for-help ()
369; "See help-for-help"
370; (interactive)
371; )
372
373(defun electric-describe-function ()
374 (interactive)
375 (electric-helpify 'describe-function))
376
377(defun electric-describe-variable ()
378 (interactive)
379 (electric-helpify 'describe-variable))
380
381(defun electric-describe-bindings ()
382 (interactive)
383 (electric-helpify 'describe-bindings))
384
385(defun electric-describe-syntax ()
386 (interactive)
387 (electric-helpify 'describe-syntax))
388
389(defun electric-command-apropos ()
390 (interactive)
1676b298 391 (electric-helpify 'command-apropos "*Apropos*"))
a2535589
JA
392
393;(define-key help-map "a" 'electric-command-apropos)
394
e27ef4db
RS
395(defun electric-apropos ()
396 (interactive)
397 (electric-helpify 'apropos))
a2535589 398
a2535589
JA
399\f
400;;;; ehelp-map
401
402(defvar ehelp-map ())
403(if ehelp-map
404 nil
405 (let ((map (copy-keymap help-map)))
f98e758c 406 (substitute-key-definition 'apropos 'electric-apropos map)
e27ef4db 407 (substitute-key-definition 'command-apropos 'electric-command-apropos map)
a2535589
JA
408 (substitute-key-definition 'describe-key 'electric-describe-key map)
409 (substitute-key-definition 'describe-mode 'electric-describe-mode map)
410 (substitute-key-definition 'view-lossage 'electric-view-lossage map)
411 (substitute-key-definition 'describe-function 'electric-describe-function map)
412 (substitute-key-definition 'describe-variable 'electric-describe-variable map)
413 (substitute-key-definition 'describe-bindings 'electric-describe-bindings map)
414 (substitute-key-definition 'describe-syntax 'electric-describe-syntax map)
415
416 (setq ehelp-map map)
417 (fset 'ehelp-command map)))
418
49116ac0
JB
419(provide 'ehelp)
420
c0274f38 421;;; ehelp.el ends here