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