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