(defgroup resize-minibuffer nil
"Dynamically resize minibuffer to display entire contents"
:group 'frames)
(defcustom resize-minibuffer-mode nil
"Toggle resizing the minibuffer so its entire contents are visible.
Setting this variable directly does not take effect;
use either \\[customize] or the function `resize-minibuffer-mode'."
:set (lambda (symbol value)
(resize-minibuffer-mode (if value 1 -1)))
:initialize 'custom-initialize-default
:type 'boolean
:group 'resize-minibuffer
:require 'rsz-mini)
(defcustom resize-minibuffer-window-max-height nil
"*Maximum size the minibuffer window is allowed to become.
If less than 1 or not a number, the limit is the height of the frame in
which the active minibuffer window resides."
:type '(choice (const nil) integer)
:group 'resize-minibuffer)
(defcustom resize-minibuffer-window-exactly t
"*Allow making minibuffer exactly the size to display all its contents.
If `nil', the minibuffer window can temporarily increase in size but
never get smaller while it is active. Any other value allows exact
resizing."
:type 'boolean
:group 'resize-minibuffer)
(defcustom resize-minibuffer-frame nil
"*Allow changing the frame height of minibuffer frames.
If non-`nil' and the active minibuffer is the sole window in its frame,
allow changing the frame height."
:type 'boolean
:group 'resize-minibuffer)
(defcustom resize-minibuffer-frame-max-height nil
"*Maximum size the minibuffer frame is allowed to become.
If less than 1 or not a number, there is no limit.")
(defcustom resize-minibuffer-frame-exactly t
"*Allow making minibuffer frame exactly the size to display all its contents.
If `nil', the minibuffer frame can temporarily increase in size but
never get smaller while it is active. Any other value allows exact
resizing."
:type 'boolean
:group 'resize-minibuffer)
(defvar resize-minibuffer-frame-original-height nil)
(defun resize-minibuffer-mode (&optional prefix)
"Toggle resize-minibuffer mode.
With argument, enable resize-minibuffer mode if and only if argument
is positive.
When this minor mode is enabled, the minibuffer is dynamically resized to
contain the entire region of text put in it as you type.
The variable `resize-minibuffer-mode' is set to t or nil depending on
whether this mode is active or not.
The maximum height to which the minibuffer can grow is controlled by the
variable `resize-minibuffer-window-max-height'.
The variable `resize-minibuffer-window-exactly' determines whether the
minibuffer window should ever be shrunk to make it no larger than needed to
display its contents.
When using a window system, it is possible for a minibuffer to be the sole
window in a frame. Since that window is already its maximum size, the only
way to make more text visible at once is to increase the size of the frame.
The variable `resize-minibuffer-frame' controls whether this should be
done. The variables `resize-minibuffer-frame-max-height' and
`resize-minibuffer-frame-exactly' are analogous to their window
counterparts."
(interactive "P")
(setq resize-minibuffer-mode
(if prefix
(> (prefix-numeric-value prefix) 0)
(not resize-minibuffer-mode)))
(add-hook 'minibuffer-setup-hook 'resize-minibuffer-setup))
(defun resize-minibuffer-setup ()
(cond
(resize-minibuffer-mode
(cond
((and window-system
(eq 'only (cdr (assq 'minibuffer (frame-parameters)))))
(and resize-minibuffer-frame
(progn
(make-local-variable 'resize-minibuffer-frame-original-height)
(setq resize-minibuffer-frame-original-height (frame-height))
(make-local-hook 'post-command-hook)
(add-hook 'post-command-hook 'resize-minibuffer-frame 'append t)
(make-local-hook 'minibuffer-exit-hook)
(add-hook 'minibuffer-exit-hook 'resize-minibuffer-frame-restore
nil t)
(resize-minibuffer-frame))))
(t
(make-local-variable 'post-command-hook)
(setq post-command-hook (copy-sequence post-command-hook))
(add-hook 'post-command-hook 'resize-minibuffer-window 'append)
(make-local-variable 'minibuffer-exit-hook)
(add-hook 'minibuffer-exit-hook 'resize-minibuffer-window-restore)
(resize-minibuffer-window))))))
(defun resize-minibuffer-count-window-lines (&optional start end)
"Return number of window lines occupied by text in region.
The number of window lines may be greater than the number of actual lines
in the buffer if any wrap on the display due to their length.
Optional arguments START and END default to point-min and point-max,
respectively."
(or start (setq start (point-min)))
(or end (setq end (point-max)))
(if (= start end)
0
(save-excursion
(save-restriction
(widen)
(narrow-to-region start end)
(goto-char start)
(vertical-motion (buffer-size))))))
(defun resize-minibuffer-window ()
(and (eq (selected-window) (minibuffer-window))
(let ((height (window-height))
(lines (1+ (resize-minibuffer-count-window-lines))))
(and (numberp resize-minibuffer-window-max-height)
(> resize-minibuffer-window-max-height 0)
(setq lines (min lines resize-minibuffer-window-max-height)))
(or (if resize-minibuffer-window-exactly
(= lines height)
(<= lines height))
(enlarge-window (- lines height))))))
(defun resize-minibuffer-window-restore ()
(cond
((not (eq (minibuffer-window) (selected-window))))
((> (window-height) 1)
(enlarge-window (- 1 (window-height)))
(sit-for 0))))
(defun resize-minibuffer-frame ()
(let ((height (frame-height))
(lines (1+ (resize-minibuffer-count-window-lines))))
(and (numberp resize-minibuffer-frame-max-height)
(> resize-minibuffer-frame-max-height 0)
(setq lines (min lines resize-minibuffer-frame-max-height)))
(cond
((> lines height)
(set-frame-size (window-frame (minibuffer-window)) (frame-width) lines))
((and resize-minibuffer-frame-exactly
(> height resize-minibuffer-frame-original-height)
(< lines height))
(set-frame-size (window-frame (minibuffer-window))
(frame-width) lines)))))
(defun resize-minibuffer-frame-restore ()
(set-frame-size (window-frame (minibuffer-window))
(frame-width)
resize-minibuffer-frame-original-height))
(if resize-minibuffer-mode
(resize-minibuffer-mode 1))
(provide 'rsz-mini)