;;; help.el --- help commands for Emacs
-;; Copyright (C) 1985-1986, 1993-1994, 1998-2011
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1985-1986, 1993-1994, 1998-2013 Free Software
+;; Foundation, Inc.
;; Maintainer: FSF
;; Keywords: help, internal
;;; Commentary:
-;; This code implements GNU Emacs' on-line help system, the one invoked by
+;; This code implements GNU Emacs's on-line help system, the one invoked by
;; `M-x help-for-help'.
;;; Code:
(add-hook 'temp-buffer-setup-hook 'help-mode-setup)
(add-hook 'temp-buffer-show-hook 'help-mode-finish)
-;; The variable `help-window' below is used by `help-mode-finish' to
-;; communicate the window displaying help (the "help window") to the
-;; macro `with-help-window'. The latter sets `help-window' to t before
-;; invoking `with-output-to-temp-buffer'. If and only if `help-window'
-;; is eq to t, `help-mode-finish' (called by `temp-buffer-setup-hook')
-;; sets `help-window' to the window selected by `display-buffer'.
-;; Exiting `with-help-window' and calling `help-print-return-message'
-;; reset `help-window' to nil.
-(defvar help-window nil
- "Window chosen for displaying help.")
-
;; `help-window-point-marker' is a marker you can move to a valid
;; position of the buffer shown in the help window in order to override
;; the standard positioning mechanism (`point-min') chosen by
-;; `with-output-to-temp-buffer'. `with-help-window' has this point
-;; nowhere before exiting. Currently used by `view-lossage' to assert
-;; that the last keystrokes are always visible.
+;; `with-output-to-temp-buffer' and `with-temp-buffer-window'.
+;; `with-help-window' has this point nowhere before exiting. Currently
+;; used by `view-lossage' to assert that the last keystrokes are always
+;; visible.
(defvar help-window-point-marker (make-marker)
- "Marker to override default `window-point' of `help-window'.")
+ "Marker to override default `window-point' in help windows.")
(defvar help-map
(let ((map (make-sparse-keymap)))
"What to do to \"exit\" the help buffer.
This is a list
(WINDOW . t) delete the selected window (and possibly its frame,
- see `quit-window' and `View-quit'), go to WINDOW.
+ see `quit-window'), go to WINDOW.
(WINDOW . quit-window) do quit-window, then select WINDOW.
(WINDOW BUF START POINT) display BUF at START, POINT, then select WINDOW.")
If FUNCTION is nil, it applies `message', thus displaying the message.
In addition, this function sets up `help-return-method', which see, that
specifies what to do when the user exits the help buffer."
- ;; Reset `help-window' here to avoid confusing `help-mode-finish'.
- (setq help-window nil)
(and (not (get-buffer-window standard-output))
(let ((first-message
(cond ((or
;; Secondly, the buffer has not been displayed yet,
;; so we don't know whether its frame will be selected.
nil)
- (display-buffer-reuse-frames
- (setq help-return-method (cons (selected-window)
- 'quit-window))
- nil)
((not (one-window-p t))
(setq help-return-method
(cons (selected-window) 'quit-window))
(unless definition (error "No command"))
(let ((func (indirect-function definition))
(defs nil)
- (standard-output (if insert (current-buffer) t)))
+ (standard-output (if insert (current-buffer) standard-output)))
;; In DEFS, find all symbols that are aliases for DEFINITION.
(mapatoms (lambda (symbol)
(and (fboundp symbol)
(setq saved-yank-menu (copy-sequence yank-menu))
(menu-bar-update-yank-menu "(any string)" nil))
(setq key (read-key-sequence "Describe key (or click or menu item): "))
+ ;; Clear the echo area message (Bug#7014).
+ (message nil)
;; If KEY is a down-event, read and discard the
;; corresponding up-event. Note that there are also
;; down-events on scroll bars and mode lines: the actual
(aref key 1)
(aref key 0)))
(modifiers (event-modifiers event))
- (standard-output (if insert (current-buffer) t))
+ (standard-output (if insert (current-buffer) standard-output))
(mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers)
(memq 'drag modifiers)) " at that spot" ""))
(defn (key-binding key t))
For this to work correctly for a minor mode, the mode's indicator
variable \(listed in `minor-mode-alist') must also be a function
-whose documentation describes the minor mode."
+whose documentation describes the minor mode.
+
+If called from Lisp with a non-nil BUFFER argument, display
+documentation for the major and minor modes of that buffer."
(interactive "@")
(unless buffer (setq buffer (current-buffer)))
(help-setup-xref (list #'describe-mode buffer)
;; In order to list up all minor modes, minor-mode-list
;; is used here instead of minor-mode-alist.
(delq nil (mapcar 'symbol-name minor-mode-list)))
+
(defun describe-minor-mode-from-symbol (symbol)
"Display documentation of a minor mode given as a symbol, SYMBOL"
(interactive (list (intern (completing-read
(t
i))))
minor-mode-alist)))
+
(defun describe-minor-mode-from-indicator (indicator)
"Display documentation of a minor mode specified by INDICATOR.
If you call this function interactively, you can give indicator which
(error "Cannot find minor mode for `%s'" indicator))))
(defun lookup-minor-mode-from-indicator (indicator)
- "Return a minor mode symbol from its indicator on the modeline."
+ "Return a minor mode symbol from its indicator on the mode line."
;; remove first space if existed
(if (and (< 0 (length indicator))
(eq (aref indicator 0) ?\s))
minor-modes nil)
(setq minor-modes (cdr minor-modes)))))
result))
-
\f
;;; Automatic resizing of temporary buffers.
-
-(defcustom temp-buffer-max-height (lambda (buffer) (/ (- (frame-height) 2) 2))
+(defcustom temp-buffer-max-height
+ (lambda (buffer)
+ (if (eq (selected-window) (frame-root-window))
+ (/ (x-display-pixel-height) (frame-char-height) 2)
+ (/ (- (frame-height) 2) 2)))
"Maximum height of a window displaying a temporary buffer.
This is effective only when Temp Buffer Resize mode is enabled.
-The value is the maximum height (in lines) which `resize-temp-buffer-window'
-will give to a window displaying a temporary buffer.
-It can also be a function to be called to choose the height for such a buffer.
-It gets one argumemt, the buffer, and should return a positive integer."
+The value is the maximum height (in lines) which
+`resize-temp-buffer-window' will give to a window displaying a
+temporary buffer. It can also be a function to be called to
+choose the height for such a buffer. It gets one argument, the
+buffer, and should return a positive integer. At the time the
+function is called, the window to be resized is selected."
:type '(choice integer function)
:group 'help
- :version "20.4")
+ :version "24.3")
(define-minor-mode temp-buffer-resize-mode
- "Toggle the mode which makes windows smaller for temporary buffers.
-With prefix argument ARG, turn the resizing of windows displaying temporary
-buffers on if ARG is positive or off otherwise.
-This makes the window the right height for its contents, but never
-more than `temp-buffer-max-height' nor less than `window-min-height'.
-This applies to `help', `apropos' and `completion' buffers, and some others."
+ "Toggle auto-resizing temporary buffer windows (Temp Buffer Resize Mode).
+With a prefix argument ARG, enable Temp Buffer Resize mode if ARG
+is positive, and disable it otherwise. If called from Lisp,
+enable the mode if ARG is omitted or nil.
+
+When Temp Buffer Resize mode is enabled, the windows in which we
+show a temporary buffer are automatically resized in height to
+fit the buffer's contents, but never more than
+`temp-buffer-max-height' nor less than `window-min-height'.
+
+A window is resized only if it has been specially created for the
+buffer. Windows that have shown another buffer before are not
+resized. A frame is resized only if `fit-frame-to-buffer' is
+non-nil.
+
+This mode is used by `help', `apropos' and `completion' buffers,
+and some others."
:global t :group 'help
(if temp-buffer-resize-mode
;; `help-make-xrefs' may add a `back' button and thus increase the
(add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
(remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
-(defun resize-temp-buffer-window ()
- "Resize the selected window to fit its contents.
-Will not make it higher than `temp-buffer-max-height' nor smaller than
-`window-min-height'. Do nothing if it is the only window on its frame, if it
-is not as wide as the frame or if some of the window's contents are scrolled
-out of view."
- (unless (or (one-window-p 'nomini)
- (not (pos-visible-in-window-p (point-min)))
- (not (window-full-width-p)))
- (fit-window-to-buffer
- (selected-window)
- (if (functionp temp-buffer-max-height)
- (funcall temp-buffer-max-height (current-buffer))
- temp-buffer-max-height))))
-
-\f
-;;; help-window
-
+(defun resize-temp-buffer-window (&optional window)
+ "Resize WINDOW to fit its contents.
+WINDOW can be any live window and defaults to the selected one.
+
+Do not make WINDOW higher than `temp-buffer-max-height' nor
+smaller than `window-min-height'. Do nothing if WINDOW is not
+vertically combined, some of its contents are scrolled out of
+view, or WINDOW was not created by `display-buffer'."
+ (setq window (window-normalize-window window t))
+ (let ((buffer-name (buffer-name (window-buffer window))))
+ (let ((height (if (functionp temp-buffer-max-height)
+ (with-selected-window window
+ (funcall temp-buffer-max-height (window-buffer)))
+ temp-buffer-max-height))
+ (quit-cadr (cadr (window-parameter window 'quit-restore))))
+ (cond
+ ;; Resize WINDOW iff it was split off by `display-buffer'.
+ ((and (eq quit-cadr 'window)
+ (pos-visible-in-window-p (point-min) window)
+ (window-combined-p window))
+ (fit-window-to-buffer window height))
+ ;; Resize FRAME iff it was created by `display-buffer'.
+ ((and fit-frame-to-buffer
+ (eq quit-cadr 'frame)
+ (eq window (frame-root-window window)))
+ (let ((frame (window-frame window)))
+ (fit-frame-to-buffer
+ frame (+ (frame-height frame)
+ (- (window-total-size window))
+ height))))))))
+
+;;; Help windows.
(defcustom help-window-select 'other
"Non-nil means select help window for viewing.
Choices are:
never (nil) Select help window only if there is no other window
on its frame.
other Select help window unless the selected window is the
- only other window on its frame.
+ only other window on the help window's frame.
always (t) Always select the help window.
This option has effect if and only if the help window was created
:group 'help
:version "23.1")
-(defun help-window-display-message (quit-part window &optional other)
+(defcustom help-enable-auto-load t
+ "Whether Help commands can perform autoloading.
+If non-nil, whenever \\[describe-function] is called for an
+autoloaded function whose docstring contains any key substitution
+construct (see `substitute-command-keys'), the library is loaded,
+so that the documentation can show the right key bindings."
+ :type 'boolean
+ :group 'help
+ :version "24.3")
+
+(defun help-window-display-message (quit-part window &optional scroll)
"Display message telling how to quit and scroll help window.
QUIT-PART is a string telling how to quit the help window WINDOW.
-Optional argument OTHER non-nil means return text telling how to
-scroll the \"other\" window."
+Optional argument SCROLL non-nil means tell how to scroll WINDOW.
+SCROLL equal `other' means tell how to scroll the \"other\"
+window."
(let ((scroll-part
(cond
+ ;; If we don't have QUIT-PART we probably reuse a window
+ ;; showing the same buffer so we don't show any message.
+ ((not quit-part) nil)
((pos-visible-in-window-p
(with-current-buffer (window-buffer window)
- (point-max)) window)
- ;; Buffer end is visible.
+ (point-max)) window t)
+ ;; Buffer end is at least partially visible, no need to talk
+ ;; about scrolling.
".")
- (other ", \\[scroll-other-window] to scroll help.")
- (t ", \\[scroll-up] to scroll help."))))
+ ((eq scroll 'other)
+ ", \\[scroll-other-window] to scroll help.")
+ (scroll ", \\[scroll-up] to scroll help."))))
(message "%s"
(substitute-command-keys (concat quit-part scroll-part)))))
-(defun help-window-setup-finish (window &optional reuse keep-frame)
- "Finish setting up help window WINDOW.
-Select WINDOW according to the value of `help-window-select'.
-Display message telling how to scroll and eventually quit WINDOW.
+(defun help-window-setup (help-window)
+ "Set up help window for `with-help-window'.
+HELP-WINDOW is the window used for displaying the help buffer."
+ (let* ((help-buffer (when (window-live-p help-window)
+ (window-buffer help-window)))
+ (help-setup (when (window-live-p help-window)
+ (car (window-parameter help-window 'quit-restore)))))
+ (when help-buffer
+ ;; Handle `help-window-point-marker'.
+ (when (eq (marker-buffer help-window-point-marker) help-buffer)
+ (set-window-point help-window help-window-point-marker)
+ ;; Reset `help-window-point-marker'.
+ (set-marker help-window-point-marker nil))
-Optional argument REUSE non-nil means WINDOW has been reused by
-`display-buffer'. Optional argument KEEP-FRAME non-nil means
-that quitting should not delete WINDOW's frame."
- (let ((number-of-windows
- (length (window-list (window-frame window) 'no-mini window))))
- (cond
- ((eq window (selected-window))
- ;; The help window is the selected window, probably the
- ;; `pop-up-windows' nil case.
- (help-window-display-message
- (if reuse
- "Type \"q\" to restore this window"
- ;; This should not be taken.
- "Type \"q\" to quit") window))
- ((= number-of-windows 1)
- ;; The help window is alone on a frame and not the selected
- ;; window, could be the `pop-up-frames' t case.
- (help-window-display-message
- (cond
- (keep-frame "Type \"q\" to delete this window")
- (reuse "Type \"q\" to restore this window")
- (view-remove-frame-by-deleting "Type \"q\" to delete this frame")
- (t "Type \"q\" to iconify this frame"))
- window))
- ((and (= number-of-windows 2)
- (eq (window-frame window) (window-frame (selected-window))))
- ;; There are two windows on the help window's frame and the other
- ;; window is the selected one.
- (if (memq help-window-select '(nil other))
- ;; Do not select the help window.
- (help-window-display-message
- (if reuse
- ;; Offer `display-buffer' for consistency with
- ;; `help-print-return-message'. This is hardly TRT when
- ;; the other window and the selected window display the
- ;; same buffer but has been handled this way ever since.
- "Type \\[display-buffer] RET to restore the other window"
- ;; The classic "two windows" configuration.
- "Type \\[delete-other-windows] to delete the help window")
- window t)
- ;; Select help window and tell how to quit.
- (select-window window)
- (help-window-display-message
- (if reuse
- "Type \"q\" to restore this window"
- "Type \"q\" to delete this window") window)))
- (help-window-select
- ;; Issuing a message with 3 or more windows on the same frame
- ;; without selecting the help window doesn't make any sense.
- (select-window window)
- (help-window-display-message
- (if reuse
- "Type \"q\" to restore this window"
- "Type \"q\" to delete this window") window)))))
-
-(defun help-window-setup (list-of-frames list-of-window-tuples)
- "Set up help window.
-LIST-OF-FRAMES and LIST-OF-WINDOW-TUPLES are the lists of frames
-and window quadruples built by `with-help-window'. The help
-window itself is specified by the variable `help-window'."
- (let* ((help-buffer (window-buffer help-window))
- ;; `help-buffer' now denotes the help window's buffer.
- (view-entry
- (assq help-window
- (buffer-local-value 'view-return-to-alist help-buffer)))
- (help-entry (assq help-window list-of-window-tuples)))
-
- ;; Handle `help-window-point-marker'.
- (when (eq (marker-buffer help-window-point-marker) help-buffer)
- (set-window-point help-window help-window-point-marker)
- ;; Reset `help-window-point-marker'.
- (set-marker help-window-point-marker nil))
-
- (cond
- (view-entry
- ;; `view-return-to-alist' has an entry for the help window.
(cond
- ((eq help-window (selected-window))
- ;; The help window is the selected window, probably because the
- ;; user followed a backward/forward button or a cross reference.
- ;; In this case just purge stale entries from
- ;; `view-return-to-alist' but leave the entry alone and don't
- ;; display a message.
- (view-return-to-alist-update help-buffer))
- ((and help-entry (eq (cadr help-entry) help-buffer))
- ;; The help window was not selected but displayed the help
- ;; buffer. In this case reuse existing exit information but try
- ;; to get back to the selected window when quitting. Don't
- ;; display a message since the user must have seen one before.
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) (cddr view-entry)))))
- (help-entry
- ;; The help window was not selected, did display the help buffer
- ;; earlier, but displayed another buffer when help was invoked.
- ;; Set up things so that quitting will show that buffer again.
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) (cdr help-entry))))
- (help-window-setup-finish help-window t))
+ ((or (eq help-window (selected-window))
+ (and (or (eq help-window-select t)
+ (eq help-setup 'frame)
+ (and (eq help-window-select 'other)
+ (eq (window-frame help-window) (selected-frame))
+ (> (length (window-list nil 'no-mini)) 2)))
+ (select-window help-window)))
+ ;; The help window is or gets selected ...
+ (help-window-display-message
+ (cond
+ ((eq help-setup 'window)
+ ;; ... and is new, ...
+ "Type \"q\" to delete help window")
+ ((eq help-setup 'frame)
+ "Type \"q\" to delete help frame")
+ ((eq help-setup 'other)
+ ;; ... or displayed some other buffer before.
+ "Type \"q\" to restore previous buffer"))
+ help-window t))
+ ((and (eq (window-frame help-window) (selected-frame))
+ (= (length (window-list nil 'no-mini)) 2))
+ ;; There are two windows on the help window's frame and the
+ ;; other one is the selected one.
+ (help-window-display-message
+ (cond
+ ((eq help-setup 'window)
+ "Type \\[delete-other-windows] to delete the help window")
+ ((eq help-setup 'other)
+ "Type \"q\" in help window to restore its previous buffer"))
+ help-window 'other))
(t
- ;; The help window is new but `view-return-to-alist' had an
- ;; entry for it. This should never happen.
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) 'quit-window)))
- (help-window-setup-finish help-window t))))
- (help-entry
- ;; `view-return-to-alist' does not have an entry for help window
- ;; but `list-of-window-tuples' does. Hence `display-buffer' must
- ;; have reused an existing window.
- (if (eq (cadr help-entry) help-buffer)
- ;; The help window displayed `help-buffer' before but no
- ;; `view-return-to-alist' entry was found probably because the
- ;; user manually switched to the help buffer. Set up things
- ;; for `quit-window' although `view-exit-action' should be
- ;; able to handle this case all by itself.
- (progn
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) 'quit-window)))
- (help-window-setup-finish help-window t))
- ;; The help window displayed another buffer before. Set up
- ;; things in a way that quitting can orderly show that buffer
- ;; again. The window-start and window-point information from
- ;; `list-of-window-tuples' provide the necessary information.
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) (cdr help-entry))))
- (help-window-setup-finish help-window t)))
- ((memq (window-frame help-window) list-of-frames)
- ;; The help window is a new window on an existing frame. This
- ;; case must be handled specially by `help-window-setup-finish'
- ;; and `view-mode-exit' to ascertain that quitting does _not_
- ;; inadvertently delete the frame.
- (view-return-to-alist-update
- help-buffer (cons help-window
- (cons (selected-window) 'keep-frame)))
- (help-window-setup-finish help-window nil t))
- (t
- ;; The help window is shown on a new frame. In this case quitting
- ;; shall handle both, the help window _and_ its frame. We changed
- ;; the default of `view-remove-frame-by-deleting' to t in order to
- ;; intuitively DTRT here.
- (view-return-to-alist-update
- help-buffer (cons help-window (cons (selected-window) t)))
- (help-window-setup-finish help-window)))))
+ ;; The help window is not selected ...
+ (help-window-display-message
+ (cond
+ ((eq help-setup 'window)
+ ;; ... and is new, ...
+ "Type \"q\" in help window to delete it")
+ ((eq help-setup 'other)
+ ;; ... or displayed some other buffer before.
+ "Type \"q\" in help window to restore previous buffer"))
+ help-window))))))
;; `with-help-window' is a wrapper for `with-output-to-temp-buffer'
;; providing the following additional twists:
;; (1) Issue more accurate messages telling how to scroll and quit the
;; help window.
-;; (2) Make `view-mode-exit' DTRT in more cases.
-
-;; (3) An option (customizable via `help-window-select') to select the
+;; (2) An option (customizable via `help-window-select') to select the
;; help window automatically.
-;; (4) A marker (`help-window-point-marker') to move point in the help
+;; (3) A marker (`help-window-point-marker') to move point in the help
;; window to an arbitrary buffer position.
;; Note: It's usually always wrong to use `help-print-return-message' in
;; the body of `with-help-window'.
(defmacro with-help-window (buffer-name &rest body)
- "Display buffer BUFFER-NAME in a help window evaluating BODY.
+ "Display buffer with name BUFFER-NAME in a help window evaluating BODY.
Select help window if the actual value of the user option
`help-window-select' says so. Return last value in BODY."
(declare (indent 1) (debug t))
- ;; Bind list-of-frames to `frame-list' and list-of-window-tuples to a
- ;; list of one <window window-buffer window-start window-point> tuple
- ;; for each live window.
- `(let ((list-of-frames (frame-list))
- (list-of-window-tuples
- (let (list)
- (walk-windows
- (lambda (window)
- (push (list window (window-buffer window)
- (window-start window) (window-point window))
- list))
- 'no-mini t)
- list)))
- ;; Make `help-window' t to trigger `help-mode-finish' to set
- ;; `help-window' to the actual help window.
- (setq help-window t)
- ;; Make `help-window-point-marker' point nowhere (the only place
- ;; where this should be set to a buffer position is within BODY).
+ `(progn
+ ;; Make `help-window-point-marker' point nowhere. The only place
+ ;; where this should be set to a buffer position is within BODY.
(set-marker help-window-point-marker nil)
- (prog1
- ;; Return value returned by `with-output-to-temp-buffer'.
- (with-output-to-temp-buffer ,buffer-name
- (progn ,@body))
- (when (windowp help-window)
- ;; Set up help window.
- (help-window-setup list-of-frames list-of-window-tuples))
- ;; Reset `help-window' to nil to avoid confusing future calls of
- ;; `help-mode-finish' with plain `with-output-to-temp-buffer'.
- (setq help-window nil))))
+ (let* (help-window
+ (temp-buffer-show-hook
+ (cons (lambda () (setq help-window (selected-window)))
+ temp-buffer-show-hook)))
+ ;; Return value returned by `with-output-to-temp-buffer'.
+ (prog1
+ (with-output-to-temp-buffer ,buffer-name
+ (progn ,@body))
+ (help-window-setup help-window)))))
;; Called from C, on encountering `help-char' when reading a char.
;; Don't print to *Help*; that would clobber Help history.