(tibetan-pre-write-conversion): Cancel previous
[bpt/emacs.git] / lisp / rsz-mini.el
index deef3b3..7241070 100644 (file)
@@ -1,12 +1,13 @@
 ;;; rsz-mini.el --- dynamically resize minibuffer to display entire contents
 
-;;; Copyright (C) 1990, 1993, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1990, 1993-1995, 1997 Free Software Foundation, Inc.
 
-;;; Author: Noah Friedman <friedman@prep.ai.mit.edu>
-;;;         Roland McGrath <roland@prep.ai.mit.edu>
-;;; Maintainer: friedman@prep.ai.mit.edu
-;;; Keywords: minibuffer, window, frame, display
-;;; Status: Known to work in FSF GNU Emacs 19.23.
+;; Author: Noah Friedman <friedman@splode.com>
+;;         Roland McGrath <roland@gnu.org>
+;; Maintainer: Noah Friedman <friedman@splode.com>
+;; Keywords: minibuffer, window, frame, display
+
+;; $Id: rsz-mini.el,v 1.22 1998/09/11 01:36:54 friedman Exp $
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
-;;; This package allows the entire contents (or as much as possible) of the
-;;; minibuffer to be visible at once when typing.  As the end of a line is
-;;; reached, the minibuffer will resize itself.  When the user is done
-;;; typing, the minibuffer will return to its original size.
+;; This package allows the entire contents (or as much as possible) of the
+;; minibuffer to be visible at once when typing.  As the end of a line is
+;; reached, the minibuffer will resize itself.  When the user is done
+;; typing, the minibuffer will return to its original size.
 
-;;; In window systems where it is possible to have a frame in which the
-;;; minibuffer is the only window, the frame itself can be resized.  In FSF
-;;; GNU Emacs 19.22 and earlier, the frame may not be properly returned to
-;;; its original size after it ceases to be active because
-;;; `minibuffer-exit-hook' didn't exist until version 19.23.
+;; In window systems where it is possible to have a frame in which the
+;; minibuffer is the only window, the frame itself can be resized.  In
+;; Emacs 19.22 and earlier, the frame may not be properly returned to
+;; its original size after it ceases to be active because
+;; `minibuffer-exit-hook' didn't exist until version 19.23.
+;;
+;; Prior to Emacs 19.26, minibuffer-exit-hook wasn't called after exiting
+;; from the minibuffer by hitting the quit char.  That meant that the
+;; frame size restoration function wasn't being called in that case.  In
+;; 19.26 or later, minibuffer-exit-hook should be called anyway.
 
-;;; Note that the minibuffer and echo area are not the same!  They simply
-;;; happen to occupy roughly the same place on the frame.  Messages put in
-;;; the echo area will not cause any resizing by this package.
+;; Note that the minibuffer and echo area are not the same!  They simply
+;; happen to occupy roughly the same place on the frame.  Messages put in
+;; the echo area will not cause any resizing by this package.
 
-;;; This package is considered a minor mode but it doesn't put anything in
-;;; minor-mode-alist because this mode is specific to the minibuffer, which
-;;; has no mode line.
+;; This package is considered a minor mode but it doesn't put anything in
+;; minor-mode-alist because this mode is specific to the minibuffer, which
+;; has no mode line.
 
