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