+(defun window-buffer-height (window)
+ "Return the height (in screen lines) of the buffer that WINDOW is displaying."
+ (with-current-buffer (window-buffer window)
+ (max 1
+ (count-screen-lines (point-min) (point-max)
+ ;; If buffer ends with a newline, ignore it when
+ ;; counting height unless point is after it.
+ (eobp)
+ window))))
+
+(defun count-screen-lines (&optional beg end count-final-newline window)
+ "Return the number of screen lines in the region.
+The number of screen lines may be different from the number of actual lines,
+due to line breaking, display table, etc.
+
+Optional arguments BEG and END default to `point-min' and `point-max'
+respectively.
+
+If region ends with a newline, ignore it unless optional third argument
+COUNT-FINAL-NEWLINE is non-nil.
+
+The optional fourth argument WINDOW specifies the window used for obtaining
+parameters such as width, horizontal scrolling, and so on. The default is
+to use the selected window's parameters.
+
+Like `vertical-motion', `count-screen-lines' always uses the current buffer,
+regardless of which buffer is displayed in WINDOW. This makes possible to use
+`count-screen-lines' in any buffer, whether or not it is currently displayed
+in some window."
+ (unless beg
+ (setq beg (point-min)))
+ (unless end
+ (setq end (point-max)))
+ (if (= beg end)
+ 0
+ (save-excursion
+ (save-restriction
+ (widen)
+ (narrow-to-region (min beg end)
+ (if (and (not count-final-newline)
+ (= ?\n (char-before (max beg end))))
+ (1- (max beg end))
+ (max beg end)))
+ (goto-char (point-min))
+ (1+ (vertical-motion (buffer-size) window))))))
+
+(defun fit-window-to-buffer (&optional window max-height min-height)
+ "Make WINDOW the right size to display its contents exactly.
+If WINDOW is omitted or nil, it defaults to the selected window.
+If the optional argument MAX-HEIGHT is supplied, it is the maximum height
+ the window is allowed to be, defaulting to the frame height.
+If the optional argument MIN-HEIGHT is supplied, it is the minimum
+ height the window is allowed to be, defaulting to `window-min-height'.
+
+The heights in MAX-HEIGHT and MIN-HEIGHT include the mode-line and/or
+header-line."
+ (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))
+ ;; We do our own height checking, so avoid any restrictions due to
+ ;; window-min-height.
+ (window-min-height 1))
+
+ ;; 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)
+
+ ;; 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)))))))
+