This commit was manufactured by cvs2svn to create branch 'chise-r21-4-18'.
[chise/xemacs-chise.git-] / lisp / minibuf.el
diff --git a/lisp/minibuf.el b/lisp/minibuf.el
new file mode 100644 (file)
index 0000000..7e4c7c9
--- /dev/null
@@ -0,0 +1,2320 @@
+;;; minibuf.el --- Minibuffer functions for XEmacs
+
+;; Copyright (C) 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1995 Tinker Systems.
+;; Copyright (C) 1995, 1996, 2000 Ben Wing.
+
+;; Author: Richard Mlynarik
+;; Created: 2-Oct-92
+;; Maintainer: XEmacs Development Team
+;; Keywords: internal, dumped
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Synched up with: all the minibuffer history stuff is synched with
+;;; 19.30.  Not sure about the rest.
+
+;;; Commentary:
+
+;; This file is dumped with XEmacs.
+
+;; Written by Richard Mlynarik 2-Oct-92
+
+;; 06/11/1997 -  Use char-(after|before) instead of
+;;  (following|preceding)-char. -slb
+
+;;; Code:
+
+(defgroup minibuffer nil
+  "Controling the behavior of the minibuffer."
+  :group 'environment)
+
+
+(defcustom insert-default-directory t
+ "*Non-nil means when reading a filename start with default dir in minibuffer."
+ :type 'boolean
+ :group 'minibuffer)
+
+(defcustom minibuffer-history-uniquify t
+  "*Non-nil means when adding an item to a minibuffer history, remove
+previous occurrences of the same item from the history list first,
+rather than just consing the new element onto the front of the list."
+  :type 'boolean
+  :group 'minibuffer)
+
+(defvar minibuffer-completion-table nil
+  "Alist or obarray used for completion in the minibuffer.
+This becomes the ALIST argument to `try-completion' and `all-completions'.
+
+The value may alternatively be a function, which is given three arguments:
+  STRING, the current buffer contents;
+  PREDICATE, the predicate for filtering possible matches;
+  CODE, which says what kind of things to do.
+CODE can be nil, t or `lambda'.
+nil means to return the best completion of STRING, nil if there is none,
+  or t if it is already a unique completion.
+t means to return a list of all possible completions of STRING.
+`lambda' means to return t if STRING is a valid completion as it stands.")
+
+(defvar minibuffer-completion-predicate nil
+  "Within call to `completing-read', this holds the PREDICATE argument.")
+
+(defvar minibuffer-completion-confirm nil
+  "Non-nil => demand confirmation of completion before exiting minibuffer.")
+
+(defcustom minibuffer-confirm-incomplete nil
+  "If true, then in contexts where completing-read allows answers which
+are not valid completions, an extra RET must be typed to confirm the
+response.  This is helpful for catching typos, etc."
+  :type 'boolean
+  :group 'minibuffer)
+
+(defcustom completion-auto-help t
+  "*Non-nil means automatically provide help for invalid completion input."
+  :type 'boolean
+  :group 'minibuffer)
+
+(defcustom enable-recursive-minibuffers nil
+  "*Non-nil means to allow minibuffer commands while in the minibuffer.
+More precisely, this variable makes a difference when the minibuffer window
+is the selected window.  If you are in some other window, minibuffer commands
+are allowed even if a minibuffer is active."
+  :type 'boolean
+  :group 'minibuffer)
+
+(defcustom minibuffer-max-depth 1
+  ;; See comment in #'minibuffer-max-depth-exceeded
+  "*Global maximum number of minibuffers allowed;
+compare to enable-recursive-minibuffers, which is only consulted when the
+minibuffer is reinvoked while it is the selected window."
+  :type '(choice integer
+                (const :tag "Indefinite" nil))
+  :group 'minibuffer)
+
+;; Moved to C.  The minibuffer prompt must be setup before this is run
+;; and that can only be done from the C side.
+;(defvar minibuffer-setup-hook nil
+;  "Normal hook run just after entry to minibuffer.")
+
+;; see comment at list-mode-hook.
+(put 'minibuffer-setup-hook 'permanent-local t)
+
+(defvar minibuffer-exit-hook nil
+  "Normal hook run just after exit from minibuffer.")
+(put 'minibuffer-exit-hook 'permanent-local t)
+
+(defvar minibuffer-help-form nil
+  "Value that `help-form' takes on inside the minibuffer.")
+
+(defvar minibuffer-default nil
+  "Default value for minibuffer input.")
+  
+(defvar minibuffer-local-map
+  (let ((map (make-sparse-keymap 'minibuffer-local-map)))
+    map)
+  "Default keymap to use when reading from the minibuffer.")
+
+(defvar minibuffer-local-completion-map
+  (let ((map (make-sparse-keymap 'minibuffer-local-completion-map)))
+    (set-keymap-parents map (list minibuffer-local-map))
+    map)
+  "Local keymap for minibuffer input with completion.")
+
+(defvar minibuffer-local-must-match-map
+  (let ((map (make-sparse-keymap 'minibuffer-must-match-map)))
+    (set-keymap-parents map (list minibuffer-local-completion-map))
+    map)
+  "Local keymap for minibuffer input with completion, for exact match.")
+
+;; (define-key minibuffer-local-map "\C-g" 'abort-recursive-edit)
+(define-key minibuffer-local-map "\C-g" 'minibuffer-keyboard-quit) ;; moved here from pending-del.el
+(define-key minibuffer-local-map "\r" 'exit-minibuffer)
+(define-key minibuffer-local-map "\n" 'exit-minibuffer)
+
+;; Historical crock.  Unused by anything but user code, if even that
+;(defvar minibuffer-local-ns-map
+;  (let ((map (make-sparse-keymap 'minibuffer-local-ns-map)))
+;    (set-keymap-parents map (list minibuffer-local-map))
+;    map)
+;  "Local keymap for the minibuffer when spaces are not allowed.")
+;(define-key minibuffer-local-ns-map [space] 'exit-minibuffer)
+;(define-key minibuffer-local-ns-map [tab] 'exit-minibuffer)
+;(define-key minibuffer-local-ns-map [?\?] 'self-insert-and-exit)
+
+(define-key minibuffer-local-completion-map "\t" 'minibuffer-complete)
+(define-key minibuffer-local-completion-map " " 'minibuffer-complete-word)
+(define-key minibuffer-local-completion-map "?" 'minibuffer-completion-help)
+(define-key minibuffer-local-must-match-map "\r" 'minibuffer-complete-and-exit)
+(define-key minibuffer-local-must-match-map "\n" 'minibuffer-complete-and-exit)
+
+(define-key minibuffer-local-map "\M-n" 'next-history-element)
+(define-key minibuffer-local-map "\M-p" 'previous-history-element)
+(define-key minibuffer-local-map '[next]  "\M-n")
+(define-key minibuffer-local-map '[prior] "\M-p")
+(define-key minibuffer-local-map "\M-r" 'previous-matching-history-element)
+(define-key minibuffer-local-map "\M-s" 'next-matching-history-element)
+(define-key minibuffer-local-must-match-map [next]
+  'next-complete-history-element)
+(define-key minibuffer-local-must-match-map [prior]
+  'previous-complete-history-element)
+
+;; This is an experiment--make up and down arrows do history.
+(define-key minibuffer-local-map [up] 'previous-history-element)
+(define-key minibuffer-local-map [down] 'next-history-element)
+(define-key minibuffer-local-completion-map [up] 'previous-history-element)
+(define-key minibuffer-local-completion-map [down] 'next-history-element)
+(define-key minibuffer-local-must-match-map [up] 'previous-history-element)
+(define-key minibuffer-local-must-match-map [down] 'next-history-element)
+
+(defvar read-expression-map (let ((map (make-sparse-keymap
+                                       'read-expression-map)))
+                              (set-keymap-parents map
+                                                 (list minibuffer-local-map))
+                              (define-key map "\M-\t" 'lisp-complete-symbol)
+                              map)
+  "Minibuffer keymap used for reading Lisp expressions.")
+
+(defvar read-shell-command-map
+  (let ((map (make-sparse-keymap 'read-shell-command-map)))
+    (set-keymap-parents map (list minibuffer-local-map))
+    (define-key map "\t" 'comint-dynamic-complete)
+    (define-key map "\M-\t" 'comint-dynamic-complete)
+    (define-key map "\M-?" 'comint-dynamic-list-completions)
+    map)
+  "Minibuffer keymap used by `shell-command' and related commands.")
+
+(defcustom use-dialog-box t
+  "*Variable controlling usage of the dialog box.
+If nil, the dialog box will never be used, even in response to mouse events."
+  :type 'boolean
+  :group 'minibuffer)
+\f
+(defcustom minibuffer-electric-file-name-behavior t
+  "*If non-nil, slash and tilde in certain places cause immediate deletion.
+These are the same places where this behavior would occur later on anyway,
+in `substitute-in-file-name'."
+  :type 'boolean
+  :group 'minibuffer)
+
+;; originally by Stig@hackvan.com
+(defun minibuffer-electric-separator ()
+  (interactive)
+  (let ((c last-command-char))
+    (and minibuffer-electric-file-name-behavior
+        (eq c directory-sep-char)
+        (eq c (char-before (point)))
+        (not (save-excursion
+             (goto-char (point-min))
+             (and (looking-at "/.+:~?[^/]*/.+")
+                  (re-search-forward "^/.+:~?[^/]*" nil t)
+                  (progn
+                    (delete-region (point) (point-max))
+                    t))))
+        (not (save-excursion
+               (goto-char (point-min))
+               (and (looking-at ".+://[^/]*/.+")
+                    (re-search-forward "^.+:/" nil t)
+                    (progn
+                      (delete-region (point) (point-max))
+                      t))))
+        ;; permit `//hostname/path/to/file'
+        (not (eq (point) (1+ (point-min))))
+        ;; permit `http://url/goes/here'
+        (or (not (eq ?: (char-after (- (point) 2))))
+            (eq ?/ (char-after (point-min))))
+       (delete-region (point-min) (point)))
+    (insert c)))
+
+(defun minibuffer-electric-tilde ()
+  (interactive)
+  (and minibuffer-electric-file-name-behavior
+       (eq directory-sep-char (char-before (point)))
+       ;; permit URL's with //, for e.g. http://hostname/~user
+       (not (save-excursion (search-backward "//" nil t)))
+       (delete-region (point-min) (point)))
+  (insert ?~))
+
+
+(defvar read-file-name-map
+  (let ((map (make-sparse-keymap 'read-file-name-map)))
+    (set-keymap-parents map (list minibuffer-local-completion-map))
+    (define-key map (vector directory-sep-char) 'minibuffer-electric-separator)
+    (define-key map "~" 'minibuffer-electric-tilde)
+    map
+    ))
+
+(defvar read-file-name-must-match-map
+  (let ((map (make-sparse-keymap 'read-file-name-map)))
+    (set-keymap-parents map (list minibuffer-local-must-match-map))
+    (define-key map (vector directory-sep-char) 'minibuffer-electric-separator)
+    (define-key map "~" 'minibuffer-electric-tilde)
+    map
+    ))
+\f
+(defun minibuffer-keyboard-quit ()
+  "Abort recursive edit.
+If `zmacs-regions' is true, and the zmacs region is active in this buffer,
+then this key deactivates the region without beeping."
+  (interactive)
+  (if (region-active-p)
+      ;; pseudo-zmacs compatibility: don't beep if this ^G is simply
+      ;; deactivating the region.  If it is inactive, beep.
+      nil
+    (abort-recursive-edit)))
+\f
+;;;; Guts of minibuffer invocation
+
+;;#### The only things remaining in C are
+;; "Vminibuf_prompt" and the display junk
+;;  "minibuf_prompt_width" and "minibuf_prompt_pix_width"
+;; Also "active_frame", though I suspect I could already
+;;   hack that in Lisp if I could make any sense of the
+;;   complete mess of frame/frame code in XEmacs.
+;; Vminibuf_prompt could easily be made Lisp-bindable.
+;;  I suspect that minibuf_prompt*_width are actually recomputed
+;;  by redisplay as needed -- or could be arranged to be so --
+;;  and that there could be need for read-minibuffer-internal to
+;;  save and restore them.
+;;#### The only other thing which read-from-minibuffer-internal does
+;;  which we can't presently do in Lisp is move the frame cursor
+;;  to the start of the minibuffer line as it returns.  This is
+;;  a rather nice touch and should be preserved -- probably by
+;;  providing some Lisp-level mechanism (extension to cursor-in-echo-area ?)
+;;  to effect it.
+
+
+;; Like reset_buffer in FSF's buffer.c
+;;  (Except that kill-all-local-variables doesn't nuke 'permanent-local
+;;   variables -- we preserve them, reset_buffer doesn't.)
+(defun reset-buffer (buffer)
+  (with-current-buffer buffer
+    ;(if (fboundp 'unlock-buffer) (unlock-buffer))
+    (kill-all-local-variables)
+    (setq buffer-read-only nil)
+    ;; don't let read only text yanked into the minibuffer
+    ;; permanently wedge it.
+    (make-local-variable 'inhibit-read-only)
+    (setq inhibit-read-only t)
+    (erase-buffer)
+    ;(setq default-directory nil)
+    (setq buffer-file-name nil)
+    (setq buffer-file-truename nil)
+    (set-buffer-modified-p nil)
+    (setq buffer-backed-up nil)
+    (setq buffer-auto-save-file-name nil)
+    (set-buffer-dedicated-frame buffer nil)
+    buffer))
+
+(defvar minibuffer-history-variable 'minibuffer-history
+  "History list symbol to add minibuffer values to.
+Each minibuffer output is added with
+  (set minibuffer-history-variable
+       (cons STRING (symbol-value minibuffer-history-variable)))")
+(defvar minibuffer-history-position)
+
+;; Added by hniksic:
+(defvar initial-minibuffer-history-position)
+(defvar current-minibuffer-contents)
+(defvar current-minibuffer-point)
+
+(defcustom minibuffer-history-minimum-string-length nil
+  "*If this variable is non-nil, a string will not be added to the
+minibuffer history if its length is less than that value."
+  :type '(choice (const :tag "Any" nil)
+                integer)
+  :group 'minibuffer)
+
+(define-error 'input-error "Keyboard input error")
+
+(put 'input-error 'display-error
+     #'(lambda (error-object stream)
+        (princ (cadr error-object) stream)))
+
+(defun read-from-minibuffer (prompt &optional initial-contents
+                                    keymap
+                                    readp
+                                    history
+                                   abbrev-table
+                                   default)
+  "Read a string from the minibuffer, prompting with string PROMPT.
+If optional second arg INITIAL-CONTENTS is non-nil, it is a string
+  to be inserted into the minibuffer before reading input.
+  If INITIAL-CONTENTS is (STRING . POSITION), the initial input
+  is STRING, but point is placed POSITION characters into the string.
+Third arg KEYMAP is a keymap to use while reading;
+  if omitted or nil, the default is `minibuffer-local-map'.
+If fourth arg READ is non-nil, then interpret the result as a lisp object
+  and return that object:
+  in other words, do `(car (read-from-string INPUT-STRING))'
+Fifth arg HISTORY, if non-nil, specifies a history list
+  and optionally the initial position in the list.
+  It can be a symbol, which is the history list variable to use,
+  or it can be a cons cell (HISTVAR . HISTPOS).
+  In that case, HISTVAR is the history list variable to use,
+  and HISTPOS is the initial position (the position in the list
+  which INITIAL-CONTENTS corresponds to).
+  If HISTORY is `t', no history will be recorded.
+  Positions are counted starting from 1 at the beginning of the list.
+Sixth arg ABBREV-TABLE, if non-nil, becomes the value of `local-abbrev-table'
+  in the minibuffer.
+Seventh arg DEFAULT, if non-nil, will be returned when user enters
+  an empty string.
+
+See also the variable `completion-highlight-first-word-only' for
+  control over completion display."
+  (if (and (not enable-recursive-minibuffers)
+           (> (minibuffer-depth) 0)
+           (eq (selected-window) (minibuffer-window)))
+      (error "Command attempted to use minibuffer while in minibuffer"))
+
+  (if (and minibuffer-max-depth
+          (> minibuffer-max-depth 0)
+           (>= (minibuffer-depth) minibuffer-max-depth))
+      (minibuffer-max-depth-exceeded))
+
+  ;; catch this error before the poor user has typed something...
+  (if history
+      (if (symbolp history)
+         (or (boundp history)
+             (error "History list %S is unbound" history))
+       (or (boundp (car history))
+           (error "History list %S is unbound" (car history)))))
+
+  (if (noninteractive)
+      (progn
+        ;; XEmacs in -batch mode calls minibuffer: print the prompt.
+        (message "%s" (gettext prompt))
+        ;;#### force-output
+
+        ;;#### Should this even be falling though to the code below?
+        ;;#### How does this stuff work now, anyway?
+        ))
+  (let* ((dir default-directory)
+         (owindow (selected-window))
+        (oframe (selected-frame))
+         (window (minibuffer-window))
+         (buffer (if (eq (minibuffer-depth) 0)
+                     (window-buffer window)
+                  (get-buffer-create (format " *Minibuf-%d"
+                                             (minibuffer-depth)))))
+         (frame (window-frame window))
+         (mconfig (if (eq frame (selected-frame))
+                      nil (current-window-configuration frame)))
+         (oconfig (current-window-configuration))
+        ;; dynamic scope sucks sucks sucks sucks sucks sucks.
+        ;; `M-x doctor' makes history a local variable, and thus
+        ;; our binding above is buffer-local and doesn't apply
+        ;; once we switch buffers!!!!  We demand better scope!
+        (_history_ history)
+        (minibuffer-default default))
+    (unwind-protect
+         (progn
+           (set-buffer (reset-buffer buffer))
+           (setq default-directory dir)
+           (make-local-variable 'print-escape-newlines)
+           (setq print-escape-newlines t)
+          (make-local-variable 'current-minibuffer-contents)
+          (make-local-variable 'current-minibuffer-point)
+          (make-local-variable 'initial-minibuffer-history-position)
+          (setq current-minibuffer-contents ""
+                current-minibuffer-point 1)
+          (if (not minibuffer-smart-completion-tracking-behavior)
+              nil
+            (make-local-variable 'mode-motion-hook)
+            (or mode-motion-hook
+                ;;####disgusting
+                (setq mode-motion-hook 'minibuffer-smart-mouse-tracker))
+            (make-local-variable 'mouse-track-click-hook)
+            (add-hook 'mouse-track-click-hook
+                      'minibuffer-smart-maybe-select-highlighted-completion))
+           (set-window-buffer window buffer)
+           (select-window window)
+           (set-window-hscroll window 0)
+           (buffer-enable-undo buffer)
+           (message nil)
+           (if initial-contents
+               (if (consp initial-contents)
+                   (progn
+                     (insert (car initial-contents))
+                     (goto-char (1+ (cdr initial-contents)))
+                    (setq current-minibuffer-contents (car initial-contents)
+                          current-minibuffer-point (cdr initial-contents)))
+                (insert initial-contents)
+                (setq current-minibuffer-contents initial-contents
+                      current-minibuffer-point (point))))
+           (use-local-map (help-keymap-with-help-key
+                          (or keymap minibuffer-local-map)
+                          minibuffer-help-form))
+           (let ((mouse-grabbed-buffer
+                 (and minibuffer-smart-completion-tracking-behavior
+                      (current-buffer)))
+                 (current-prefix-arg current-prefix-arg)
+;;                 (help-form minibuffer-help-form)
+                 (minibuffer-history-variable (cond ((not _history_)
+                                                     'minibuffer-history)
+                                                    ((consp _history_)
+                                                     (car _history_))
+                                                    (t
+                                                     _history_)))
+                 (minibuffer-history-position (cond ((consp _history_)
+                                                     (cdr _history_))
+                                                    (t
+                                                     0)))
+                 (minibuffer-scroll-window owindow))
+            (setq initial-minibuffer-history-position
+                  minibuffer-history-position)
+            (if abbrev-table
+                (setq local-abbrev-table abbrev-table
+                      abbrev-mode t))
+            ;; This is now run from read-minibuffer-internal
+             ;(if minibuffer-setup-hook
+             ;    (run-hooks 'minibuffer-setup-hook))
+             ;(message nil)
+             (if (eq 't
+                     (catch 'exit
+                       (if (> (recursion-depth) (minibuffer-depth))
+                           (let ((standard-output t)
+                                 (standard-input t))
+                             (read-minibuffer-internal prompt))
+                           (read-minibuffer-internal prompt))))
+                 ;; Translate an "abort" (throw 'exit 't)
+                 ;;  into a real quit
+                 (signal 'quit '())
+               ;; return value
+               (let* ((val (progn (set-buffer buffer)
+                                  (if minibuffer-exit-hook
+                                      (run-hooks 'minibuffer-exit-hook))
+                                  (if (and (eq (char-after (point-min)) nil)
+                                          default)
+                                     default
+                                   (buffer-string))))
+                     (histval (if (and default (string= val ""))
+                                  default
+                                val))
+                      (err nil))
+                 (if readp
+                     (condition-case e
+                         (let ((v (read-from-string val)))
+                           (if (< (cdr v) (length val))
+                               (save-match-data
+                                 (or (string-match "[ \t\n]*\\'" val (cdr v))
+                                     (error "Trailing garbage following expression"))))
+                           (setq v (car v))
+                           ;; total total kludge
+                           (if (stringp v) (setq v (list 'quote v)))
+                           (setq val v))
+                       (end-of-file
+                       (setq err
+                             '(input-error "End of input before end of expression")))
+                      (error (setq err e))))
+                 ;; Add the value to the appropriate history list unless
+                 ;; it's already the most recent element, or it's only
+                 ;; two characters long.
+                 (if (and (symbolp minibuffer-history-variable)
+                          (boundp minibuffer-history-variable))
+                    (let ((list (symbol-value minibuffer-history-variable)))
+                      (or (eq list t)
+                          (null val)
+                          (and list (equal histval (car list)))
+                          (and (stringp val)
+                               minibuffer-history-minimum-string-length
+                               (< (length val)
+                                  minibuffer-history-minimum-string-length))
+                          (set minibuffer-history-variable
+                               (if minibuffer-history-uniquify
+                                   (cons histval (remove histval list))
+                                 (cons histval list))))))
+                 (if err (signal (car err) (cdr err)))
+                 val))))
+      ;; stupid display code requires this for some reason
+      (set-buffer buffer)
+      (buffer-disable-undo buffer)
+      (setq buffer-read-only nil)
+      (erase-buffer)
+
+      ;; restore frame configurations
+      (if (and mconfig (frame-live-p oframe)
+              (eq frame (selected-frame)))
+         ;; if we changed frames (due to surrogate minibuffer),
+         ;; and we're still on the new frame, go back to the old one.
+         (select-frame oframe))
+      (if mconfig (set-window-configuration mconfig))
+      (set-window-configuration oconfig))))
+
+
+(defun minibuffer-max-depth-exceeded ()
+  ;;
+  ;; This signals an error if an Nth minibuffer is invoked while N-1 are
+  ;; already active, whether the minibuffer window is selected or not.
+  ;; Since, under X, it's easy to jump out of the minibuffer (by doing M-x,
+  ;; getting distracted, and clicking elsewhere) many many novice users have
+  ;; had the problem of having multiple minibuffers build up, even to the
+  ;; point of exceeding max-lisp-eval-depth.  Since the variable
+  ;; enable-recursive-minibuffers historically/crockishly is only consulted
+  ;; when the minibuffer is currently active (like typing M-x M-x) it doesn't
+  ;; help in this situation.
+  ;;
+  ;; This routine also offers to edit .emacs for you to get rid of this
+  ;; complaint, like `disabled' commands do, since it's likely that non-novice
+  ;; users will be annoyed by this change, so we give them an easy way to get
+  ;; rid of it forever.
+  ;;
+  (beep t 'minibuffer-limit-exceeded)
+  (message
+   "Minibuffer already active: abort it with `^]', enable new one with `n': ")
+  (let ((char (let ((cursor-in-echo-area t)) ; #### doesn't always work??
+               (read-char))))
+    (cond
+     ((eq char ?n)
+      (cond
+       ((y-or-n-p "Enable recursive minibuffers for other sessions too? ")
+       ;; This is completely disgusting, but it's basically what novice.el
+       ;; does.  This kind of thing should be generalized.
+       (setq minibuffer-max-depth nil)
+       (save-excursion
+         (set-buffer
+          (find-file-noselect
+           (substitute-in-file-name custom-file)))
+         (goto-char (point-min))
+         (if (re-search-forward
+              "^(setq minibuffer-max-depth \\([0-9]+\\|'?nil\\|'?()\\))\n"
+              nil t)
+             (delete-region (match-beginning 0 ) (match-end 0))
+           ;; Must have been disabled by default.
+           (goto-char (point-max)))
+         (insert"\n(setq minibuffer-max-depth nil)\n")
+         (save-buffer))
+       (message "Multiple minibuffers enabled")
+       (sit-for 1))))
+     ((eq char ?\1d)
+      (abort-recursive-edit))
+     (t
+      (error "Minibuffer already active")))))
+
+\f
+;;;; Guts of minibuffer completion
+
+
+;; Used by minibuffer-do-completion
+(defvar last-exact-completion nil)
+
+(defun temp-minibuffer-message (m)
+  (let ((savemax (point-max)))
+    (save-excursion
+      (goto-char (point-max))
+      (message nil)
+      (insert m))
+    (let ((inhibit-quit t))
+      (sit-for 2)
+      (delete-region savemax (point-max))
+      ;;  If the user types a ^G while we're in sit-for, then quit-flag
+      ;;  gets set. In this case, we want that ^G to be interpreted
+      ;;  as a normal character, and act just like typeahead.
+      (if (and quit-flag (not unread-command-event))
+          (setq unread-command-event (character-to-event (quit-char))
+                quit-flag nil)))))
+
+
+;; Determines whether buffer-string is an exact completion
+(defun exact-minibuffer-completion-p (buffer-string)
+  (cond ((not minibuffer-completion-table)
+         ;; Empty alist
+         nil)
+        ((vectorp minibuffer-completion-table)
+         (let ((tem (intern-soft buffer-string
+                                 minibuffer-completion-table)))
+           (if (or tem
+                   (and (string-equal buffer-string "nil")
+                        ;; intern-soft loses for 'nil
+                        (catch 'found
+                          (mapatoms #'(lambda (s)
+                                       (if (string-equal
+                                            (symbol-name s)
+                                            buffer-string)
+                                           (throw 'found t)))
+                                   minibuffer-completion-table)
+                          nil)))
+               (if minibuffer-completion-predicate
+                   (funcall minibuffer-completion-predicate
+                            tem)
+                   t)
+               nil)))
+        ((and (consp minibuffer-completion-table)
+              ;;#### Emacs-Lisp truly sucks!
+              ;; lambda, autoload, etc
+              (not (symbolp (car minibuffer-completion-table))))
+         (if (not completion-ignore-case)
+             (assoc buffer-string minibuffer-completion-table)
+             (let ((s (upcase buffer-string))
+                   (tail minibuffer-completion-table)
+                   tem)
+               (while tail
+                 (setq tem (car (car tail)))
+                 (if (or (equal tem buffer-string)
+                         (equal tem s)
+                        (if tem (equal (upcase tem) s)))
+                     (setq s 'win
+                           tail nil)    ;exit
+                     (setq tail (cdr tail))))
+               (eq s 'win))))
+        (t
+         (funcall minibuffer-completion-table
+                  buffer-string
+                  minibuffer-completion-predicate
+                  'lambda)))
+  )
+
+;; 0 'none                 no possible completion
+;; 1 'unique               was already an exact and unique completion
+;; 3 'exact                was already an exact (but nonunique) completion
+;; NOT USED 'completed-exact-unique completed to an exact and completion
+;; 4 'completed-exact      completed to an exact (but nonunique) completion
+;; 5 'completed            some completion happened
+;; 6 'uncompleted          no completion happened
+(defun minibuffer-do-completion-1 (buffer-string completion)
+  (cond ((not completion)
+         'none)
+        ((eq completion t)
+         ;; exact and unique match
+         'unique)
+        (t
+         ;; It did find a match.  Do we match some possibility exactly now?
+         (let ((completedp (not (string-equal completion buffer-string))))
+           (if completedp
+               (progn
+                 ;; Some completion happened
+                 (erase-buffer)
+                 (insert completion)
+                 (setq buffer-string completion)))
+           (if (exact-minibuffer-completion-p buffer-string)
+               ;; An exact completion was possible
+               (if completedp
+;; Since no callers need to know the difference, don't bother
+;;  with this (potentially expensive) discrimination.
+;;                 (if (eq (try-completion completion
+;;                                         minibuffer-completion-table
+;;                                         minibuffer-completion-predicate)
+;;                         't)
+;;                     'completed-exact-unique
+                       'completed-exact
+;;                     )
+                   'exact)
+               ;; Not an exact match
+               (if completedp
+                   'completed
+                   'uncompleted))))))
+
+
+(defun minibuffer-do-completion (buffer-string)
+  (let* ((completion (try-completion buffer-string
+                                     minibuffer-completion-table
+                                     minibuffer-completion-predicate))
+         (status (minibuffer-do-completion-1 buffer-string completion))
+         (last last-exact-completion))
+    (setq last-exact-completion nil)
+    (cond ((eq status 'none)
+           ;; No completions
+           (ding nil 'no-completion)
+           (temp-minibuffer-message " [No match]"))
+          ((eq status 'unique)
+           )
+          (t
+           ;; It did find a match.  Do we match some possibility exactly now?
+           (if (not (string-equal completion buffer-string))
+               (progn
+                 ;; Some completion happened
+                 (erase-buffer)
+                 (insert completion)
+                 (setq buffer-string completion)))
+           (cond ((eq status 'exact)
+                  ;; If the last exact completion and this one were
+                  ;;  the same, it means we've already given a
+                  ;;  "Complete but not unique" message and that the
+                  ;;  user's hit TAB again, so now we give help.
+                  (setq last-exact-completion completion)
+                  (if (equal buffer-string last)
+                      (minibuffer-completion-help)))
+                 ((eq status 'uncompleted)
+                  (if completion-auto-help
+                      (minibuffer-completion-help)
+                      (temp-minibuffer-message " [Next char not unique]")))
+                 (t
+                  nil))))
+    status))
+
+\f
+;;;; completing-read
+
+(defun completing-read (prompt table
+                        &optional predicate require-match
+                                  initial-contents history default)
+  "Read a string in the minibuffer, with completion.
+
+PROMPT is a string to prompt with; normally it ends in a colon and a space.
+TABLE is an alist whose elements' cars are strings, or an obarray.
+TABLE can also be a function which does the completion itself.
+PREDICATE limits completion to a subset of TABLE.
+See `try-completion' and `all-completions' for more details
+  on completion, TABLE, and PREDICATE.
+
+If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless
+  the input is (or completes to) an element of TABLE or is null.
+  If it is also not t, Return does not exit if it does non-null completion.
+If INITIAL-CONTENTS is non-nil, insert it in the minibuffer initially.
+  If it is (STRING . POSITION), the initial input
+  is STRING, but point is placed POSITION characters into the string.
+
+HISTORY, if non-nil, specifies a history list
+  and optionally the initial position in the list.
+  It can be a symbol, which is the history list variable to use,
+  or it can be a cons cell (HISTVAR . HISTPOS).
+  In that case, HISTVAR is the history list variable to use,
+  and HISTPOS is the initial position (the position in the list
+  which INITIAL-CONTENTS corresponds to).
+  If HISTORY is `t', no history will be recorded.
+  Positions are counted starting from 1 at the beginning of the list.
+DEFAULT, if non-nil, will be returned when the user enters an empty
+  string.
+
+Completion ignores case if the ambient value of
+  `completion-ignore-case' is non-nil."
+  (let ((minibuffer-completion-table table)
+        (minibuffer-completion-predicate predicate)
+        (minibuffer-completion-confirm (if (eq require-match 't) nil t))
+        (last-exact-completion nil)
+       ret)
+    (setq ret (read-from-minibuffer prompt
+                                   initial-contents
+                                   (if (not require-match)
+                                       minibuffer-local-completion-map
+                                     minibuffer-local-must-match-map)
+                                   nil
+                                   history
+                                   nil
+                                   default))
+    (if (and (string= ret "")
+            default)
+       default
+      ret)))
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;                   Minibuffer completion commands                   ;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defun minibuffer-complete ()
+  "Complete the minibuffer contents as far as possible.
+Return nil if there is no valid completion, else t.
+If no characters can be completed, display a list of possible completions.
+If you repeat this command after it displayed such a list,
+scroll the window of possible completions."
+  (interactive)
+  ;; If the previous command was not this, then mark the completion
+  ;;  buffer obsolete.
+  (or (eq last-command this-command)
+      (setq minibuffer-scroll-window nil))
+  (let ((window minibuffer-scroll-window))
+    (if (and window (windowp window) (window-buffer window)
+             (buffer-name (window-buffer window)))
+       ;; If there's a fresh completion window with a live buffer
+       ;;  and this command is repeated, scroll that window.
+       (let ((obuf (current-buffer)))
+          (unwind-protect
+             (progn
+               (set-buffer (window-buffer window))
+               (if (pos-visible-in-window-p (point-max) window)
+                   ;; If end is in view, scroll up to the beginning.
+                   (set-window-start window (point-min))
+                 ;; Else scroll down one frame.
+                 (scroll-other-window)))
+           (set-buffer obuf))
+          nil)
+      (let ((status (minibuffer-do-completion (buffer-string))))
+       (if (eq status 'none)
+           nil
+         (progn
+           (cond ((eq status 'unique)
+                  (temp-minibuffer-message
+                   " [Sole completion]"))
+                 ((eq status 'exact)
+                  (temp-minibuffer-message
+                   " [Complete, but not unique]")))
+           t))))))
+
+
+(defun minibuffer-complete-and-exit ()
+  "Complete the minibuffer contents, and maybe exit.
+Exit if the name is valid with no completion needed.
+If name was completed to a valid match,
+a repetition of this command will exit."
+  (interactive)
+  (if (= (point-min) (point-max))
+      ;; Crockishly allow user to specify null string
+      (throw 'exit nil))
+  (let ((buffer-string (buffer-string)))
+    ;; Short-cut -- don't call minibuffer-do-completion if we already
+    ;;  have an (possibly nonunique) exact completion.
+    (if (exact-minibuffer-completion-p buffer-string)
+        (throw 'exit nil))
+    (let ((status (minibuffer-do-completion buffer-string)))
+      (if (or (eq status 'unique)
+              (eq status 'exact)
+              (if (or (eq status 'completed-exact)
+                      (eq status 'completed-exact-unique))
+                  (if minibuffer-completion-confirm
+                      (progn (temp-minibuffer-message " [Confirm]")
+                             nil)
+                      t)))
+          (throw 'exit nil)))))
+
+
+(defun self-insert-and-exit ()
+  "Terminate minibuffer input."
+  (interactive)
+  (self-insert-command 1)
+  (throw 'exit nil))
+
+(defun exit-minibuffer ()
+  "Terminate this minibuffer argument.
+If minibuffer-confirm-incomplete is true, and we are in a completing-read
+of some kind, and the contents of the minibuffer is not an existing
+completion, requires an additional RET before the minibuffer will be exited
+\(assuming that RET was the character that invoked this command:
+the character in question must be typed again)."
+  (interactive)
+  (if (not minibuffer-confirm-incomplete)
+      (throw 'exit nil))
+  (let ((buffer-string (buffer-string)))
+    (if (exact-minibuffer-completion-p buffer-string)
+        (throw 'exit nil))
+    (let ((completion (if (not minibuffer-completion-table)
+                          t
+                          (try-completion buffer-string
+                                          minibuffer-completion-table
+                                          minibuffer-completion-predicate))))
+      (if (or (eq completion 't)
+              ;; Crockishly allow user to specify null string
+              (string-equal buffer-string ""))
+          (throw 'exit nil))
+      (if completion ;; rewritten for I18N3 snarfing
+         (temp-minibuffer-message " [incomplete; confirm]")
+       (temp-minibuffer-message " [no completions; confirm]"))
+      (let ((event (let ((inhibit-quit t))
+                    (prog1
+                        (next-command-event)
+                      (setq quit-flag nil)))))
+        (cond ((equal event last-command-event)
+               (throw 'exit nil))
+              ((equal (quit-char) (event-to-character event))
+               ;; Minibuffer abort.
+               (throw 'exit t)))
+        (dispatch-event event)))))
+\f
+;;;; minibuffer-complete-word
+
+
+;;;#### I think I have done this correctly; it certainly is simpler
+;;;#### than what the C code seemed to be trying to do.
+(defun minibuffer-complete-word ()
+  "Complete the minibuffer contents at most a single word.
+After one word is completed as much as possible, a space or hyphen
+is added, provided that matches some possible completion.
+Return nil if there is no valid completion, else t."
+  (interactive)
+  (let* ((buffer-string (buffer-string))
+         (completion (try-completion buffer-string
+                                     minibuffer-completion-table
+                                     minibuffer-completion-predicate))
+         (status (minibuffer-do-completion-1 buffer-string completion)))
+    (cond ((eq status 'none)
+           (ding nil 'no-completion)
+           (temp-minibuffer-message " [No match]")
+           nil)
+          ((eq status 'unique)
+           ;; New message, only in this new Lisp code
+           (temp-minibuffer-message " [Sole completion]")
+           t)
+          (t
+           (cond ((or (eq status 'uncompleted)
+                      (eq status 'exact))
+                  (let ((foo #'(lambda (s)
+                                (condition-case nil
+                                    (if (try-completion
+                                         (concat buffer-string s)
+                                         minibuffer-completion-table
+                                         minibuffer-completion-predicate)
+                                        (progn
+                                          (goto-char (point-max))
+                                          (insert s)
+                                          t)
+                                       nil)
+                                   (error nil))))
+                        (char last-command-char))
+                    ;; Try to complete by adding a word-delimiter
+                    (or (and (characterp char) (> char 0)
+                             (funcall foo (char-to-string char)))
+                        (and (not (eq char ?\ ))
+                             (funcall foo " "))
+                        (and (not (eq char ?\-))
+                             (funcall foo "-"))
+                        (progn
+                          (if completion-auto-help
+                              (minibuffer-completion-help)
+                              ;; New message, only in this new Lisp code
+                           ;; rewritten for I18N3 snarfing
+                           (if (eq status 'exact)
+                               (temp-minibuffer-message
+                                " [Complete, but not unique]")
+                             (temp-minibuffer-message " [Ambiguous]")))
+                          nil))))
+                 (t
+                  (erase-buffer)
+                  (insert completion)
+                  ;; First word-break in stuff found by completion
+                  (goto-char (point-min))
+                  (let ((len (length buffer-string))
+                        n)
+                    (if (and (< len (length completion))
+                             (catch 'match
+                               (setq n 0)
+                               (while (< n len)
+                                 (if (char-equal
+                                       (upcase (aref buffer-string n))
+                                       (upcase (aref completion n)))
+                                     (setq n (1+ n))
+                                     (throw 'match nil)))
+                               t)
+                             (progn
+                               (goto-char (point-min))
+                               (forward-char len)
+                               (re-search-forward "\\W" nil t)))
+                        (delete-region (point) (point-max))
+                        (goto-char (point-max))))
+                  t))))))
+\f
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;                      "Smart minibuffer" hackery                    ;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; ("Kludgy minibuffer hackery" is perhaps a better name)
+
+;; This works by setting `mouse-grabbed-buffer' to the minibuffer,
+;; defining button2 in the minibuffer keymap to
+;; `minibuffer-smart-select-highlighted-completion', and setting the
+;; mode-motion-hook of the minibuffer to `minibuffer-mouse-tracker'.
+;; By setting `mouse-grabbed-buffer', the minibuffer's keymap and
+;; mode-motion-hook apply (for mouse motion and presses) no matter
+;; what buffer the mouse is over.  Then, `minibuffer-mouse-tracker'
+;; examines the text under the mouse looking for something that looks
+;; like a completion, and causes it to be highlighted, and
+;; `minibuffer-smart-select-highlighted-completion' looks for a
+;; flagged completion under the mouse and inserts it.  This has the
+;; following advantages:
+;;
+;; -- filenames and such in any buffer can be inserted by clicking,
+;;    not just completions
+;;
+;; but the following disadvantages:
+;;
+;; -- unless you're aware of the "filename in any buffer" feature,
+;;    the fact that strings in arbitrary buffers get highlighted appears
+;;    as a bug
+;; -- mouse motion can cause ange-ftp actions -- bad bad bad.
+;;
+;; There's some hackery in minibuffer-mouse-tracker to try to avoid the
+;; ange-ftp stuff, but it doesn't work.
+;;
+
+(defcustom minibuffer-smart-completion-tracking-behavior nil
+  "*If non-nil, look for completions under mouse in all buffers.
+This allows you to click on something that looks like a completion
+and have it selected, regardless of what buffer it is in.
+
+This is not enabled by default because
+
+-- The \"mysterious\" highlighting in normal buffers is confusing to
+   people not expecting it, and looks like a bug
+-- If ange-ftp is enabled, this tracking sometimes causes ange-ftp
+   action as a result of mouse motion, which is *bad bad bad*.
+   Hopefully this bug will be fixed at some point."
+  :type 'boolean
+  :group 'minibuffer)
+
+(defun minibuffer-smart-mouse-tracker (event)
+  ;; Used as the mode-motion-hook of the minibuffer window, which is the
+  ;; value of `mouse-grabbed-buffer' while the minibuffer is active.  If
+  ;; the word under the mouse is a valid minibuffer completion, then it
+  ;; is highlighted.
+  ;;
+  ;; We do some special voodoo when we're reading a pathname, because
+  ;; the way filename completion works is funny.  Possibly there's some
+  ;; more general way this could be dealt with...
+  ;;
+  ;; We do some further voodoo when reading a pathname that is an
+  ;; ange-ftp or efs path, because causing FTP activity as a result of
+  ;; mouse motion is a really bad time.
+  ;;
+  (and minibuffer-smart-completion-tracking-behavior
+       (event-point event)
+       ;; avoid conflict with display-completion-list extents
+       (not (extent-at (event-point event)
+                      (event-buffer event)
+                      'list-mode-item))
+       (let ((filename-kludge-p (eq minibuffer-completion-table
+                                   'read-file-name-internal)))
+        (mode-motion-highlight-internal
+         event
+         #'(lambda () (default-mouse-track-beginning-of-word
+                        (if filename-kludge-p 'nonwhite t)))
+         #'(lambda ()
+             (let ((p (point))
+                   (string ""))
+               (default-mouse-track-end-of-word
+                 (if filename-kludge-p 'nonwhite t))
+               (if (and (/= p (point)) minibuffer-completion-table)
+                   (setq string (buffer-substring p (point))))
+               (if (string-match "\\`[ \t\n]*\\'" string)
+                   (goto-char p)
+                 (if filename-kludge-p
+                     (setq string (minibuffer-smart-select-kludge-filename
+                                   string)))
+                 ;; try-completion bogusly returns a string even when
+                 ;; that string is complete if that string is also a
+                 ;; prefix for other completions.  This means that we
+                 ;; can't just do the obvious thing, (eq t
+                 ;; (try-completion ...)).
+                 (let (comp)
+                   (if (and filename-kludge-p
+                            ;; #### evil evil evil evil
+                            (or (and (fboundp 'ange-ftp-ftp-path)
+                                     (ange-ftp-ftp-path string))
+                                (and (fboundp 'efs-ftp-path)
+                                     (efs-ftp-path string))))
+                       (setq comp t)
+                     (setq comp
+                           (try-completion string
+                                           minibuffer-completion-table
+                                           minibuffer-completion-predicate)))
+                   (or (eq comp t)
+                       (and (equal comp string)
+                            (or (null minibuffer-completion-predicate)
+                                (stringp
+                                 minibuffer-completion-predicate) ; ???
+                                (funcall minibuffer-completion-predicate
+                                         (if (vectorp
+                                              minibuffer-completion-table)
+                                             (intern-soft
+                                              string
+                                              minibuffer-completion-table)
+                                           string))))
+                       (goto-char p))))))))))
+
+(defun minibuffer-smart-select-kludge-filename (string)
+  (save-excursion
+    (set-buffer mouse-grabbed-buffer) ; the minibuf
+    (let ((kludge-string (concat (buffer-string) string)))
+      (if (or (and (fboundp 'ange-ftp-ftp-path)
+                  (ange-ftp-ftp-path kludge-string))
+              (and (fboundp 'efs-ftp-path) (efs-ftp-path kludge-string)))
+          ;; #### evil evil evil, but more so.
+          string
+        (append-expand-filename (buffer-string) string)))))
+
+(defun minibuffer-smart-select-highlighted-completion (event)
+  "Select the highlighted text under the mouse as a minibuffer response.
+When the minibuffer is being used to prompt the user for a completion,
+any valid completions which are visible on the frame will highlight
+when the mouse moves over them.  Clicking \\<minibuffer-local-map>\
+\\[minibuffer-smart-select-highlighted-completion] will select the
+highlighted completion under the mouse.
+
+If the mouse is clicked while not over a highlighted completion,
+then the global binding of \\[minibuffer-smart-select-highlighted-completion] \
+will be executed instead.  In this\nway you can get at the normal global \
+behavior of \\[minibuffer-smart-select-highlighted-completion] as well as
+the special minibuffer behavior."
+  (interactive "e")
+  (if minibuffer-smart-completion-tracking-behavior
+      (minibuffer-smart-select-highlighted-completion-1 event t)
+    (let ((command (lookup-key global-map
+                              (vector current-mouse-event))))
+      (if command (call-interactively command)))))
+
+(defun minibuffer-smart-select-highlighted-completion-1 (event global-p)
+  (let* ((filename-kludge-p (eq minibuffer-completion-table
+                               'read-file-name-internal))
+        completion
+        command-p
+        (evpoint (event-point event))
+        (evextent (and evpoint (extent-at evpoint (event-buffer event)
+                                          'list-mode-item))))
+    (if evextent
+       ;; avoid conflict with display-completion-list extents.
+       ;; if we find one, do that behavior instead.
+       (list-mode-item-selected-1 evextent event)
+      (save-excursion
+       (let* ((buffer (window-buffer (event-window event)))
+              (p (event-point event))
+              (extent (and p (extent-at p buffer 'mouse-face))))
+         (set-buffer buffer)
+         (if (not (and (extent-live-p extent)
+                       (eq (extent-object extent) (current-buffer))
+                       (not (extent-detached-p extent))))
+             (setq command-p t)
+           ;; ...else user has selected a highlighted completion.
+           (setq completion
+                 (buffer-substring (extent-start-position extent)
+                                   (extent-end-position extent)))
+           (if filename-kludge-p
+               (setq completion (minibuffer-smart-select-kludge-filename
+                                 completion)))
+           ;; remove the extent so that it's not hanging around in
+           ;; *Completions*
+           (detach-extent extent)
+           (set-buffer mouse-grabbed-buffer)
+           (erase-buffer)
+           (insert completion))))
+      ;; we need to execute the command or do the throw outside of the
+      ;; save-excursion.
+      (cond ((and command-p global-p)
+            (let ((command (lookup-key global-map
+                                       (vector current-mouse-event))))
+              (if command
+                  (call-interactively command)
+                (if minibuffer-completion-table
+                    (error
+                     "Highlighted words are valid completions.  You may select one.")
+                  (error "no completions")))))
+           ((not command-p)
+            ;; things get confused if the minibuffer is terminated while
+            ;; not selected.
+            (select-window (minibuffer-window))
+            (if (and filename-kludge-p (file-directory-p completion))
+                ;; if the user clicked middle on a directory name, display the
+                ;; files in that directory.
+                (progn
+                  (goto-char (point-max))
+                  (minibuffer-completion-help))
+              ;; otherwise, terminate input
+              (throw 'exit nil)))))))
+
+(defun minibuffer-smart-maybe-select-highlighted-completion
+  (event &optional click-count)
+  "Like `minibuffer-smart-select-highlighted-completion' but does nothing if
+there is no completion (as opposed to executing the global binding).  Useful
+as the value of `mouse-track-click-hook'."
+  (interactive "e")
+  (minibuffer-smart-select-highlighted-completion-1 event nil))
+
+(define-key minibuffer-local-map 'button2
+  'minibuffer-smart-select-highlighted-completion)
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;                         Minibuffer History                         ;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar minibuffer-history '()
+  "Default minibuffer history list.
+This is used for all minibuffer input except when an alternate history
+list is specified.")
+
+;; Some other history lists:
+;;
+(defvar minibuffer-history-search-history '())
+(defvar function-history '())
+(defvar variable-history '())
+(defvar buffer-history '())
+(defvar shell-command-history '())
+(defvar file-name-history '())
+
+(defvar read-expression-history nil)
+
+(defvar minibuffer-history-sexp-flag nil ;weird FSF Emacs kludge
+  "Non-nil when doing history operations on `command-history'.
+More generally, indicates that the history list being acted on
+contains expressions rather than strings.")
+
+(defun previous-matching-history-element (regexp n)
+  "Find the previous history element that matches REGEXP.
+\(Previous history elements refer to earlier actions.)
+With prefix argument N, search for Nth previous match.
+If N is negative, find the next or Nth next match."
+  (interactive
+   (let ((enable-recursive-minibuffers t)
+        (minibuffer-history-sexp-flag nil)
+        (minibuffer-max-depth (and minibuffer-max-depth
+                                   (1+ minibuffer-max-depth))))
+     (if (eq 't (symbol-value minibuffer-history-variable))
+        (error "History is not being recorded in this context"))
+     (list (read-from-minibuffer "Previous element matching (regexp): "
+                                (car minibuffer-history-search-history)
+                                minibuffer-local-map
+                                nil
+                                'minibuffer-history-search-history)
+          (prefix-numeric-value current-prefix-arg))))
+  (let ((history (symbol-value minibuffer-history-variable))
+       prevpos
+       (pos minibuffer-history-position))
+    (if (eq history t)
+       (error "History is not being recorded in this context"))
+    (while (/= n 0)
+      (setq prevpos pos)
+      (setq pos (min (max 1 (+ pos (if (< n 0) -1 1))) (length history)))
+      (if (= pos prevpos)
+         (if (= pos 1) ;; rewritten for I18N3 snarfing
+             (error "No later matching history item")
+           (error "No earlier matching history item")))
+      (if (string-match regexp
+                       (if minibuffer-history-sexp-flag
+                           (let ((print-level nil))
+                             (prin1-to-string (nth (1- pos) history)))
+                            (nth (1- pos) history)))
+         (setq n (+ n (if (< n 0) 1 -1)))))
+    (setq minibuffer-history-position pos)
+    (setq current-minibuffer-contents (buffer-string)
+         current-minibuffer-point (point))
+    (erase-buffer)
+    (let ((elt (nth (1- pos) history)))
+      (insert (if minibuffer-history-sexp-flag
+                 (let ((print-level nil))
+                   (prin1-to-string elt))
+                  elt)))
+      (goto-char (point-min)))
+  (if (or (eq (car (car command-history)) 'previous-matching-history-element)
+         (eq (car (car command-history)) 'next-matching-history-element))
+      (setq command-history (cdr command-history))))
+
+(defun next-matching-history-element (regexp n)
+  "Find the next history element that matches REGEXP.
+\(The next history element refers to a more recent action.)
+With prefix argument N, search for Nth next match.
+If N is negative, find the previous or Nth previous match."
+  (interactive
+   (let ((enable-recursive-minibuffers t)
+        (minibuffer-history-sexp-flag nil)
+        (minibuffer-max-depth (and minibuffer-max-depth
+                                   (1+ minibuffer-max-depth))))
+     (if (eq t (symbol-value minibuffer-history-variable))
+        (error "History is not being recorded in this context"))
+     (list (read-from-minibuffer "Next element matching (regexp): "
+                                (car minibuffer-history-search-history)
+                                minibuffer-local-map
+                                nil
+                                'minibuffer-history-search-history)
+          (prefix-numeric-value current-prefix-arg))))
+  (previous-matching-history-element regexp (- n)))
+
+(defun next-history-element (n)
+  "Insert the next element of the minibuffer history into the minibuffer."
+  (interactive "p")
+  (if (eq 't (symbol-value minibuffer-history-variable))
+      (error "History is not being recorded in this context"))
+  (unless (zerop n)
+    (when (eq minibuffer-history-position
+             initial-minibuffer-history-position)
+      (setq current-minibuffer-contents (buffer-string)
+           current-minibuffer-point (point)))
+    (let ((narg (- minibuffer-history-position n))
+         (minimum (if minibuffer-default -1 0)))
+      ;; a weird special case here; when in repeat-complex-command, we're
+      ;; trying to edit the top command, and minibuffer-history-position
+      ;; points to 1, the next-to-top command.  in this case, the top
+      ;; command in the history is suppressed in favor of the one being
+      ;; edited, and there is no more command below it, except maybe the
+      ;; default.
+      (if (and (zerop narg) (eq minibuffer-history-position
+                               initial-minibuffer-history-position))
+         (setq minimum (1+ minimum)))
+      (cond ((< narg minimum)
+            (error (if minibuffer-default
+                       "No following item in %s"
+                     "No following item in %s; no default available")
+                   minibuffer-history-variable))
+           ((> narg (length (symbol-value minibuffer-history-variable)))
+            (error "No preceding item in %s" minibuffer-history-variable)))
+      (erase-buffer)
+      (setq minibuffer-history-position narg)
+      (if (eq narg initial-minibuffer-history-position)
+         (progn
+           (insert current-minibuffer-contents)
+           (goto-char current-minibuffer-point))
+       (let ((elt (if (> narg 0)
+                      (nth (1- minibuffer-history-position)
+                           (symbol-value minibuffer-history-variable))
+                    minibuffer-default)))
+         (insert
+          (if (not (stringp elt))
+              (let ((print-level nil))
+                (condition-case nil
+                    (let ((print-readably t)
+                          (print-escape-newlines t))
+                      (prin1-to-string elt))
+                  (error (prin1-to-string elt))))
+            elt)))
+       ;; FSF has point-min here.
+       (goto-char (point-max))))))
+
+(defun previous-history-element (n)
+  "Insert the previous element of the minibuffer history into the minibuffer."
+  (interactive "p")
+  (next-history-element (- n)))
+
+(defun next-complete-history-element (n)
+  "Get next element of history which is a completion of minibuffer contents."
+  (interactive "p")
+  (let ((point-at-start (point)))
+    (next-matching-history-element
+     (concat "^" (regexp-quote (buffer-substring (point-min) (point)))) n)
+    ;; next-matching-history-element always puts us at (point-min).
+    ;; Move to the position we were at before changing the buffer contents.
+    ;; This is still sensical, because the text before point has not changed.
+    (goto-char point-at-start)))
+
+(defun previous-complete-history-element (n)
+  "Get previous element of history which is a completion of minibuffer contents."
+  (interactive "p")
+  (next-complete-history-element (- n)))
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;                reading various things from a minibuffer            ;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun read-expression (prompt &optional initial-contents history default-value)
+  "Return a Lisp object read using the minibuffer, prompting with PROMPT.
+If non-nil, optional second arg INITIAL-CONTENTS is a string to insert
+ in the minibuffer before reading.
+Third arg HISTORY, if non-nil, specifies a history list.
+Fourth arg DEFAULT-VALUE is the default value.  If non-nil, it is used
+ for history command, and as the value to return if the user enters the
+ empty string."
+  (let ((minibuffer-history-sexp-flag t)
+       ;; Semi-kludge to get around M-x C-x o M-ESC trying to do completion.
+       (minibuffer-completion-table nil))
+    (read-from-minibuffer prompt
+                         initial-contents
+                         read-expression-map
+                         t
+                         (or history 'read-expression-history)
+                         lisp-mode-abbrev-table
+                         default-value)))
+
+(defun read-string (prompt &optional initial-contents history default-value)
+  "Return a string from the minibuffer, prompting with string PROMPT.
+If non-nil, optional second arg INITIAL-CONTENTS is a string to insert
+ in the minibuffer before reading.
+Third arg HISTORY, if non-nil, specifies a history list.
+Fourth arg DEFAULT-VALUE is the default value.  If non-nil, it is used
+ for history command, and as the value to return if the user enters the
+ empty string."
+  (let ((minibuffer-completion-table nil))
+    (read-from-minibuffer prompt
+                         initial-contents
+                         minibuffer-local-map
+                         nil history nil default-value)))
+
+(defun eval-minibuffer (prompt &optional initial-contents history default-value)
+  "Return value of Lisp expression read using the minibuffer.
+Prompt with PROMPT.  If non-nil, optional second arg INITIAL-CONTENTS
+is a string to insert in the minibuffer before reading.
+Third arg HISTORY, if non-nil, specifies a history list.
+Fourth arg DEFAULT-VALUE is the default value.  If non-nil, it is used
+ for history command, and as the value to return if the user enters the
+ empty string."
+  (eval (read-expression prompt initial-contents history default-value)))
+
+;; The name `command-history' is already taken
+(defvar read-command-history '())
+
+(defun read-command (prompt &optional default-value)
+  "Read the name of a command and return as a symbol.
+Prompts with PROMPT.  By default, return DEFAULT-VALUE."
+  (intern (completing-read prompt obarray 'commandp t nil
+                          ;; 'command-history is not right here: that's a
+                          ;; list of evalable forms, not a history list.
+                          'read-command-history
+                          default-value)))
+
+(defun read-function (prompt &optional default-value)
+  "Read the name of a function and return as a symbol.
+Prompts with PROMPT.  By default, return DEFAULT-VALUE."
+  (intern (completing-read prompt obarray 'fboundp t nil
+                          'function-history default-value)))
+
+(defun read-variable (prompt &optional default-value)
+  "Read the name of a user variable and return it as a symbol.
+Prompts with PROMPT.  By default, return DEFAULT-VALUE.
+A user variable is one whose documentation starts with a `*' character."
+  (intern (completing-read prompt obarray 'user-variable-p t nil
+                          'variable-history
+                          (if (symbolp default-value)
+                              (symbol-name default-value)
+                            default-value))))
+
+(defun read-buffer (prompt &optional default require-match)
+  "Read the name of a buffer and return as a string.
+Prompts with PROMPT.  Optional second arg DEFAULT is value to return if user
+enters an empty line.  If optional third arg REQUIRE-MATCH is non-nil,
+only existing buffer names are allowed."
+  (let ((prompt (if default
+                    (format "%s(default %s) "
+                            (gettext prompt) (if (bufferp default)
+                                                (buffer-name default)
+                                              default))
+                    prompt))
+        (alist (mapcar #'(lambda (b) (cons (buffer-name b) b))
+                       (buffer-list)))
+        result)
+    (while (progn
+             (setq result (completing-read prompt alist nil require-match
+                                          nil 'buffer-history 
+                                          (if (bufferp default)
+                                              (buffer-name default)
+                                            default)))
+             (cond ((not (equal result ""))
+                    nil)
+                   ((not require-match)
+                    (setq result default)
+                    nil)
+                   ((not default)
+                    t)
+                   ((not (get-buffer default))
+                    t)
+                   (t
+                    (setq result default)
+                    nil))))
+    (if (bufferp result)
+        (buffer-name result)
+      result)))
+
+(defun read-number (prompt &optional integers-only default-value)
+  "Read a number from the minibuffer, prompting with PROMPT.
+If optional second argument INTEGERS-ONLY is non-nil, accept
+ only integer input.
+If DEFAULT-VALUE is non-nil, return that if user enters an empty
+ line."
+  (let ((pred (if integers-only 'integerp 'numberp))
+       num)
+    (while (not (funcall pred num))
+      (setq num (condition-case ()
+                   (let ((minibuffer-completion-table nil))
+                     (read-from-minibuffer
+                      prompt (if num (prin1-to-string num)) nil t
+                      nil nil default-value))
+                 (input-error nil)
+                 (invalid-read-syntax nil)
+                 (end-of-file nil)))
+      (or (funcall pred num) (beep)))
+    num))
+
+(defun read-shell-command (prompt &optional initial-input history default-value)
+  "Just like read-string, but uses read-shell-command-map:
+\\{read-shell-command-map}"
+  (let ((minibuffer-completion-table nil))
+    (read-from-minibuffer prompt initial-input read-shell-command-map
+                         nil (or history 'shell-command-history)
+                         nil default-value)))
+
+\f
+;;; This read-file-name stuff probably belongs in files.el
+
+;; Quote "$" as "$$" to get it past substitute-in-file-name
+(defun un-substitute-in-file-name (string)
+  (let ((regexp "\\$")
+        (olen (length string))
+        new
+        n o ch)
+    (if (not (string-match regexp string))
+       string
+      (setq n 1)
+      (while (string-match regexp string (match-end 0))
+       (setq n (1+ n)))
+      (setq new (make-string (+ olen n) ?$))
+      (setq n 0 o 0)
+      (while (< o olen)
+       (setq ch (aref string o))
+       (aset new n ch)
+       (setq o (1+ o) n (1+ n))
+       (if (eq ch ?$)
+           ;; already aset by make-string initial-value
+           (setq n (1+ n))))
+      new)))
+
+
+;; Wrapper for `directory-files' for use in generating completion lists.
+;; Generates output in the same format as `file-name-all-completions'.
+;;
+;; The EFS replacement for `directory-files' doesn't support the FILES-ONLY
+;; option, so it has to be faked.  The listing cache will hopefully
+;; improve the performance of this operation.
+(defun minibuf-directory-files (dir &optional match-regexp files-only)
+  (let ((want-file (or (eq files-only nil) (eq files-only t)))
+        (want-dirs (or (eq files-only nil) (not (eq files-only t)))))
+    (delete nil
+            (mapcar (function (lambda (f)
+                                (if (file-directory-p (expand-file-name f dir))
+                                    (and want-dirs (file-name-as-directory f))
+                                  (and want-file f))))
+                    (delete "." (directory-files dir nil match-regexp))))))
+
+
+(defun read-file-name-2 (history prompt dir default
+                                must-match initial-contents
+                                completer)
+  (if (not dir)
+      (setq dir default-directory))
+  (setq dir (abbreviate-file-name dir t))
+  (let* ((insert (cond ((and (not insert-default-directory)
+                            (not initial-contents))
+                        "")
+                       (initial-contents
+                        (cons (un-substitute-in-file-name
+                              (concat dir initial-contents))
+                              (length dir)))
+                       (t
+                        (un-substitute-in-file-name dir))))
+         (val 
+                ;;  Hateful, broken, case-sensitive un*x
+;;;                 (completing-read prompt
+;;;                                  completer
+;;;                                  dir
+;;;                                  must-match
+;;;                                  insert
+;;;                                  history)
+         ;; #### - this is essentially the guts of completing read.
+         ;; There should be an elegant way to pass a pair of keymaps to
+         ;; completing read, but this will do for now.  All sins are
+         ;; relative.  --Stig
+         (let ((minibuffer-completion-table completer)
+               (minibuffer-completion-predicate dir)
+               (minibuffer-completion-confirm (if (eq must-match 't)
+                                                  nil t))
+               (last-exact-completion nil))
+           (read-from-minibuffer prompt
+                                 insert
+                                 (if (not must-match)
+                                     read-file-name-map
+                                   read-file-name-must-match-map)
+                                 nil
+                                 history
+                                 nil
+                                 default))))
+;;;     ;; Kludge!  Put "/foo/bar" on history rather than "/default//foo/bar"
+;;;     (let ((hist (cond ((not history) 'minibuffer-history)
+;;;                       ((consp history) (car history))
+;;;                       (t history))))
+;;;       (if (and val
+;;;                hist
+;;;                (not (eq hist 't))
+;;;                (boundp hist)
+;;;                (equal (car-safe (symbol-value hist)) val))
+;;;           (let ((e (condition-case nil
+;;;                        (expand-file-name val)
+;;;                      (error nil))))
+;;;             (if (and e (not (equal e val)))
+;;;                 (set hist (cons e (cdr (symbol-value hist))))))))
+
+    (cond ((not val)
+           (error "No file name specified"))
+          ((and default
+                (equal val (if (consp insert) (car insert) insert)))
+           default)
+          (t
+           (substitute-in-file-name val)))))
+
+;; #### this function should use minibuffer-completion-table
+;; or something.  But that is sloooooow.
+;; #### all this shit needs better documentation!!!!!!!!
+(defun read-file-name-activate-callback (event extent dir-p)
+  ;; used as the activate-callback of the filename list items
+  ;; in the completion buffer, in place of default-choose-completion.
+  ;; if a regular file was selected, we call default-choose-completion
+  ;; (which just inserts the string in the minibuffer and calls
+  ;; exit-minibuffer).  If a directory was selected, we display
+  ;; the contents of the directory.
+  (let* ((file (extent-string extent))
+        (completion-buf (extent-object extent))
+        (minibuf (symbol-value-in-buffer 'completion-reference-buffer
+                                         completion-buf))
+        (in-dir (file-name-directory (buffer-substring nil nil minibuf)))
+        (full (expand-file-name file in-dir)))
+    (if (not (file-directory-p full))
+       (default-choose-completion event extent minibuf)
+      (erase-buffer minibuf)
+      (insert-string (file-name-as-directory
+                     (abbreviate-file-name full t)) minibuf)
+      (reset-buffer completion-buf)
+      (let ((standard-output completion-buf))
+       (display-completion-list
+         (minibuf-directory-files full nil (if dir-p 'directory))
+        :user-data dir-p
+        :reference-buffer minibuf
+        :activate-callback 'read-file-name-activate-callback)
+       (goto-char (point-min) completion-buf)))))
+
+(defun read-file-name-1 (type history prompt dir default
+                             must-match initial-contents
+                             completer)
+  (if (should-use-dialog-box-p)
+      (condition-case nil
+         (let ((file
+                (apply #'make-dialog-box
+                       type `(:title ,(capitalize-string-as-title
+                                       ;; Kludge: Delete ": " off the end.
+                                       (replace-in-string prompt ": $" ""))
+                                     ,@(and dir (list :initial-directory
+                                                      dir))
+                                     :file-must-exist ,must-match
+                                     ,@(and initial-contents
+                                            (list :initial-filename
+                                                  initial-contents))))))
+           ;; hack -- until we implement reading a directory properly,
+           ;; allow a file as indicating the directory it's in
+           (if (and (eq completer 'read-directory-name-internal)
+                    (not (file-directory-p file)))
+               (file-name-directory file)
+             file))
+       (unimplemented
+        ;; this calls read-file-name-2
+        (mouse-read-file-name-1 history prompt dir default must-match
+                                initial-contents completer)
+        ))
+    (add-one-shot-hook
+     'minibuffer-setup-hook
+     (lambda ()
+       ;; #### SCREAM!  Create a `file-system-ignore-case'
+       ;; function, so this kind of stuff is generalized!
+       (and (eq system-type 'windows-nt)
+           (set (make-local-variable 'completion-ignore-case) t))
+       (set
+       (make-local-variable
+        'completion-display-completion-list-function)
+       #'(lambda (completions)
+           (display-completion-list
+            completions
+            :user-data (not (eq completer 'read-file-name-internal))
+            :activate-callback
+            'read-file-name-activate-callback)))))
+    (read-file-name-2 history prompt dir default must-match
+                     initial-contents completer)))
+
+(defun read-file-name (prompt
+                       &optional dir default must-match initial-contents
+                      history)
+  "Read file name, prompting with PROMPT and completing in directory DIR.
+This will prompt with a dialog box if appropriate, according to
+ `should-use-dialog-box-p'.
+Value is not expanded---you must call `expand-file-name' yourself.
+Value is subject to interpretation by `substitute-in-file-name' however.
+Default name to DEFAULT if user enters a null string.
+ (If DEFAULT is omitted, the visited file name is used,
+  except that if INITIAL-CONTENTS is specified, that combined with DIR is
+  used.)
+Fourth arg MUST-MATCH non-nil means require existing file's name.
+ Non-nil and non-t means also require confirmation after completion.
+Fifth arg INITIAL-CONTENTS specifies text to start with.  If this is not
+ specified, and `insert-default-directory' is non-nil, DIR or the current
+ directory will be used.
+Sixth arg HISTORY specifies the history list to use.  Default is
+ `file-name-history'.
+DIR defaults to current buffer's directory default."
+  (read-file-name-1 
+   'file (or history 'file-name-history)
+   prompt dir (or default
+                 (and initial-contents
+                      (abbreviate-file-name (expand-file-name
+                                             initial-contents dir) t))
+                 (and buffer-file-truename
+                      (abbreviate-file-name buffer-file-name t)))
+   must-match initial-contents
+   ;; A separate function (not an anonymous lambda-expression)
+   ;; and passed as a symbol because of disgusting kludges in various
+   ;; places which do stuff like (let ((filename-kludge-p (eq minibuffer-completion-table 'read-file-name-internal))) ...)
+   'read-file-name-internal))
+
+(defun read-directory-name (prompt
+                            &optional dir default must-match initial-contents
+                           history)
+  "Read directory name, prompting with PROMPT and completing in directory DIR.
+This will prompt with a dialog box if appropriate, according to
+ `should-use-dialog-box-p'.
+Value is not expanded---you must call `expand-file-name' yourself.
+Value is subject to interpreted by substitute-in-file-name however.
+Default name to DEFAULT if user enters a null string.
+ (If DEFAULT is omitted, the current buffer's default directory is used.)
+Fourth arg MUST-MATCH non-nil means require existing directory's name.
+ Non-nil and non-t means also require confirmation after completion.
+Fifth arg INITIAL-CONTENTS specifies text to start with.
+Sixth arg HISTORY specifies the history list to use.  Default is
+ `file-name-history'.
+DIR defaults to current buffer's directory default."
+  (read-file-name-1
+   'directory (or history 'file-name-history)
+   prompt dir (or default default-directory) must-match initial-contents
+   'read-directory-name-internal))
+
+
+;; Environment-variable and ~username completion hack
+(defun read-file-name-internal-1 (string dir action completer)
+  (if (not (string-match
+           "\\([^$]\\|\\`\\)\\(\\$\\$\\)*\\$\\([A-Za-z0-9_]*\\|{[^}]*\\)\\'"
+           string))
+      ;; Not doing environment-variable completion hack
+      (let* ((orig (if (equal string "") nil string))
+             (sstring (if orig (substitute-in-file-name string) string))
+             (specdir (if orig (file-name-directory sstring) nil))
+             (name    (if orig (file-name-nondirectory sstring) string))
+             (direct  (if specdir (expand-file-name specdir dir) dir)))
+        ;; ~username completion
+        (if (and (fboundp 'user-name-completion-1)
+                 (string-match "^[~]" name))
+            (let ((user (substring name 1)))
+              (cond ((eq action 'lambda)
+                     (file-directory-p name))
+                    ((eq action 't)
+                     ;; all completions
+                     (mapcar #'(lambda (p) (concat "~" p))
+                             (user-name-all-completions user)))
+                    (t;; 'nil
+                     ;; complete
+                     (let* ((val+uniq (user-name-completion-1 user))
+                            (val  (car val+uniq))
+                            (uniq (cdr val+uniq)))
+                       (cond ((stringp val)
+                              (if uniq
+                                  (file-name-as-directory (concat "~" val))
+                                (concat "~" val)))
+                             ((eq val t)
+                              (file-name-as-directory name))
+                             (t nil))))))
+          (funcall completer
+                   action
+                   orig
+                   sstring
+                   specdir
+                   direct
+                   name)))
+      ;; An odd number of trailing $'s
+      (let* ((start (match-beginning 3))
+             (env (substring string
+                             (cond ((= start (length string))
+                                    ;; "...$"
+                                    start)
+                                   ((= (aref string start) ?{)
+                                    ;; "...${..."
+                                    (1+ start))
+                                   (t
+                                    start))))
+             (head (substring string 0 (1- start)))
+             (alist #'(lambda ()
+                        (mapcar #'(lambda (x)
+                                    (cons (substring x 0 (string-match "=" x))
+                                          nil))
+                                process-environment))))
+
+       (cond ((eq action 'lambda)
+               nil)
+              ((eq action 't)
+               ;; all completions
+               (mapcar #'(lambda (p)
+                          (if (and (> (length p) 0)
+                                   ;;#### Unix-specific
+                                   ;;####  -- need absolute-pathname-p
+                                   (/= (aref p 0) ?/))
+                              (concat "$" p)
+                             (concat head "$" p)))
+                       (all-completions env (funcall alist))))
+              (t ;; nil
+               ;; complete
+               (let* ((e (funcall alist))
+                      (val (try-completion env e)))
+                 (cond ((stringp val)
+                        (if (string-match "[^A-Za-z0-9_]" val)
+                            (concat head
+                                    "${" val
+                                    ;; completed uniquely?
+                                    (if (eq (try-completion val e) 't)
+                                        "}" ""))
+                            (concat head "$" val)))
+                       ((eql val 't)
+                        (concat head
+                                (un-substitute-in-file-name (getenv env))))
+                       (t nil))))))))
+
+
+(defun read-file-name-internal (string dir action)
+  (read-file-name-internal-1
+   string dir action
+   #'(lambda (action orig string specdir dir name)
+      (cond ((eq action 'lambda)
+             (if (not orig)
+                 nil
+               (let ((sstring (condition-case nil
+                                  (expand-file-name string)
+                                (error nil))))
+                 (if (not sstring)
+                     ;; Some pathname syntax error in string
+                     nil
+                     (file-exists-p sstring)))))
+            ((eq action 't)
+             ;; all completions
+             (mapcar #'un-substitute-in-file-name
+                     (if (string= name "")
+                         (delete "./" (file-name-all-completions "" dir))
+                       (file-name-all-completions name dir))))
+            (t;; nil
+             ;; complete
+             (let* ((d (or dir default-directory))
+                   (val (file-name-completion name d)))
+               (if (and (eq val 't)
+                        (not (null completion-ignored-extensions)))
+                   ;;#### (file-name-completion "foo") returns 't
+                   ;;   when both "foo" and "foo~" exist and the latter
+                   ;;   is "pruned" by completion-ignored-extensions.
+                   ;; I think this is a bug in file-name-completion.
+                   (setq val (let ((completion-ignored-extensions '()))
+                               (file-name-completion name d))))
+               (if (stringp val)
+                   (un-substitute-in-file-name (if specdir
+                                                   (concat specdir val)
+                                                   val))
+                   (let ((tem (un-substitute-in-file-name string)))
+                     (if (not (equal tem orig))
+                         ;; substitute-in-file-name did something
+                         tem
+                         val)))))))))
+
+(defun read-directory-name-internal (string dir action)
+  (read-file-name-internal-1
+   string dir action
+   #'(lambda (action orig string specdir dir name)
+      (let* ((dirs #'(lambda (fn)
+                      (let ((l (if (equal name "")
+                                   (minibuf-directory-files
+                                    dir
+                                    ""
+                                    'directories)
+                                 (minibuf-directory-files
+                                  dir
+                                  (concat "\\`" (regexp-quote name))
+                                  'directories))))
+                        (mapcar fn
+                                ;; Wretched unix
+                                (delete "." l))))))
+        (cond ((eq action 'lambda)
+               ;; complete?
+               (if (not orig)
+                   nil
+                (file-directory-p string)))
+              ((eq action 't)
+               ;; all completions
+               (funcall dirs #'(lambda (n)
+                                (un-substitute-in-file-name
+                                 (file-name-as-directory n)))))
+              (t
+               ;; complete
+               (let ((val (try-completion
+                           name
+                           (funcall dirs
+                                    #'(lambda (n)
+                                       (list (file-name-as-directory
+                                              n)))))))
+                 (if (stringp val)
+                     (un-substitute-in-file-name (if specdir
+                                                     (concat specdir val)
+                                                  val))
+                  (let ((tem (un-substitute-in-file-name string)))
+                    (if (not (equal tem orig))
+                        ;; substitute-in-file-name did something
+                        tem
+                      val))))))))))
+
+(defun append-expand-filename (file-string string)
+  "Append STRING to FILE-STRING differently depending on whether STRING
+is a username (~string), an environment variable ($string),
+or a filename (/string).  The resultant string is returned with the
+environment variable or username expanded and resolved to indicate
+whether it is a file(/result) or a directory (/result/)."
+  (let ((file
+        (cond ((string-match "\\([~$]\\)\\([^~$/]*\\)$" file-string)
+               (cond ((string= (substring file-string
+                                          (match-beginning 1)
+                                          (match-end 1)) "~")
+                      (concat (substring file-string 0 (match-end 1))
+                              string))
+                     (t (substitute-in-file-name
+                         (concat (substring file-string 0 (match-end 1))
+                                 string)))))
+              (t (concat (file-name-directory
+                          (substitute-in-file-name file-string)) string))))
+       result)
+
+    (cond ((stringp (setq result (and (file-exists-p (expand-file-name file))
+                                     (read-file-name-internal
+                                      (condition-case nil
+                                          (expand-file-name file)
+                                        (error file))
+                                      "" nil))))
+          result)
+         (t file))))
+
+(defun mouse-rfn-setup-vars (prompt)
+  ;; a specifier would be nice.
+  (set (make-local-variable 'frame-title-format)
+       (capitalize-string-as-title
+       ;; Kludge: Delete ": " off the end.
+       (replace-in-string prompt ": $" "")))
+  ;; ensure that killing the frame works right,
+  ;; instead of leaving us in the minibuffer.
+  (add-local-hook 'delete-frame-hook
+                 #'(lambda (frame)
+                     (abort-recursive-edit))))
+
+(defun mouse-file-display-completion-list (window dir minibuf user-data)
+  (let ((standard-output (window-buffer window)))
+    (condition-case nil
+       (display-completion-list
+        (minibuf-directory-files dir nil t)
+        :window-width (window-width window)
+        :window-height (window-text-area-height window)
+        :completion-string ""
+        :activate-callback
+        'mouse-read-file-name-activate-callback
+        :user-data user-data
+        :reference-buffer minibuf
+        :help-string "")
+      (t nil))
+    ))
+
+(defun mouse-directory-display-completion-list (window dir minibuf user-data)
+  (let ((standard-output (window-buffer window)))
+    (condition-case nil
+       (display-completion-list
+        (minibuf-directory-files dir nil 1)
+        :window-width (window-width window)
+        :window-height (window-text-area-height window)
+        :completion-string ""
+        :activate-callback
+        'mouse-read-file-name-activate-callback
+        :user-data user-data
+        :reference-buffer minibuf
+        :help-string "")
+      (t nil))
+    ))
+
+(defun mouse-read-file-name-activate-callback (event extent user-data)
+  (let* ((file (extent-string extent))
+        (minibuf (symbol-value-in-buffer 'completion-reference-buffer
+                                         (extent-object extent)))
+        (ministring (buffer-substring nil nil minibuf))
+        (in-dir (file-name-directory ministring))
+        (full (expand-file-name file in-dir))
+        (filebuf (nth 0 user-data))
+        (dirbuf (nth 1 user-data))
+        (filewin (nth 2 user-data))
+        (dirwin (nth 3 user-data)))
+    (if (file-regular-p full)
+       (default-choose-completion event extent minibuf)
+      (erase-buffer minibuf)
+      (insert-string (file-name-as-directory
+                     (abbreviate-file-name full t)) minibuf)
+      (reset-buffer filebuf)
+      (if (not dirbuf)
+         (mouse-directory-display-completion-list filewin full minibuf
+                                                  user-data)
+       (mouse-file-display-completion-list filewin full minibuf user-data)
+       (reset-buffer dirbuf)
+       (mouse-directory-display-completion-list dirwin full minibuf
+                                                user-data)))))
+
+;; our cheesy but god-awful time consuming file dialog box implementation.
+;; this will be replaced with use of the native file dialog box (when
+;; available).
+(defun mouse-read-file-name-1 (history prompt dir default
+                                      must-match initial-contents
+                                      completer)
+  ;; file-p is t if we're reading files, nil if directories.
+  (let* ((file-p (eq 'read-file-name-internal completer))
+        (filebuf (get-buffer-create "*Completions*"))
+        (dirbuf (and file-p (generate-new-buffer " *mouse-read-file*")))
+        (butbuf (generate-new-buffer " *mouse-read-file*"))
+        (frame (make-dialog-frame))
+        filewin dirwin
+        user-data)
+    (unwind-protect
+       (progn
+         (reset-buffer filebuf)
+
+         ;; set up the frame.
+         (focus-frame frame)
+         (let ((window-min-height 1))
+           ;; #### should be 2 not 3, but that causes
+           ;; "window too small to split" errors for some
+           ;; people (but not for me ...) There's a more
+           ;; fundamental bug somewhere.
+           (split-window nil (- (frame-height frame) 3)))
+         (if file-p
+             (progn
+               (split-window-horizontally 16)
+               (setq filewin (frame-rightmost-window frame)
+                     dirwin (frame-leftmost-window frame))
+               (set-window-buffer filewin filebuf)
+               (set-window-buffer dirwin dirbuf))
+           (setq filewin (frame-highest-window frame))
+           (set-window-buffer filewin filebuf))
+         (setq user-data (list filebuf dirbuf filewin dirwin))
+         (set-window-buffer (frame-lowest-window frame) butbuf)
+
+         ;; set up completion buffers.
+         (let ((rfcshookfun
+                ;; kludge!
+                ;; #### I really need to flesh out the object
+                ;; hierarchy better to avoid these kludges.
+                ;; (?? I wrote this comment above some time ago,
+                ;; and I don't understand what I'm referring to
+                ;; any more. --ben
+                (lambda ()
+                  (mouse-rfn-setup-vars prompt)
+                  (when (featurep 'scrollbar)
+                    (set-specifier scrollbar-width 0 (current-buffer)))
+                  (setq truncate-lines t))))
+           
+           (set-buffer filebuf)
+           (add-local-hook 'completion-setup-hook rfcshookfun)
+           (when file-p
+             (set-buffer dirbuf)
+             (add-local-hook 'completion-setup-hook rfcshookfun)))
+
+         ;; set up minibuffer.
+         (add-one-shot-hook
+          'minibuffer-setup-hook
+          (lambda ()
+            (if (not file-p)
+                (mouse-directory-display-completion-list
+                 filewin dir (current-buffer) user-data)
+              (mouse-file-display-completion-list
+               filewin dir (current-buffer) user-data)
+              (mouse-directory-display-completion-list
+               dirwin dir (current-buffer) user-data))
+            (set
+             (make-local-variable
+              'completion-display-completion-list-function)
+             (lambda (completions)
+               (display-completion-list
+                completions
+                :help-string ""
+                :window-width (window-width filewin)
+                :window-height (window-text-area-height filewin)
+                :completion-string ""
+                :activate-callback
+                'mouse-read-file-name-activate-callback
+                :user-data user-data)))
+            (mouse-rfn-setup-vars prompt)
+            (save-selected-window
+              ;; kludge to ensure the frame title is correct.
+              ;; the minibuffer leaves the frame title the way
+              ;; it was before (i.e. of the selected window before
+              ;; the dialog box was opened), so to get it correct
+              ;; we have to be tricky.
+              (select-window filewin)
+              (redisplay-frame nil t)
+              ;; #### another kludge.  sometimes the focus ends up
+              ;; back in the main window, not the dialog box.  it
+              ;; occurs randomly and it's not possible to reliably
+              ;; reproduce.  We try to fix it by draining non-user
+              ;; events and then setting the focus back on the frame.
+              (sit-for 0 t)
+              (focus-frame frame))))
+
+         ;; set up button buffer.
+         (set-buffer butbuf)
+         (mouse-rfn-setup-vars prompt)
+         (when dir
+           (setq default-directory dir))
+         (when (featurep 'scrollbar)
+           (set-specifier scrollbar-width 0 butbuf))
+         (insert "                 ")
+         (insert-gui-button (make-gui-button "OK"
+                                             (lambda (foo)
+                                               (exit-minibuffer))))
+         (insert "                 ")
+         (insert-gui-button (make-gui-button "Cancel"
+                                             (lambda (foo)
+                                               (abort-recursive-edit))))
+
+         ;; now start reading filename.
+         (read-file-name-2 history prompt dir default
+                           must-match initial-contents
+                           completer))
+
+      ;; always clean up.
+      ;; get rid of our hook that calls abort-recursive-edit -- not a good
+      ;; idea here.
+      (kill-local-variable 'delete-frame-hook)
+      (delete-frame frame)
+      (kill-buffer filebuf)
+      (kill-buffer butbuf)
+      (and dirbuf (kill-buffer dirbuf)))))
+
+(defun read-face (prompt &optional must-match)
+  "Read the name of a face from the minibuffer and return it as a symbol."
+  (intern (completing-read prompt obarray 'find-face must-match)))
+
+;; #### - wrong place for this variable?  Exactly.  We probably want
+;; `color-list' to be a console method, so `tty-color-list' becomes
+;; obsolete, and `read-color-completion-table' conses (mapcar #'list
+;; (color-list)), optionally caching the results.
+
+;; Ben wanted all of the possibilities from the `configure' script used
+;; here, but I think this is way too many.  I already trimmed the R4 variants
+;; and a few obvious losers from the list.  --Stig
+(defvar x-library-search-path '("/usr/X11R6/lib/X11/"
+                               "/usr/X11R5/lib/X11/"
+                               "/usr/lib/X11R6/X11/"
+                               "/usr/lib/X11R5/X11/"
+                               "/usr/local/X11R6/lib/X11/"
+                               "/usr/local/X11R5/lib/X11/"
+                               "/usr/local/lib/X11R6/X11/"
+                               "/usr/local/lib/X11R5/X11/"
+                               "/usr/X11/lib/X11/"
+                               "/usr/lib/X11/"
+                               "/usr/local/lib/X11/"
+                               "/usr/X386/lib/X11/"
+                               "/usr/x386/lib/X11/"
+                               "/usr/XFree86/lib/X11/"
+                               "/usr/unsupported/lib/X11/"
+                               "/usr/athena/lib/X11/"
+                               "/usr/local/x11r5/lib/X11/"
+                               "/usr/lpp/Xamples/lib/X11/"
+                               "/usr/openwin/lib/X11/"
+                               "/usr/openwin/share/lib/X11/")
+  "Search path used by `read-color' to find rgb.txt.")
+
+(defvar x-read-color-completion-table)
+
+(defun read-color-completion-table ()
+  (case (device-type)
+    ;; #### Evil device-type dependency
+    ((x gtk)
+     (if (boundp 'x-read-color-completion-table)
+        x-read-color-completion-table
+       (let ((rgb-file (locate-file "rgb.txt" x-library-search-path))
+            clist color p)
+        (if (not rgb-file)
+            ;; prevents multiple searches for rgb.txt if we can't find it
+            (setq x-read-color-completion-table nil)
+          (with-current-buffer (get-buffer-create " *colors*")
+            (reset-buffer (current-buffer))
+            (insert-file-contents rgb-file)
+            (while (not (eobp))
+              ;; skip over comments
+              (while (looking-at "^!")
+                (end-of-line)
+                (forward-char 1))
+              (skip-chars-forward "0-9 \t")
+              (setq p (point))
+              (end-of-line)
+              (setq color (buffer-substring p (point))
+                    clist (cons (list color) clist))
+              ;; Ugh.  If we want to be able to complete the lowercase form
+              ;; of the color name, we need to add it twice!  Yuck.
+              (let ((dcase (downcase color)))
+                (or (string= dcase color)
+                    (push (list dcase) clist)))
+              (forward-char 1))
+            (kill-buffer (current-buffer))))
+        (setq x-read-color-completion-table clist)
+        x-read-color-completion-table)))
+    (mswindows
+     (mapcar #'list (mswindows-color-list)))
+    (tty
+     (mapcar #'list (tty-color-list)))))
+
+(defun read-color (prompt &optional must-match initial-contents)
+  "Read the name of a color from the minibuffer.
+On X devices, this uses `x-library-search-path' to find rgb.txt in order
+ to build a completion table.
+On TTY devices, this uses `tty-color-list'.
+On mswindows devices, this uses `mswindows-color-list'."
+  (let ((table (read-color-completion-table)))
+    (completing-read prompt table nil (and table must-match)
+                    initial-contents)))
+
+\f
+;; #### The doc string for read-non-nil-coding system gets lost if we
+;; only include these if the mule feature is present.  Strangely,
+;; read-coding-system doesn't.
+
+;;(if (featurep 'mule)
+
+(defun read-coding-system (prompt &optional default-coding-system)
+  "Read a coding-system (or nil) from the minibuffer.
+Prompting with string PROMPT.
+If the user enters null input, return second argument DEFAULT-CODING-SYSTEM.
+DEFAULT-CODING-SYSTEM can be a string, symbol, or coding-system object."
+  (intern (completing-read prompt obarray 'find-coding-system t nil nil 
+                          (cond ((symbolp default-coding-system)
+                                 (symbol-name default-coding-system))
+                                ((coding-system-p default-coding-system)
+                                 (symbol-name (coding-system-name default-coding-system)))
+                                (t
+                                 default-coding-system)))))
+
+(defun read-non-nil-coding-system (prompt)
+  "Read a non-nil coding-system from the minibuffer.
+Prompt with string PROMPT."
+  (let ((retval (intern "")))
+    (while (= 0 (length (symbol-name retval)))
+      (setq retval (intern (completing-read prompt obarray
+                                           'find-coding-system
+                                           t))))
+    retval))
+
+;;) ;; end of (featurep 'mule)
+
+\f
+
+(defcustom force-dialog-box-use nil
+  "*If non-nil, always use a dialog box for asking questions, if possible.
+You should *bind* this, not set it.  This is useful if you're doing
+something mousy but which wasn't actually invoked using the mouse."
+  :type 'boolean
+  :group 'minibuffer)
+
+;; We include this here rather than dialog.el so it is defined
+;; even when dialog boxes are not present.
+(defun should-use-dialog-box-p ()
+  "If non-nil, questions should be asked with a dialog box instead of the
+minibuffer.  This looks at `last-command-event' to see if it was a mouse
+event, and checks whether dialog-support exists and the current device
+supports dialog boxes.
+
+The dialog box is totally disabled if the variable `use-dialog-box'
+is set to nil."
+  (and (featurep 'dialog)
+       (device-on-window-system-p)
+       use-dialog-box
+       (or force-dialog-box-use
+          (button-press-event-p last-command-event)
+          (button-release-event-p last-command-event)
+          (misc-user-event-p last-command-event))))
+
+;;; minibuf.el ends here