Mercurial > emacs
changeset 100361:ecf3d51be3b3
(fit-window-to-buffer): Use with-selected-window and
condition-case. Do not delete more windows than necessary in
the shrinking (delta < 0) case. Do not raise an error when the
containing frame is too small to show all of buffer. (Bug#1488)
author | Martin Rudalics <rudalics@gmx.at> |
---|---|
date | Thu, 11 Dec 2008 17:17:44 +0000 |
parents | 9ddc22f5e149 |
children | 4150ab3a5845 |
files | lisp/window.el |
diffstat | 1 files changed, 88 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/window.el Thu Dec 11 14:58:04 2008 +0000 +++ b/lisp/window.el Thu Dec 11 17:17:44 2008 +0000 @@ -1294,86 +1294,100 @@ (defun fit-window-to-buffer (&optional window max-height min-height) "Adjust height of WINDOW to display its buffer's contents exactly. -WINDOW defaults to the selected window. +WINDOW defaults to the selected window. Return nil. Optional argument MAX-HEIGHT specifies the maximum height of the -window and defaults to the height of WINDOW's frame. +window and defaults to the maximum permissible height of a window +on WINDOW's frame. Optional argument MIN-HEIGHT specifies the minimum height of the window and defaults to `window-min-height'. Both, MAX-HEIGHT and MIN-HEIGHT are specified in lines and include the mode line and header line, if any. -Always return nil." + +Caution: This function can delete WINDOW and/or other windows +when their height shrinks to less than MIN-HEIGHT." (interactive) - - (when (null window) - (setq window (selected-window))) - (when (null max-height) - (setq max-height (frame-height (window-frame window)))) - - (let* ((buf - ;; Buffer that is displayed in WINDOW - (window-buffer window)) - (window-height - ;; The current height of WINDOW - (window-height window)) - (desired-height - ;; The height necessary to show the buffer displayed by WINDOW - ;; (`count-screen-lines' always works on the current buffer). - (with-current-buffer buf - (+ (count-screen-lines) - ;; If the buffer is empty, (count-screen-lines) is - ;; zero. But, even in that case, we need one text line - ;; for cursor. - (if (= (point-min) (point-max)) - 1 0) - ;; For non-minibuffers, count the mode-line, if any - (if (and (not (window-minibuffer-p window)) - mode-line-format) - 1 0) - ;; Count the header-line, if any - (if header-line-format 1 0)))) - (delta - ;; Calculate how much the window height has to change to show - ;; desired-height lines, constrained by MIN-HEIGHT and MAX-HEIGHT. - (- (max (min desired-height max-height) - (or min-height window-min-height)) - window-height))) - - ;; Don't try to redisplay with the cursor at the end - ;; on its own line--that would force a scroll and spoil things. - (when (with-current-buffer buf - (and (eobp) (bolp) (not (bobp)))) - (set-window-point window (1- (window-point window)))) - - (save-selected-window - (select-window window 'norecord) - - ;; Adjust WINDOW to the nominally correct size (which may actually - ;; be slightly off because of variable height text, etc). - (unless (zerop delta) - (enlarge-window delta)) - - ;; Check if the last line is surely fully visible. If not, - ;; enlarge the window. - (let ((end (with-current-buffer buf - (save-excursion - (goto-char (point-max)) - (when (and (bolp) (not (bobp))) - ;; Don't include final newline - (backward-char 1)) - (when truncate-lines - ;; If line-wrapping is turned off, test the - ;; beginning of the last line for visibility - ;; instead of the end, as the end of the line - ;; could be invisible by virtue of extending past - ;; the edge of the window. - (forward-line 0)) - (point))))) - (set-window-vscroll window 0) - (while (and (< desired-height max-height) - (= desired-height (window-height window)) - (not (pos-visible-in-window-p end window))) - (enlarge-window 1) - (setq desired-height (1+ desired-height))))))) + ;; Do all the work in WINDOW and its buffer and restore the selected + ;; window and the current buffer when we're done. + (let ((old-buffer (current-buffer))) + (with-selected-window (or window (setq window (selected-window))) + (set-buffer (window-buffer)) + ;; Use `condition-case' to handle any fixed-size windows and other + ;; pitfalls nearby. + (condition-case nil + (let* (;; MIN-HEIGHT must not be less than 1 and defaults to + ;; `window-min-height'. + (min-height (max (or min-height window-min-height) 1)) + (max-window-height + ;; Maximum height of any window on this frame. + (min (window-height (frame-root-window)) (frame-height))) + ;; MAX-HEIGHT must not be larger than max-window-height and + ;; defaults to max-window-height. + (max-height + (min (or max-height max-window-height) max-window-height)) + (desired-height + ;; The height necessary to show all of WINDOW's buffer, + ;; constrained by MIN-HEIGHT and MAX-HEIGHT. + (max + (min + ;; For an empty buffer `count-screen-lines' returns zero. + ;; Even in that case we need one line for the cursor. + (+ (max (count-screen-lines) 1) + ;; For non-minibuffers count the mode line, if any. + (if (and (not (window-minibuffer-p)) mode-line-format) + 1 0) + ;; Count the header line, if any. + (if header-line-format 1 0)) + max-height) + min-height)) + (delta + ;; How much the window height has to change. + (if (= (window-height) (window-height (frame-root-window))) + ;; Don't try to resize a full-height window. + 0 + (- desired-height (window-height)))) + ;; Do something reasonable so `enlarge-window' can make + ;; windows as small as MIN-HEIGHT. + (window-min-height (min min-height window-min-height))) + ;; Don't try to redisplay with the cursor at the end on its + ;; own line--that would force a scroll and spoil things. + (when (and (eobp) (bolp) (not (bobp))) + (set-window-point window (1- (window-point)))) + ;; Adjust WINDOW's height to the nominally correct one + ;; (which may actually be slightly off because of variable + ;; height text, etc). + (unless (zerop delta) + (enlarge-window delta)) + ;; `enlarge-window' might have deleted WINDOW, so make sure + ;; WINDOW's still alive for the remainder of this. + ;; Note: Deleting WINDOW is clearly counter-intuitive in + ;; this context, but we can't do much about it given the + ;; current semantics of `enlarge-window'. + (when (window-live-p window) + ;; Check if the last line is surely fully visible. If + ;; not, enlarge the window. + (let ((end (save-excursion + (goto-char (point-max)) + (when (and (bolp) (not (bobp))) + ;; Don't include final newline. + (backward-char 1)) + (when truncate-lines + ;; If line-wrapping is turned off, test the + ;; beginning of the last line for + ;; visibility instead of the end, as the + ;; end of the line could be invisible by + ;; virtue of extending past the edge of the + ;; window. + (forward-line 0)) + (point)))) + (set-window-vscroll window 0) + (while (and (< desired-height max-height) + (= desired-height (window-height)) + (not (pos-visible-in-window-p end))) + (enlarge-window 1) + (setq desired-height (1+ desired-height)))))) + (error nil))) + (when (buffer-live-p old-buffer) + (set-buffer old-buffer)))) (defun window-safely-shrinkable-p (&optional window) "Return t if WINDOW can be shrunk without shrinking other windows.