* net/tramp.el (tramp-get-ls-command)
[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
9c13a46e
JL
97(defvar electric-help-orig-major-mode nil)
98(make-variable-buffer-local 'electric-help-orig-major-mode)
99
a2535589 100(defun electric-help-mode ()
d5b9d1d8 101 "`with-electric-help' temporarily places its buffer in this mode.
9c13a46e 102\(On exit from `with-electric-help', the original `major-mode' is restored.)"
a2535589 103 (setq buffer-read-only t)
9c13a46e 104 (setq electric-help-orig-major-mode major-mode)
a2535589
JA
105 (setq mode-name "Help")
106 (setq major-mode 'help)
107 (setq mode-line-buffer-identification '(" Help: %b"))
108 (use-local-map electric-help-map)
2e8174d2 109 (add-hook 'mouse-leave-buffer-hook 'electric-help-retain)
db30b383 110 (view-mode -1)
a2535589
JA
111 ;; this is done below in with-electric-help
112 ;(run-hooks 'electric-help-mode-hook)
113 )
114
9dd2b34e 115;;;###autoload
483a5ec0 116(defun with-electric-help (thunk &optional buffer noerase minheight)
bbe2ecf6 117 "Pop up an \"electric\" help buffer.
f98e758c
RS
118THUNK is a function of no arguments which is called to initialize the
119contents of BUFFER. BUFFER defaults to `*Help*'. BUFFER will be
120erased before THUNK is called unless NOERASE is non-nil. THUNK will
121be called while BUFFER is current and with `standard-output' bound to
bbe2ecf6
RS
122the buffer specified by BUFFER.
123
3fd29551
JB
124If THUNK returns nil, we display BUFFER starting at the top, and shrink
125the window to fit. If THUNK returns non-nil, we don't do those things.
a2535589 126
3fd29551
JB
127After THUNK has been called, this function \"electrically\" pops up a
128window in which BUFFER is displayed and allows the user to scroll
129through that buffer in `electric-help-mode'. The window's height will
130be at least MINHEIGHT if this value is non-nil.
f98e758c
RS
131
132If THUNK returns nil, we display BUFFER starting at the top, and
d05c87ac
GM
133shrink the window to fit if `electric-help-shrink-window' is non-nil.
134If THUNK returns non-nil, we don't do those things.
f98e758c 135
f55e4a7e
EZ
136When the user exits (with `electric-help-exit', or otherwise), the help
137buffer's window disappears (i.e., we use `save-window-excursion'), and
9c13a46e 138BUFFER is put back into its original major mode."
a2535589
JA
139 (setq buffer (get-buffer-create (or buffer "*Help*")))
140 (let ((one (one-window-p t))
88c269cb 141 (config (current-window-configuration))
f98e758c 142 (bury nil)
db30b383 143 (electric-help-form-to-execute nil))
88c269cb 144 (unwind-protect
145 (save-excursion
d05c87ac
GM
146 (when one
147 (goto-char (window-start (selected-window))))
88c269cb 148 (let ((pop-up-windows t))
149 (pop-to-buffer buffer))
14acf2f5 150 (with-current-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 176
9c13a46e 177 ;; Restore the original major mode saved by `electric-help-mode'.
d05c87ac
GM
178 ;; We should really get a usable *Help* buffer when retaining
179 ;; the electric one with `r'. The problem is that a simple
9c13a46e
JL
180 ;; call to `help-mode' won't cut it; e.g. RET is bound wrong
181 ;; afterwards (`View-scroll-line-forward' instead of `help-follow').
182 ;; That's because Help mode should be set with `with-help-window'
183 ;; instead of the direct call to `help-mode'. But at least
184 ;; RET works correctly on links after using `help-mode'.
185 ;; This is satisfactory enough.
88c269cb 186 (condition-case ()
9c13a46e 187 (funcall (or electric-help-orig-major-mode 'fundamental-mode))
88c269cb 188 (error nil))
71296446 189
88c269cb 190 (set-window-configuration config)
d05c87ac 191 (when bury
f55e4a7e 192 ;;>> Perhaps this shouldn't be done,
d05c87ac
GM
193 ;; so that when we say "Press space to bury" we mean it
194 (replace-buffer-in-windows buffer)
195 ;; must do this outside of save-window-excursion
196 (bury-buffer buffer))
db30b383 197 (eval electric-help-form-to-execute))))
a2535589
JA
198
199(defun electric-help-command-loop ()
200 (catch 'exit
201 (if (pos-visible-in-window-p (point-max))
7bccdfbc 202 (progn (message "%s" (substitute-command-keys "<<< Press Space to bury the help buffer, Press \\[electric-help-retain] to retain it >>>"))
70447f8c 203 (if (equal (setq unread-command-events (list (read-event)))
3d5b307e 204 '(?\s))
dbc4e1c1 205 (progn (setq unread-command-events nil)
a2535589
JA
206 (throw 'exit t)))))
207 (let (up down both neither
e0db3d3f 208 (standard (and (eq (key-binding " " nil t)
a2535589 209 'scroll-up)
e0db3d3f 210 (eq (key-binding "\^?" nil t)
a2535589 211 'scroll-down)
e0db3d3f 212 (eq (key-binding "q" nil t)
e27ef4db 213 'electric-help-exit)
e0db3d3f 214 (eq (key-binding "r" nil t)
e27ef4db 215 'electric-help-retain))))
a2535589
JA
216 (Electric-command-loop
217 'exit
218 (function (lambda ()
71296446
JB
219 (sit-for 0) ;necessary if last command was end-of-buffer or
220 ;beginning-of-buffer - otherwise pos-visible-in-window-p
f98e758c 221 ;will yield a wrong result.
a2535589 222 (let ((min (pos-visible-in-window-p (point-min)))
1d4c1257 223 (max (pos-visible-in-window-p (1- (point-max)))))
f98e758c
RS
224 (cond (isearch-mode 'noprompt)
225 ((and min max)
e27ef4db 226 (cond (standard "Press q to exit, r to retain ")
a2535589 227 (neither)
e27ef4db 228 (t (setq neither (substitute-command-keys "Press \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 229 (min
e27ef4db 230 (cond (standard "Press SPC to scroll, q to exit, r to retain ")
a2535589 231 (up)
e27ef4db 232 (t (setq up (substitute-command-keys "Press \\[scroll-up] to scroll, \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 233 (max
f98e758c 234 (cond (standard "Press DEL to scroll back, q to exit, r to retain ")
a2535589 235 (down)
e27ef4db 236 (t (setq down (substitute-command-keys "Press \\[scroll-down] to scroll back, \\[electric-help-exit] to exit, \\[electric-help-retain] to retain ")))))
a2535589 237 (t
f98e758c 238 (cond (standard "Press SPC to scroll, DEL to scroll back, q to exit, r to retain ")
a2535589 239 (both)
e27ef4db 240 (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
241 t))))
242
243
244\f
245;(defun electric-help-scroll-up (arg)
246; ">>>Doc"
247; (interactive "P")
248; (if (and (null arg) (pos-visible-in-window-p (point-max)))
249; (electric-help-exit)
250; (scroll-up arg)))
251
252(defun electric-help-exit ()
24501f03 253 "Exit `with-electric-help', restoring the previous window/buffer configuration.
9201fa06 254\(The *Help* buffer will be buried.)"
a2535589 255 (interactive)
9201fa06
RS
256 ;; Make sure that we don't throw twice, even if two events cause
257 ;; calling this function:
258 (if (memq 'electric-help-retain mouse-leave-buffer-hook)
259 (progn
260 (remove-hook 'mouse-leave-buffer-hook 'electric-help-retain)
261 (throw 'exit t))))
a2535589
JA
262
263(defun electric-help-retain ()
24501f03 264 "Exit `with-electric-help', retaining the current window/buffer configuration.
a2535589
JA
265\(The *Help* buffer will not be selected, but \\[switch-to-buffer-other-window] RET
266will select it.)"
267 (interactive)
f98e758c
RS
268 ;; Make sure that we don't throw twice, even if two events cause
269 ;; calling this function:
2e8174d2
RS
270 (if (memq 'electric-help-retain mouse-leave-buffer-hook)
271 (progn
272 (remove-hook 'mouse-leave-buffer-hook 'electric-help-retain)
273 (throw 'exit '(retain)))))
a2535589
JA
274
275
a2535589
JA
276(defun electric-help-undefined ()
277 (interactive)
278 (error "%s is undefined -- Press %s to exit"
279 (mapconcat 'single-key-description (this-command-keys) " ")
e0db3d3f 280 (if (eq (key-binding "q" nil t) 'electric-help-exit)
f98e758c 281 "q"
a2535589
JA
282 (substitute-command-keys "\\[electric-help-exit]"))))
283
284
285;>>> this needs to be hairified (recursive help, anybody?)
286(defun electric-help-help ()
287 (interactive)
e0db3d3f
JB
288 (if (and (eq (key-binding "q" nil t) 'electric-help-exit)
289 (eq (key-binding " " nil t) 'scroll-up)
290 (eq (key-binding "\^?" nil t) 'scroll-down)
291 (eq (key-binding "r" nil t) 'electric-help-retain))
e27ef4db
RS
292 (message "SPC scrolls up, DEL scrolls down, q exits burying help buffer, r exits")
293 (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
294 (sit-for 2))
295
296\f
9dd2b34e 297;;;###autoload
1676b298
RS
298(defun electric-helpify (fun &optional name)
299 (let ((name (or name "*Help*")))
a2535589
JA
300 (if (save-window-excursion
301 ;; kludge-o-rama
d5d105e8 302 (let* ((p (symbol-function 'help-print-return-message))
a2535589
JA
303 (b (get-buffer name))
304 (m (buffer-modified-p b)))
305 (and b (not (get-buffer-window b))
306 (setq b nil))
307 (unwind-protect
308 (progn
309 (message "%s..." (capitalize (symbol-name fun)))
310 ;; with-output-to-temp-buffer marks the buffer as unmodified.
311 ;; kludging excessively and relying on that as some sort
312 ;; of indication leads to the following abomination...
313 ;;>> This would be doable without such icky kludges if either
314 ;;>> (a) there were a function to read the interactive
315 ;;>> args for a command and return a list of those args.
316 ;;>> (To which one would then just apply the command)
317 ;;>> (The only problem with this is that interactive-p
318 ;;>> would break, but that is such a misfeature in
319 ;;>> any case that I don't care)
320 ;;>> It is easy to do this for emacs-lisp functions;
321 ;;>> the only problem is getting the interactive spec
322 ;;>> for subrs
323 ;;>> (b) there were a function which returned a
324 ;;>> modification-tick for a buffer. One could tell
325 ;;>> whether a buffer had changed by whether the
326 ;;>> modification-tick were different.
327 ;;>> (Presumably there would have to be a way to either
328 ;;>> restore the tick to some previous value, or to
329 ;;>> suspend updating of the tick in order to allow
330 ;;>> things like momentary-string-display)
331 (and b
7fdbcd83 332 (with-current-buffer b
a2535589 333 (set-buffer-modified-p t)))
d5d105e8 334 (fset 'help-print-return-message 'ignore)
a2535589
JA
335 (call-interactively fun)
336 (and (get-buffer name)
337 (get-buffer-window (get-buffer name))
338 (or (not b)
339 (not (eq b (get-buffer name)))
340 (not (buffer-modified-p b)))))
d5d105e8 341 (fset 'help-print-return-message p)
a2535589 342 (and b (buffer-name b)
7fdbcd83 343 (with-current-buffer b
a2535589
JA
344 (set-buffer-modified-p m))))))
345 (with-electric-help 'ignore name t))))
346
347\f
f98e758c 348
71296446 349;; This is to be bound to M-x in ehelp mode. Retains ehelp buffer and then
f98e758c
RS
350;; continues with execute-extended-command.
351(defun electric-help-execute-extended (prefixarg)
352 (interactive "p")
db30b383 353 (setq electric-help-form-to-execute '(execute-extended-command nil))
f98e758c
RS
354 (electric-help-retain))
355
356;; This is to be buond to C-x in ehelp mode. Retains ehelp buffer and then
357;; continues with ctrl-x prefix.
358(defun electric-help-ctrl-x-prefix (prefixarg)
359 (interactive "p")
db30b383 360 (setq electric-help-form-to-execute '(progn (message nil) (setq unread-command-char ?\C-x)))
f98e758c
RS
361 (electric-help-retain))
362
363\f
a2535589
JA
364(defun electric-describe-key ()
365 (interactive)
366 (electric-helpify 'describe-key))
367
368(defun electric-describe-mode ()
369 (interactive)
370 (electric-helpify 'describe-mode))
371
372(defun electric-view-lossage ()
373 (interactive)
374 (electric-helpify 'view-lossage))
375
376;(defun electric-help-for-help ()
377; "See help-for-help"
378; (interactive)
379; )
380
381(defun electric-describe-function ()
382 (interactive)
383 (electric-helpify 'describe-function))
384
385(defun electric-describe-variable ()
386 (interactive)
387 (electric-helpify 'describe-variable))
388
389(defun electric-describe-bindings ()
390 (interactive)
391 (electric-helpify 'describe-bindings))
392
393(defun electric-describe-syntax ()
394 (interactive)
395 (electric-helpify 'describe-syntax))
396
397(defun electric-command-apropos ()
398 (interactive)
1676b298 399 (electric-helpify 'command-apropos "*Apropos*"))
a2535589
JA
400
401;(define-key help-map "a" 'electric-command-apropos)
402
e27ef4db
RS
403(defun electric-apropos ()
404 (interactive)
405 (electric-helpify 'apropos))
a2535589 406
a2535589
JA
407\f
408;;;; ehelp-map
409
3fd29551 410(defvar ehelp-map
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)
3fd29551 421 map))
6e5cbb63
RS
422
423;;;###(autoload 'ehelp-command "ehelp" "Prefix command for ehelp." t 'keymap)
424(defalias 'ehelp-command ehelp-map)
425(put 'ehelp-command 'documentation "Prefix command for ehelp.")
a2535589 426
71296446 427(provide 'ehelp)
49116ac0 428
cbee283d 429;; arch-tag: e0e3037f-42c0-433e-ba18-322c5d951f46
c0274f38 430;;; ehelp.el ends here