X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/b14e3e21ec6702d27257a1400681fc36ee10282f..22bcf2046977620a7f37bbd4dff4be4a4fffc0ed:/lisp/help.el diff --git a/lisp/help.el b/lisp/help.el index e148e5ef6a..36d49aae9b 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -37,17 +37,6 @@ (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 @@ -55,7 +44,7 @@ ;; 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))) @@ -132,7 +121,7 @@ "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.") @@ -144,8 +133,6 @@ It computes a message, and applies the optional argument FUNCTION to it. 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 @@ -415,7 +402,7 @@ With argument, display info only for the selected version." (beginning-of-line) (point))))))) -(defun view-emacs-todo (&optional arg) +(defun view-emacs-todo (&optional _arg) "Display the Emacs TODO list." (interactive "P") (view-help-file "TODO")) @@ -529,7 +516,7 @@ If INSERT (the prefix arg) is non-nil, insert the message in the buffer." (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) @@ -627,7 +614,7 @@ temporarily enables it to allow getting help on disabled items and buttons." (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)) @@ -914,6 +901,7 @@ appeared on the mode-line." ;; 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 @@ -937,6 +925,7 @@ appeared on the mode-line." (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 @@ -972,28 +961,34 @@ is currently activated with completion." minor-modes nil) (setq minor-modes (cdr minor-modes))))) result)) - ;;; Automatic resizing of temporary buffers. - (defcustom temp-buffer-max-height (lambda (buffer) (/ (- (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") (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-shrinking temp 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 reduced in height to +fit the buffer's contents, but never more than +`temp-buffer-max-height' nor less than `window-min-height'. + +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 @@ -1003,29 +998,26 @@ This applies to `help', `apropos' and `completion' buffers, and some others." (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))) +Will not make it higher than `temp-buffer-max-height' nor smaller +than `window-min-height'. Do nothing if the selected window is +not vertically combined or some of its contents are scrolled out +of view." + (when (and (pos-visible-in-window-p (point-min)) + (window-combined-p)) (fit-window-to-buffer - (selected-window) + nil (if (functionp temp-buffer-max-height) - (funcall temp-buffer-max-height (current-buffer)) + (funcall temp-buffer-max-height (window-buffer)) temp-buffer-max-height)))) - -;;; help-window - +;;; 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 @@ -1036,175 +1028,85 @@ by `with-help-window'" :group 'help :version "23.1") -(defun help-window-display-message (quit-part window &optional other) +(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. - -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)) +(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)) - (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: @@ -1212,50 +1114,41 @@ window itself is specified by the variable `help-window'." ;; (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 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. +(defun help-form-show () + "Display the output of a non-nil `help-form'." + (let ((msg (eval help-form))) + (if (stringp msg) + (with-output-to-temp-buffer " *Char Help*" + (princ msg))))) (provide 'help)