-;;; To use this package, put the following in your .emacs:
-;;;
-;;;     (autoload 'resize-minibuffer-mode "rsz-mini" nil t)
-;;;
-;;; Invoking the command `resize-minibuffer-mode' will then enable this mode.
+;; To enable or disable this mode, use M-x resize-minibuffer-mode.
 
 ;;; Code:
 
 \f
+(defgroup resize-minibuffer nil
+  "Dynamically resize minibuffer to display entire contents"
+  :group 'frames)
+
 ;;;###autoload
-(defvar resize-minibuffer-mode nil
-  "*If non-`nil', resize the minibuffer so its entire contents are visible.")
+(defcustom resize-minibuffer-mode nil
+  "*If non-`nil', resize the minibuffer so its entire contents are visible.
+You must modify via \\[customize] for this variable to have an effect."
+  :set (lambda (symbol value)
+        (resize-minibuffer-mode (if value 1 -1)))
+  :initialize 'custom-initialize-default
+  :type 'boolean
+  :group 'resize-minibuffer
+  :require 'rsz-mini)
 
 ;;;###autoload
-(defvar resize-minibuffer-window-max-height nil
+(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.")
+which the active minibuffer window resides."
+  :type '(choice (const nil) integer)
+  :group 'resize-minibuffer)
 
 ;;;###autoload
-(defvar resize-minibuffer-window-exactly t
-  "*If non-`nil', make minibuffer exactly the size needed to display all its contents.
-Otherwise, the minibuffer window can temporarily increase in size but
-never get smaller while it is active.")
+(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)
 
-\f
 ;;;###autoload
-(defvar resize-minibuffer-frame nil
-  "*If non-`nil' and the active minibuffer is the sole window in its frame, allow changing the frame height.")
+(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)
 
 ;;;###autoload
-(defvar resize-minibuffer-frame-max-height nil
+(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.")
 
 ;;;###autoload
-(defvar resize-minibuffer-frame-exactly nil
-  "*If non-`nil', make minibuffer frame exactly the size needed to display all its contents.
-Otherwise, the minibuffer frame can temporarily increase in size but
-never get smaller while it is active.")
+(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)
+
+;; Variable used to store the height of the minibuffer frame
+;; on entry, so it can be restored on exit.  It is made local before it is
+;; modified.  Do not use it yourself.
+(defvar resize-minibuffer-frame-original-height nil)
 
 \f
 ;;;###autoload
 (defun resize-minibuffer-mode (&optional prefix)
-  "Enable or disable resize-minibuffer mode.
-A negative prefix argument disables this mode.  A positive argument or
-argument of 0 enables it.
+  "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.
@@ -113,13 +143,12 @@ 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")
-  (or prefix (setq prefix 0))
-  (cond
-   ((>= prefix 0)
-    (setq resize-minibuffer-mode t))
-   (t
-    (setq resize-minibuffer-mode nil))))
+  (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
@@ -127,15 +156,35 @@ counterparts."
     (cond
      ((and window-system
            (eq 'only (cdr (assq 'minibuffer (frame-parameters)))))
+      ;; Checking for resize-minibuffer-frame is done outside the cond
+      ;; predicate because that should always be t if this is a minibuffer
+      ;; frame; it just shouldn't do anything if this flag is nil.
       (and resize-minibuffer-frame
            (progn
-             (make-local-variable 'minibuffer-exit-hook)
-             (add-hook 'minibuffer-exit-hook 'resize-minibuffer-frame-restore)
-             (make-local-variable 'post-command-hook)
-             (add-hook 'post-command-hook 'resize-minibuffer-frame))))
+             ;; Can't trust the height stored in minibuffer-frame-alist
+             ;; since the frame can be resized by the window manager and
+             ;; that variable isn't updated.
+             (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)
-      (add-hook 'post-command-hook 'resize-minibuffer-window))))))
+      ;; Copy this because add-hook modifies the list structure.
+      (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.
@@ -157,17 +206,38 @@ respectively."
 
 \f
 ;; Resize the minibuffer window to contain the minibuffer's contents.
-;; The minibuffer must be the current window.
 (defun resize-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)))))
+  (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))))))
+
+;; This resizes the minibuffer back to one line as soon as it is exited
+;; (e.g. when the user hits RET).  This way, subsequent messages put in the
+;; echo area aren't cluttered with leftover minibuffer text.
+;; It should be called by minibuffer-exit-hook.
+;;
+;; Note that because it calls sit-for to force a screen update, strange
+;; things may happen in the minibuffer, such as unexpanded partial
+;; completions by complete.el showing their completion.
+;; If this bothers you, just redefine this function to do nothing, in, say,
+;; your after-load-alist.  Perhaps there should be an option variable,
+;; but I don't know if there's really any demand for it.
+;; (Clobbering this definition is harmless because eventually emacs restores
+;; its idea of the minibuffer window size when the minibuffer isn't in use
+;; anyway; this is just a kludge because of the timing for that update).
+(defun resize-minibuffer-window-restore ()
+  (cond
+   ((not (eq (minibuffer-window) (selected-window))))
+   ((> (window-height) 1)
+    (enlarge-window (- 1 (window-height)))
+    (sit-for 0))))
 
 \f
 ;; Resize the minibuffer frame to contain the minibuffer's contents.
@@ -180,21 +250,24 @@ respectively."
          (setq lines (min lines resize-minibuffer-frame-max-height)))
     (cond
      ((> lines height)
-      (set-frame-size (selected-frame) (frame-width) lines))
+      (set-frame-size (window-frame (minibuffer-window)) (frame-width) lines))
      ((and resize-minibuffer-frame-exactly
-           (> height (cdr (assq 'height minibuffer-frame-alist)))
+           (> height resize-minibuffer-frame-original-height)
            (< lines height))
-      (set-frame-size (selected-frame) (frame-width) lines)))))
+      (set-frame-size (window-frame (minibuffer-window))
+                     (frame-width) lines)))))
 
 ;; Restore the original height of the frame.
+;; resize-minibuffer-frame-original-height is set in
+;; resize-minibuffer-setup.
 (defun resize-minibuffer-frame-restore ()
-  (set-frame-size (selected-frame)
+  (set-frame-size (window-frame (minibuffer-window))
                   (frame-width)
-                  (cdr (assq 'height minibuffer-frame-alist))))
+                  resize-minibuffer-frame-original-height))
 
-\f
-(provide 'rsz-mini)
+(if resize-minibuffer-mode
+    (resize-minibuffer-mode 1))
 
-(add-hook 'minibuffer-setup-hook 'resize-minibuffer-setup)
+(provide 'rsz-mini)
 
 ;; rsz-mini.el ends here