diff lisp/ido.el @ 88155:d7ddb3e565de

sync with trunk
author Henrik Enberg <henrik.enberg@telia.com>
date Mon, 16 Jan 2006 00:03:54 +0000
parents 1da4c425c852
children
line wrap: on
line diff
--- a/lisp/ido.el	Sun Jan 15 23:02:10 2006 +0000
+++ b/lisp/ido.el	Mon Jan 16 00:03:54 2006 +0000
@@ -1,6 +1,7 @@
 ;;; ido.el --- interactively do things with buffers and files.
 
-;; Copyright (C) 1996-2003  Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+;;   2004, 2005 Free Software Foundation, Inc.
 
 ;; Author: Kim F. Storm <storm@cua.dk>
 ;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
@@ -20,46 +21,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Acknowledgements
-
-;; Infinite amounts of gratitude goes to Stephen Eglen <stephen@cns.ed.ac.uk>
-;; who wrote iswitch-buffer mode - from which I ripped off 99% of the code
-;; for ido-switch-buffer and found the inspiration for ido-find-file.
-;; The ido package would never have existed without his work.
-
-;; Also thanks to Klaus Berndl, Rohit Namjoshi, Robert Fenk, Alex Schroeder,
-;; Bill Benedetto, and Stephen Eglen for bug fixes and improvements.
-
-;;; History
-
-;; Since I discovered Stephen Eglen's excellent iswitchb package, I just
-;; couldn't live without it, but once being addicted to switching buffers
-;; with a minimum of keystrokes, I soon found that opening files in the
-;; old-fashioned way was just too slow - so I decided to write a package
-;; which could open files with the same speed and ease as iswitchb could
-;; switch buffers.
-
-;; I originally wrote a separate ifindf.el package based on a copy of
-;; iswitchb.el, which did for opening files what iswitchb did for
-;; switching buffers.  Along the way, I corrected a few errors in
-;; ifindf which could have found its way back into iswitchb, but since
-;; most of the functionality of the two package was practically
-;; identical, I decided that the proper thing to do was to merge my
-;; ifindf package back into iswitchb.
-;;
-;; This is basically what ido (interactively do) is all about; but I
-;; found it ackward to merge my changes into the "iswitchb-" namespace,
-;; so I invented a common "ido-" namespace for the merged packages.
-;;
-;; This version is based on ido.el version 1.57 released on
-;; gnu.emacs.sources adapted for emacs 21.4 to use command remapping
-;; and optionally hooking the read-buffer and read-file-name functions.
-;;
-;; Prefix matching was added by Klaus Berndl <klaus.berndl@sdm.de> based on
-;; an idea of Yuji Minejima <ggb01164@nifty.ne.jp> and his mcomplete-package.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 
 ;;; Commentary:
@@ -92,23 +55,23 @@
 ;; most recent, when I use ido-switch-buffer, I first of all get
 ;; presented with the list of all the buffers
 ;;
-;;       Buffer:  {123456,123}
+;;       Buffer: {123456 | 123}
 ;;
 ;; If I then press 2:
-;;       Buffer: 2[3]{123456,123}
+;;       Buffer: 2[3]{123456 | 123}
 ;;
 ;; The list in {...} are the matching buffers, most recent first
 ;; (buffers visible in the current frame are put at the end of the
 ;; list by default).  At any time I can select the item at the head of
-;; the list by pressing RET.  I can also bring the put the first
-;; element at the end of the list by pressing C-s or [right], or put
-;; the last element at the head of the list by pressing C-r or [left].
+;; the list by pressing RET.  I can also put the first element at the
+;; end of the list by pressing C-s or [right], or bring the last
+;; element to the head of the list by pressing C-r or [left].
 ;;
 ;; The item in [...] indicates what can be added to my input by
 ;; pressing TAB.  In this case, I will get "3" added to my input.
 
 ;; So, I press TAB:
-;;	 Buffer: 23{123456,123}
+;;	 Buffer: 23{123456 | 123}
 ;;
 ;; At this point, I still have two matching buffers.
 ;; If I want the first buffer in the list, I simply press RET.  If I
@@ -116,13 +79,16 @@
 ;; top of the list and then RET to select it.
 ;;
 ;; However, if I type 4, I only have one match left:
-;;       Buffer: 234[123456] [Matched]
+;;       Buffer: 234[123456]
 ;;
-;; Since there is only one matching buffer left, it is given in [] and we
-;; see the text [Matched] afterwards.  I can now press TAB or RET to go
-;; to that buffer.
+;; Since there is only one matching buffer left, it is given in [] and
+;; it is shown in the `ido-only-match' face (ForestGreen).  I can now
+;; press TAB or RET to go to that buffer.
 ;;
-;; If however, I now type "a":
+;; If I want to create a new buffer named "234", I press C-j instead of
+;; TAB or RET.
+;;
+;; If instead, I type "a":
 ;;       Buffer: 234a [No match]
 ;; There are no matching buffers.  If I press RET or TAB, I can be
 ;; prompted to create a new buffer called "234a".
@@ -209,8 +175,7 @@
 ;; Example:
 ;;
 ;; If you have again two Buffers "123456" and "123" then hitting "2" does
-;; not match because "2" is not a PREFIX in any of the buffer-names. This
-;; is the only difference between the substring and prefix matching.
+;; not match because "2" is not a PREFIX in any of the buffer-names.
 
 ;; Flexible matching
 ;; -----------------
@@ -235,14 +200,10 @@
 ;;
 ;; There is limited provision for regexp matching within ido,
 ;; enabled through `ido-enable-regexp' (toggle with C-t).
-;; This allows you to type `c$' for example and see all file names
-;; ending in `c'.  This facility is quite limited though in two
-;; respects.  First, you can't currently type in expressions like
-;; `[0-9]' directly -- you have to type them in when ido-enable-regexp
-;; is nil and then toggle on the regexp functionality.  Likewise,
-;; don't enter an expression containing `\' in regexp mode.  If you
-;; try, ido gets confused, so just hit C-g and try again.  Secondly,
-;; no completion mechanism is currently offered with regexp searching.
+;; This allows you to type `[ch]$' for example and see all file names
+;; ending in `c' or `h'.
+;;
+;; Note: ido-style completion is inhibited when you enable regexp matching.
 
 
 ;; Customization
@@ -250,12 +211,12 @@
 ;;
 ;; Customize the `ido' group to change the `ido' functionality.
 ;;
-;; To modify the keybindings, use the hook provided.  For example:
-;;(add-hook 'ido-define-mode-map-hook 'ido-my-keys)
+;; To modify the keybindings, use the ido-setup-hook.  For example:
+;;(add-hook 'ido-setup-hook 'ido-my-keys)
 ;;
 ;;(defun ido-my-keys ()
 ;;  "Add my keybindings for ido."
-;;  (define-key ido-mode-map " " 'ido-next-match)
+;;  (define-key ido-completion-map " " 'ido-next-match)
 ;;  )
 
 ;; Seeing all the matching buffers or files
@@ -290,7 +251,7 @@
 ;; then all files matching "Summary" are moved to the end of the
 ;; list.  (I find this handy for keeping the INBOX Summary and so on
 ;; out of the way.)  It also moves files matching "output\*$" to the
-;; end of the list (these are created by AUC TeX when compiling.)
+;; end of the list (these are created by AUCTeX when compiling.)
 ;; Other functions could be made available which alter the list of
 ;; matching files (either deleting or rearranging elements.)
 
@@ -298,8 +259,8 @@
 ;; ------------
 
 ;; The highlighting of matching items is controlled via ido-use-faces.
-;; The faces used are ido-first-match-face, ido-only-match-face and
-;; ido-subdir-face.
+;; The faces used are ido-first-match, ido-only-match and
+;; ido-subdir.
 ;; Colouring of the matching item was suggested by
 ;; Carsten Dominik (dominik@strw.leidenuniv.nl).
 
@@ -321,11 +282,52 @@
 ;; can be used by other packages to read a buffer name, a file name,
 ;; or a directory name in the `ido' way.
 
+;;; Acknowledgements
+
+;; Infinite amounts of gratitude goes to Stephen Eglen <stephen@cns.ed.ac.uk>
+;; who wrote iswitch-buffer mode - from which I ripped off 99% of the code
+;; for ido-switch-buffer and found the inspiration for ido-find-file.
+;; The ido package would never have existed without his work.
+
+;; Also thanks to Klaus Berndl, Rohit Namjoshi, Robert Fenk, Alex
+;; Schroeder, Bill Benedetto, Stephen Eglen, and many others for bug
+;; fixes and improvements.
+
+;;; History
+
+;; Since I discovered Stephen Eglen's excellent iswitchb package, I just
+;; couldn't live without it, but once being addicted to switching buffers
+;; with a minimum of keystrokes, I soon found that opening files in the
+;; old-fashioned way was just too slow - so I decided to write a package
+;; which could open files with the same speed and ease as iswitchb could
+;; switch buffers.
+
+;; I originally wrote a separate ifindf.el package based on a copy of
+;; iswitchb.el, which did for opening files what iswitchb did for
+;; switching buffers.  Along the way, I corrected a few errors in
+;; ifindf which could have found its way back into iswitchb, but since
+;; most of the functionality of the two package was practically
+;; identical, I decided that the proper thing to do was to merge my
+;; ifindf package back into iswitchb.
+;;
+;; This is basically what ido (interactively do) is all about; but I
+;; found it ackward to merge my changes into the "iswitchb-" namespace,
+;; so I invented a common "ido-" namespace for the merged packages.
+;;
+;; This version is based on ido.el version 1.57 released on
+;; gnu.emacs.sources adapted for emacs 22.1 to use command remapping
+;; and optionally hooking the read-buffer and read-file-name functions.
+;;
+;; Prefix matching was added by Klaus Berndl <klaus.berndl@sdm.de> based on
+;; an idea of Yuji Minejima <ggb01164@nifty.ne.jp> and his mcomplete-package.
+
 
 ;;; Code:
 
 (provide 'ido)
 
+(defvar cua-inhibit-cua-keys)
+
 ;;; User Variables
 ;;
 ;; These are some things you might want to change.
@@ -337,13 +339,14 @@
   "Switch between files using substrings."
   :group 'extensions
   :group 'convenience
+  :version "22.1"
   :link '(emacs-commentary-link :tag "Commentary" "ido.el")
   :link '(emacs-library-link :tag "Lisp File" "ido.el"))
 
 ;;;###autoload
 (defcustom ido-mode nil
   "Determines for which functional group \(buffer and files) ido behavior
-should be enabled. The following values are possible:
+should be enabled.  The following values are possible:
 - `buffer': Turn only on ido buffer behavior \(switching, killing,
   displaying...)
 - `file': Turn only on ido file behavior \(finding, writing, inserting...)
@@ -354,11 +357,10 @@
 use either \\[customize] or the function `ido-mode'."
   :set #'(lambda (symbol value)
 	   (ido-mode value))
-  :initialize 'custom-initialize-default
+  :initialize 'custom-initialize-set
   :require 'ido
   :link '(emacs-commentary-link "ido.el")
   :set-after '(ido-save-directory-list-file)
-  :version "21.4"
   :type '(choice (const :tag "Turn on only buffer" buffer)
                  (const :tag "Turn on only file" file)
                  (const :tag "Turn on both buffer and file" both)
@@ -370,7 +372,7 @@
 Setting this variable directly does not work.  Use `customize' or
 call the function `ido-everywhere'."
   :set #'(lambda (symbol value)
-	   (ido-everywhere value))
+	   (ido-everywhere (if value 1 -1)))
   :initialize 'custom-initialize-default
   :type 'boolean
   :group 'ido)
@@ -409,6 +411,15 @@
   :type 'boolean
   :group 'ido)
 
+(defcustom ido-file-extensions-order nil
+  "*List of file extensions specifying preferred order of file selections.
+Each element is either a string with `.' as the first char, an empty
+string matching files without extension, or t which is the default order
+for files with an unlisted file extension."
+  :type '(repeat (choice string
+			 (const :tag "Default order" t)))
+  :group 'ido)
+
 (defcustom ido-ignore-directories
   '("\\`CVS/" "\\`\\.\\./" "\\`\\./")
   "*List of regexps or functions matching sub-directory names to ignore."
@@ -443,9 +454,9 @@
 `otherframe'	Show new file in another frame
 `maybe-frame'	If a file is visible in another frame, prompt to ask if you
 		you want to see the file in the same window of the current
-  		frame or in the other frame.
+  		frame or in the other frame
 `always-frame'  If a file is visible in another frame, raise that
-		frame.  Otherwise, visit the file in the same window."
+		frame; otherwise, visit the file in the same window"
     :type '(choice (const samewindow)
 		   (const otherwindow)
 		   (const display)
@@ -456,7 +467,7 @@
 
 (defcustom ido-default-buffer-method  'always-frame
     "*How to switch to new buffer when using `ido-switch-buffer'.
-See ido-default-file-method for details."
+See `ido-default-file-method' for details."
     :type '(choice (const samewindow)
 		   (const otherwindow)
 		   (const display)
@@ -481,14 +492,27 @@
   :group 'ido)
 
 (defcustom ido-enable-prefix nil
-  "*Nil means that `ido' will match if the inserted text is an
-arbitrary substring (default). If non-nil `ido' will only match if the inserted
-text is a prefix \(this behavior is like the standard unix- or
-emacs-completion works).
+  "*Non-nil means only match if the entered text is a prefix of file name.
+This behavior is like the standard emacs-completion.
+Nil means to match if the entered text is an arbitrary substring.
 Value can be toggled within `ido' using `ido-toggle-prefix'."
   :type 'boolean
   :group 'ido)
 
+(defcustom ido-enable-dot-prefix nil
+  "*Non-nil means to match leading dot as prefix.
+I.e. hidden files and buffers will match only if you type a dot
+as first char even if `ido-enable-prefix' is nil."
+  :type 'boolean
+  :group 'ido)
+
+(defcustom ido-confirm-unique-completion nil
+  "*Non-nil means that even a unique completion must be confirmed.
+This means that \\[ido-complete] must always be followed by \\[ido-exit-minibuffer]
+even when there is only one unique completion."
+  :type 'boolean
+  :group 'ido)
+
 (defcustom ido-cannot-complete-command 'ido-completion-help
   "*Command run when `ido-complete' can't complete any more.
 The most useful values are `ido-completion-help', which pops up a
@@ -507,7 +531,7 @@
 (defcustom ido-max-prospects 12
   "*Non-zero means that the prospect list will be limited to than number of items.
 For a long list of prospects, building the full list for the minibuffer can take a
-non-negletable amount of time; setting this variable reduces that time."
+non-negligible amount of time; setting this variable reduces that time."
   :type 'integer
   :group 'ido)
 
@@ -553,6 +577,24 @@
   :group 'ido)
 
 
+(defcustom ido-use-filename-at-point nil
+  "*Non-nil means that ido shall look for a filename at point.
+May use `ffap-guesser' to guess whether text at point is a filename.
+If found, use that as the starting point for filename selection."
+  :type '(choice
+	  (const :tag "Disabled" nil)
+	  (const :tag "Guess filename" guess)
+	  (other :tag "Use literal filename" t))
+  :group 'ido)
+
+
+(defcustom ido-use-url-at-point nil
+  "*Non-nil means that ido shall look for a URL at point.
+If found, call `find-file-at-point' to visit it."
+  :type 'boolean
+  :group 'ido)
+
+
 (defcustom ido-enable-tramp-completion t
   "*Non-nil means that ido shall perform tramp method and server name completion.
 A tramp file name uses the following syntax: /method:user@host:filename."
@@ -578,7 +620,7 @@
 (defcustom ido-slow-ftp-hosts nil
   "*List of slow ftp hosts where ido prompting should not be used.
 If an ftp host is on this list, ido automatically switches to the non-ido
-equivalent function, e.g. find-file rather than ido-find-file."
+equivalent function, e.g. `find-file' rather than `ido-find-file'."
   :type '(repeat string)
   :group 'ido)
 
@@ -638,17 +680,30 @@
   :type 'integer
   :group 'ido)
 
+(defcustom ido-max-directory-size 30000
+  "*Maximum size (in bytes) for directories to use ido completion.
+If you enter a directory with a size larger than this size, ido will
+not provide the normal completion.  To show the completions, use C-a."
+  :type '(choice (const :tag "No limit" nil)
+		 (integer :tag "Size in bytes" 30000))
+  :group 'ido)
+
 (defcustom ido-rotate-file-list-default nil
   "*Non-nil means that `ido' will always rotate file list to get default in front."
   :type 'boolean
   :group 'ido)
 
-(defcustom ido-enter-single-matching-directory 'slash
-  "*Automatically enter sub-directory if it is the only matching item, if non-nil.
-If value is 'slash, only enter if typing final slash, else do it always."
+(defcustom ido-enter-matching-directory 'only
+  "*Additional methods to enter sub-directory of first/only matching item.
+If value is 'first, enter first matching sub-directory when typing a slash.
+If value is 'only, typing a slash only enters the sub-directory if it is
+the only matching item.
+If value is t, automatically enter a sub-directory when it is the only
+matching item, even without typing a slash."
   :type '(choice (const :tag "Never" nil)
-		 (const :tag "When typing /" slash)
-		 (other :tag "Always" t))
+		 (const :tag "Slash enters first directory" first)
+		 (const :tag "Slash enters first and only directory" only)
+		 (other :tag "Always enter unique directory" t))
   :group 'ido)
 
 (defcustom ido-create-new-buffer 'prompt
@@ -660,8 +715,11 @@
 		 (const never))
   :group 'ido)
 
-(defcustom ido-define-mode-map-hook  nil
-  "*Hook to define keys in `ido-mode-map' for extra keybindings."
+(defcustom ido-setup-hook  nil
+  "*Hook run after the ido variables and keymap have been setup.
+The dynamic variable `ido-cur-item' contains the current type of item that
+is read by ido, possible values are file, dir, buffer, and list.
+Additional keys can be defined in `ido-completion-map'."
   :type 'hook
   :group 'ido)
 
@@ -671,16 +729,18 @@
   :type '(choice string (const nil))
   :group 'ido)
 
-(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]")
+(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]")
   "*List of strings used by ido to display the alternatives in the minibuffer.
-There are 8 elements in this list, each is a pair of strings:
+There are 10 elements in this list:
 1st and 2nd elements are used as brackets around the prospect list,
 3rd element is the separator between prospects (ignored if ido-separator is set),
 4th element is the string inserted at the end of a truncated list of prospects,
 5th and 6th elements are used as brackets around the common match string which
 can be completed using TAB,
-7th element is the string displayed when there are a no matches, and
-8th element displayed if there is a single match (and faces are not used)."
+7th element is the string displayed when there are no matches, and
+8th element is displayed if there is a single match (and faces are not used),
+9th element is displayed when the current directory is non-readable,
+10th element is displayed when directory exceeds `ido-max-directory-size'."
   :type '(repeat string)
   :group 'ido)
 
@@ -690,23 +750,29 @@
   :type 'boolean
   :group 'ido)
 
-(defface ido-first-match-face  '((t (:bold t)))
+(defface ido-first-match  '((t (:bold t)))
   "*Font used by ido for highlighting first match."
   :group 'ido)
 
-(defface ido-only-match-face  '((((class color))
+(defface ido-only-match  '((((class color))
                                  (:foreground "ForestGreen"))
                                 (t (:italic t)))
   "*Font used by ido for highlighting only match."
   :group 'ido)
 
-(defface ido-subdir-face  '((((class color))
+(defface ido-subdir  '((((min-colors 88) (class color))
+                             (:foreground "red1"))
+			    (((class color))
                              (:foreground "red"))
                             (t (:underline t)))
   "*Font used by ido for highlighting subdirs in the alternatives."
   :group 'ido)
 
-(defface ido-indicator-face  '((((class color))
+(defface ido-indicator  '((((min-colors 88) (class color))
+				(:foreground "yellow1"
+				 :background "red1"
+				 :width condensed))
+			       (((class color))
 				(:foreground "yellow"
 				 :background "red"
 				 :width condensed))
@@ -714,6 +780,12 @@
   "*Font used by ido for highlighting its indicators."
   :group 'ido)
 
+(defface ido-incomplete-regexp
+  '((t
+     (:inherit font-lock-warning-face)))
+  "Ido face for indicating incomplete regexps."
+  :group 'ido)
+
 (defcustom ido-make-file-list-hook  nil
   "*List of functions to run when the list of matching files is created.
 Each function on the list may modify the dynamically bound variable
@@ -808,23 +880,41 @@
 (defcustom ido-read-file-name-as-directory-commands '()
   "List of commands which uses read-file-name to read a directory name.
 When `ido-everywhere' is non-nil, the commands in this list will read
-the directory using ido-read-directory-name."
+the directory using `ido-read-directory-name'."
   :type '(repeat symbol)
   :group 'ido)
 
 (defcustom ido-read-file-name-non-ido '()
   "List of commands which shall not read file names the ido way.
 When `ido-everywhere' is non-nil, the commands in this list will read
-the file name using normal read-file-name style."
+the file name using normal `read-file-name' style."
   :type '(repeat symbol)
   :group 'ido)
 
+(defcustom ido-before-fallback-functions '()
+  "List of functions to call before calling a fallback command.
+The fallback command is passed as an argument to the functions."
+  :type 'hook
+  :group 'ido)
+
 ;;; Internal Variables
 
 ;; Persistent variables
 
-(defvar ido-mode-map nil
-  "Keymap for `ido-find-file' and `ido-switch-buffer'.")
+(defvar ido-completion-map nil
+  "Currently active keymap for ido commands.")
+
+(defvar ido-common-completion-map nil
+  "Keymap for all ido commands.")
+
+(defvar ido-file-completion-map nil
+  "Keymap for ido file commands.")
+
+(defvar ido-file-dir-completion-map nil
+  "Keymap for ido file and directory commands.")
+
+(defvar ido-buffer-completion-map nil
+  "Keymap for ido buffer commands.")
 
 (defvar  ido-file-history nil
   "History of files selected using `ido-find-file'.")
@@ -839,7 +929,7 @@
 (defvar ido-work-directory-list nil
   "List of actual working directory names.
 The current directory is inserted at the front of this list whenever a
-file is opened with ido-find-file and family.")
+file is opened with `ido-find-file' and family.")
 
 (defvar ido-work-file-list nil
   "List of actual work file names.
@@ -853,7 +943,7 @@
 
 (defvar ido-ignore-item-temp-list nil
   "List of items to ignore in current ido invocation.
-Intended to be let-bound by functions which calls ido repeatedly.
+Intended to be let-bound by functions which call ido repeatedly.
 Should never be set permanently.")
 
 ;; Temporary storage
@@ -878,6 +968,9 @@
 (defvar ido-text-init nil
   "The initial string for the users string it is typed in.")
 
+(defvar ido-input-stack nil
+  "Stores the users strings when user hits M-b/M-f.")
+
 (defvar ido-matches nil
   "List of files currently matching `ido-text'.")
 
@@ -890,7 +983,7 @@
 selected.")
 
 (defvar ido-current-directory nil
-  "Current directory for ido-find-file.")
+  "Current directory for `ido-find-file'.")
 
 (defvar ido-auto-merge-timer nil
   "Delay timer for auto merge.")
@@ -900,11 +993,13 @@
 Is set by ido functions to the current minibuffer-depth, so that
 it doesn't interfere with other minibuffer usage.")
 
+(defvar ido-incomplete-regexp nil
+  "Non-nil if an incomplete regexp is entered.")
 
 ;;; Variables with dynamic bindings.
 ;;; Declared here to keep the byte compiler quiet.
 
-;; Stores the current ido item type ('file, 'dir or 'buffer).
+;; Stores the current ido item type ('file, 'dir, 'buffer, or 'list).
 (defvar ido-cur-item)
 
 ;; Stores the current list of items that will be searched through.
@@ -913,10 +1008,19 @@
 ;; at the end of the list.  Created by `ido-make-item-list'.
 (defvar ido-cur-list)
 
+;; Stores the choice list for ido-completing-read
+(defvar ido-choice-list)
+
 ;; Stores the list of items which are ignored when building
 ;; `ido-cur-list'.  It is in no specific order.
 (defvar ido-ignored-list)
 
+;; Remember if current directory is non-readable (so we cannot do completion).
+(defvar ido-directory-nonreadable)
+
+;; Remember if current directory is 'huge' (so we don't want to do completion).
+(defvar ido-directory-too-big)
+
 ;; Keep current item list if non-nil.
 (defvar ido-keep-item-list)
 
@@ -954,12 +1058,14 @@
 ;; Value is a list (ido-text dir cur-list ignored-list matches).
 (defvar ido-pre-merge-state)
 
-;; Original value of vc-master-templates for use in ido-toggle-vc.
-(defvar ido-saved-vc-mt)
+;; Original value of vc-handled-backends for use in ido-toggle-vc.
+(defvar ido-saved-vc-hb)
 
 ;; Stores temporary state of literal find file.
 (defvar ido-find-literal)
 
+;; Set to 'ignore to inhibit switching between find-file/switch-buffer.
+(defvar ido-context-switch-command)
 
 ;;; FUNCTIONS
 
@@ -993,9 +1099,9 @@
 	  (setq truncate-lines t)))))
 
 (defun ido-is-tramp-root (&optional dir)
-  (setq dir (or dir ido-current-directory))
   (and ido-enable-tramp-completion
-       (string-match "\\`/[^/][^/]+:\\([^/:@]+@\\)?\\'" dir)))
+       (string-match "\\`/[^/]+[@:]\\'"
+		     (or dir ido-current-directory))))
 
 (defun ido-is-root-directory (&optional dir)
   (setq dir (or dir ido-current-directory))
@@ -1045,6 +1151,8 @@
 (defun ido-may-cache-directory (&optional dir)
   (setq dir (or dir ido-current-directory))
   (cond
+   ((ido-directory-too-big-p dir)
+    nil)
    ((and (ido-is-root-directory dir)
 	 (or ido-enable-tramp-completion
 	     (memq system-type '(windows-nt ms-dos))))
@@ -1208,8 +1316,7 @@
 	  (while e
 	    (setq d (car e) e (cdr e))
 	    (if (not (consp d))
-		(set-text-properties 0 (length d) nil d))))))
-)
+		(set-text-properties 0 (length d) nil d)))))))
 
 
 (defun ido-kill-emacs-hook ()
@@ -1219,15 +1326,14 @@
 (defvar ido-minor-mode-map-entry nil)
 
 ;;;###autoload
-(defun ido-mode (&optional arg nobind)
+(defun ido-mode (&optional arg)
   "Toggle ido speed-ups on or off.
 With ARG, turn ido speed-up on if arg is positive, off otherwise.
-If second argument NOBIND is non-nil, no keys are rebound; otherwise,
-turning on ido-mode will modify the default keybindings for the
-find-file and switch-to-buffer families of commands to the ido
-versions of these functions.
-However, if second arg equals 'files, bind only for files, or if it
-equals 'buffers, bind only for buffers.
+Turning on ido-mode will remap (via a minor-mode keymap) the default
+keybindings for the `find-file' and `switch-to-buffer' families of
+commands to the ido versions of these functions.
+However, if ARG arg equals 'files, remap only commands for files, or
+if it equals 'buffers, remap only commands for buffer switching.
 This function also adds a hook to the minibuffer."
   (interactive "P")
   (setq ido-mode
@@ -1241,6 +1347,8 @@
 	 (t nil)))
 
   (ido-everywhere (if ido-everywhere 1 -1))
+  (when ido-mode
+    (ido-init-completion-maps))
 
   (when ido-mode
     (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
@@ -1249,11 +1357,7 @@
 
     (add-hook 'kill-emacs-hook 'ido-kill-emacs-hook)
 
-    (unless ido-minor-mode-map-entry
-      (setq ido-minor-mode-map-entry (cons 'ido-mode (make-sparse-keymap)))
-      (add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry))
-
-    (let ((map (cdr ido-minor-mode-map-entry)))
+    (let ((map (make-sparse-keymap)))
       (when (memq ido-mode '(file both))
 	(define-key map [remap find-file] 'ido-find-file)
 	(define-key map [remap find-file-read-only] 'ido-find-file-read-only)
@@ -1273,29 +1377,42 @@
 	(define-key map [remap switch-to-buffer-other-frame] 'ido-switch-buffer-other-frame)
 	(define-key map [remap insert-buffer] 'ido-insert-buffer)
 	(define-key map [remap kill-buffer] 'ido-kill-buffer)
-	(define-key map [remap display-buffer] 'ido-display-buffer)))))
+	(define-key map [remap display-buffer] 'ido-display-buffer))
+
+      (if ido-minor-mode-map-entry
+	  (setcdr ido-minor-mode-map-entry map)
+	(setq ido-minor-mode-map-entry (cons 'ido-mode map))
+	(add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry)))))
+
 
 (defun ido-everywhere (arg)
-  "Enable ido everywhere file and directory names are read."
+  "Toggle using ido speed-ups everywhere file and directory names are read.
+With ARG, turn ido speed-up on if arg is positive, off otherwise."
   (interactive "P")
   (setq ido-everywhere (if arg
 			   (> (prefix-numeric-value arg) 0)
 			 (not ido-everywhere)))
-  (setq read-file-name-function
-	(and ido-everywhere (memq ido-mode '(both file))
-	     'ido-read-file-name))
-  (setq read-buffer-function
-	(and ido-everywhere (memq ido-mode '(both buffer))
-	     'ido-read-buffer)))
+  (when (get 'ido-everywhere 'file)
+    (setq read-file-name-function (car (get 'ido-everywhere 'file)))
+    (put 'ido-everywhere 'file nil))
+  (when (get 'ido-everywhere 'buffer)
+    (setq read-buffer-function (car (get 'ido-everywhere 'buffer)))
+    (put 'ido-everywhere 'buffer nil))
+  (when ido-everywhere
+    (when (memq ido-mode '(both file))
+      (put 'ido-everywhere 'file (cons read-file-name-function nil))
+      (setq read-file-name-function 'ido-read-file-name))
+    (when (memq ido-mode '(both buffer))
+      (put 'ido-everywhere 'buffer (cons read-buffer-function nil))
+      (setq read-buffer-function 'ido-read-buffer))))
 
 
 ;;; IDO KEYMAP
-(defun ido-define-mode-map ()
-  "Set up the keymap for `ido'."
-  (let (map)
-    ;; generated every time so that it can inherit new functions.
-
-    (setq map (copy-keymap minibuffer-local-map))
+(defun ido-init-completion-maps ()
+  "Set up the completion keymaps used by `ido'."
+
+  ;; Common map
+  (let ((map (make-sparse-keymap)))
     (define-key map "\C-a" 'ido-toggle-ignore)
     (define-key map "\C-c" 'ido-toggle-case)
     (define-key map "\C-e" 'ido-edit-input)
@@ -1308,59 +1425,97 @@
     (define-key map "\C-s" 'ido-next-match)
     (define-key map "\C-t" 'ido-toggle-regexp)
     (define-key map "\C-z" 'ido-undo-merge-work-directory)
-    (define-key map [(control ? )] 'ido-restrict-to-matches)
+    (define-key map [(control ?\s)] 'ido-restrict-to-matches)
     (define-key map [(control ?@)] 'ido-restrict-to-matches)
     (define-key map [right] 'ido-next-match)
     (define-key map [left] 'ido-prev-match)
     (define-key map "?" 'ido-completion-help)
-
-    (when (memq ido-cur-item '(file dir))
-      (define-key map "\C-b" 'ido-enter-switch-buffer)
-      (define-key map "\C-d" 'ido-enter-dired)
-      (define-key map "\C-f" 'ido-fallback-command)
-      (define-key map [down] 'ido-next-match-dir)
-      (define-key map [up]   'ido-prev-match-dir)
-      (define-key map [(meta up)] 'ido-prev-work-directory)
-      (define-key map [(meta down)] 'ido-next-work-directory)
-      (define-key map [backspace] 'ido-delete-backward-updir)
-      (define-key map "\d"        'ido-delete-backward-updir)
-      (define-key map [(meta backspace)] 'ido-delete-backward-word-updir)
-      (define-key map [(control backspace)] 'ido-up-directory)
-      (define-key map [(meta ?b)] 'ido-next-work-file)
-      (define-key map [(meta ?d)] 'ido-wide-find-dir)
-      (define-key map [(meta ?f)] 'ido-wide-find-file)
-      (define-key map [(meta ?k)] 'ido-forget-work-directory)
-      (define-key map [(meta ?m)] 'ido-make-directory)
-      (define-key map [(meta ?n)] 'ido-next-work-directory)
-      (define-key map [(meta ?o)] 'ido-prev-work-file)
-      (define-key map [(meta ?p)] 'ido-prev-work-directory)
-      (define-key map [(meta ?s)] 'ido-merge-work-directories)
-      )
-
-    (when (eq ido-cur-item 'file)
-      (define-key map "\C-k" 'ido-delete-file-at-head)
-      (define-key map "\C-o" 'ido-copy-current-word)
-      (define-key map "\C-l" 'ido-reread-directory)
-      (define-key map "\C-w" 'ido-copy-current-file-name)
-      (define-key map [(meta ?l)] 'ido-toggle-literal)
-      (define-key map "\C-v" 'ido-toggle-vc)
-      )
-
-    (when (eq ido-cur-item 'buffer)
-      (define-key map "\C-b" 'ido-fallback-command)
-      (define-key map "\C-f" 'ido-enter-find-file)
-      (define-key map "\C-k" 'ido-kill-buffer-at-head)
-      )
-
-    (when (if (boundp 'viper-mode) viper-mode)
-      (define-key map [remap viper-intercept-ESC-key] 'ignore)
-      (when (memq ido-cur-item '(file dir))
+    ;; Magic commands.
+    (define-key map "\C-b" 'ido-magic-backward-char)
+    (define-key map "\C-f" 'ido-magic-forward-char)
+    (define-key map "\C-d" 'ido-magic-delete-char)
+    (set-keymap-parent map minibuffer-local-map)
+    (setq ido-common-completion-map map))
+
+  ;; File and directory map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-x\C-b" 'ido-enter-switch-buffer)
+    (define-key map "\C-x\C-f" 'ido-fallback-command)
+    (define-key map "\C-x\C-d" 'ido-enter-dired)
+    (define-key map [down] 'ido-next-match-dir)
+    (define-key map [up]   'ido-prev-match-dir)
+    (define-key map [(meta up)] 'ido-prev-work-directory)
+    (define-key map [(meta down)] 'ido-next-work-directory)
+    (define-key map [backspace] 'ido-delete-backward-updir)
+    (define-key map "\d"        'ido-delete-backward-updir)
+    (define-key map [(meta backspace)] 'ido-delete-backward-word-updir)
+    (define-key map [(control backspace)] 'ido-up-directory)
+    (define-key map "\C-l" 'ido-reread-directory)
+    (define-key map [(meta ?d)] 'ido-wide-find-dir-or-delete-dir)
+    (define-key map [(meta ?b)] 'ido-push-dir)
+    (define-key map [(meta ?f)] 'ido-wide-find-file-or-pop-dir)
+    (define-key map [(meta ?k)] 'ido-forget-work-directory)
+    (define-key map [(meta ?m)] 'ido-make-directory)
+    (define-key map [(meta ?n)] 'ido-next-work-directory)
+    (define-key map [(meta ?o)] 'ido-prev-work-file)
+    (define-key map [(meta control ?o)] 'ido-next-work-file)
+    (define-key map [(meta ?p)] 'ido-prev-work-directory)
+    (define-key map [(meta ?s)] 'ido-merge-work-directories)
+    (set-keymap-parent map ido-common-completion-map)
+    (setq ido-file-dir-completion-map map))
+
+  ;; File only map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-k" 'ido-delete-file-at-head)
+    (define-key map "\C-o" 'ido-copy-current-word)
+    (define-key map "\C-w" 'ido-copy-current-file-name)
+    (define-key map [(meta ?l)] 'ido-toggle-literal)
+    (define-key map "\C-v" 'ido-toggle-vc)
+    (set-keymap-parent map ido-file-dir-completion-map)
+    (setq ido-file-completion-map map))
+
+  ;; Buffer map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-x\C-f" 'ido-enter-find-file)
+    (define-key map "\C-x\C-b" 'ido-fallback-command)
+    (define-key map "\C-k" 'ido-kill-buffer-at-head)
+    (set-keymap-parent map ido-common-completion-map)
+    (setq ido-buffer-completion-map map)))
+
+
+(defun ido-setup-completion-map ()
+  "Set up the keymap for `ido'."
+
+  ;; generated every time so that it can inherit new functions.
+  (let ((map (make-sparse-keymap))
+	(viper-p (if (boundp 'viper-mode) viper-mode)))
+
+    (when viper-p
+      (define-key map [remap viper-intercept-ESC-key] 'ignore))
+
+    (cond
+     ((memq ido-cur-item '(file dir))
+      (when ido-context-switch-command
+	(define-key map "\C-x\C-b" ido-context-switch-command)
+	(define-key map "\C-x\C-d" 'ignore))
+      (when viper-p
 	(define-key map [remap viper-backward-char] 'ido-delete-backward-updir)
 	(define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir)
-	(define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir)))
-
-    (setq ido-mode-map map)
-    (run-hooks 'ido-define-mode-map-hook)))
+	(define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir))
+      (set-keymap-parent map
+			 (if (eq ido-cur-item 'file)
+			     ido-file-completion-map
+			   ido-file-dir-completion-map)))
+
+     ((eq ido-cur-item 'buffer)
+      (when ido-context-switch-command
+	(define-key map "\C-x\C-f" ido-context-switch-command))
+      (set-keymap-parent map ido-buffer-completion-map))
+
+     (t
+      (set-keymap-parent map ido-common-completion-map)))
+
+    (setq ido-completion-map map)))
 
 (defun ido-final-slash (dir &optional fix-it)
   ;; return DIR if DIR has final slash.
@@ -1373,19 +1528,53 @@
    (fix-it (concat dir "/"))
    (t nil)))
 
+(defun ido-no-final-slash (s)
+  ;; Remove optional final slash from string S
+  (let ((l (1- (length s))))
+    (if (and (> l 0) (eq (aref s l) ?/))
+	(substring s 0 l)
+      s)))
+
+(defun ido-nonreadable-directory-p (dir)
+  ;; Return t if dir is a directory, but not readable
+  ;; Do not check for non-readable directories via tramp, as this causes a premature
+  ;; connect on incomplete tramp paths (after entring just method:).
+  (let ((ido-enable-tramp-completion nil))
+    (and (ido-final-slash dir)
+	 (file-directory-p dir)
+	 (not (file-readable-p dir)))))
+
+(defun ido-directory-too-big-p (dir)
+  ;; Return t if dir is a directory, but too big to show
+  ;; Do not check for non-readable directories via tramp, as this causes a premature
+  ;; connect on incomplete tramp paths (after entring just method:).
+  (let ((ido-enable-tramp-completion nil))
+    (and (numberp ido-max-directory-size)
+	 (ido-final-slash dir)
+	 (file-directory-p dir)
+	 (> (nth 7 (file-attributes dir)) ido-max-directory-size))))
+
 (defun ido-set-current-directory (dir &optional subdir no-merge)
   ;; Set ido's current directory to DIR or DIR/SUBDIR
-  (setq dir (ido-final-slash dir t))
+  (unless (and ido-enable-tramp-completion
+	       (string-match "\\`/[^/]*@\\'" dir))
+    (setq dir (ido-final-slash dir t)))
   (setq ido-use-merged-list nil
 	ido-try-merged-list (not no-merge))
-  (if subdir
-      (setq dir (ido-final-slash (concat dir subdir) t)))
+  (when subdir
+    (setq dir (concat dir subdir))
+    (unless (and ido-enable-tramp-completion
+		 (string-match "\\`/[^/]*@\\'" dir))
+      (setq dir (ido-final-slash dir t))))
   (if (equal dir ido-current-directory)
       nil
     (ido-trace "cd" dir)
     (setq ido-current-directory dir)
     (if (get-buffer ido-completion-buffer)
 	(kill-buffer ido-completion-buffer))
+    (setq ido-directory-nonreadable (ido-nonreadable-directory-p dir))
+    (setq ido-directory-too-big (and (not ido-directory-nonreadable)
+				     (ido-directory-too-big-p dir)))
     t))
 
 (defun ido-set-current-home (&optional dir)
@@ -1409,7 +1598,7 @@
 			 (floor (* (frame-width) ido-max-file-prompt-width))
 		       ido-max-file-prompt-width))
 	  (literal (and (boundp 'ido-find-literal) ido-find-literal "(literal) "))
-	  (vc-off (and ido-saved-vc-mt (not vc-master-templates) "[-VC] "))
+	  (vc-off (and ido-saved-vc-hb (not vc-handled-backends) "[-VC] "))
 	  (prefix nil)
 	  (rule ido-rewrite-file-prompt-rules))
       (let ((case-fold-search nil))
@@ -1498,8 +1687,12 @@
        (ido-enable-regexp ido-enable-regexp)
        )
 
-    (ido-define-mode-map)
+    (ido-setup-completion-map)
     (setq ido-text-init initial)
+    (setq ido-input-stack nil)
+
+    (run-hooks 'ido-setup-hook)
+
     (while (not done)
       (ido-trace "\n_LOOP_" ido-text-init)
       (setq ido-exit nil)
@@ -1530,6 +1723,7 @@
 		(l (ido-make-merged-file-list ido-text-init
 					      (eq ido-use-merged-list 'auto)
 					      (eq ido-try-merged-list 'wide))))
+	    (ido-trace "merged" l)
 	    (cond
 	     ((not l)
 	      (if (eq ido-try-merged-list 'wide)
@@ -1549,6 +1743,9 @@
 		      ido-use-merged-list nil)))
 	     ((eq l t)
 	      (setq ido-use-merged-list nil))
+	     ((eq l 'input-pending-p)
+	      (setq ido-try-merged-list t
+		    ido-use-merged-list nil))
 	     (t
 	      (setq ido-pre-merge-state
 		    (list ido-text-init ido-current-directory olist oign omat))
@@ -1570,13 +1767,20 @@
 	      ido-rescan nil))
        ((eq ido-cur-item 'file)
 	(setq ido-ignored-list nil
-	      ido-cur-list (ido-make-file-list ido-default-item)))
+	      ido-cur-list (and (not ido-directory-nonreadable)
+				(not ido-directory-too-big)
+				(ido-make-file-list ido-default-item))))
        ((eq ido-cur-item 'dir)
 	(setq ido-ignored-list nil
-	      ido-cur-list (ido-make-dir-list ido-default-item)))
+	      ido-cur-list (and (not ido-directory-nonreadable)
+				(not ido-directory-too-big)
+				(ido-make-dir-list ido-default-item))))
        ((eq ido-cur-item 'buffer)
 	(setq ido-ignored-list nil
 	      ido-cur-list (ido-make-buffer-list ido-default-item)))
+       ((eq ido-cur-item 'list)
+	(setq ido-ignored-list nil
+	      ido-cur-list (ido-make-choice-list ido-default-item)))
        (t nil))
       (setq ido-rotate-temp nil)
 
@@ -1588,7 +1792,8 @@
       (if (and ido-matches (eq ido-try-merged-list 'auto))
 	  (setq ido-try-merged-list t))
       (let
-	  ((minibuffer-local-completion-map ido-mode-map)
+	  ((minibuffer-local-completion-map ido-completion-map)
+	   (minibuffer-local-filename-completion-map ido-completion-map)
 	   (max-mini-window-height (or ido-max-window-height
 				       (and (boundp 'max-mini-window-height) max-mini-window-height)))
 	   (ido-completing-read t)
@@ -1626,8 +1831,7 @@
        ((memq ido-exit '(edit chdir))
 	(cond
 	 ((memq ido-cur-item '(file dir))
-	  (let* ((process-environment (cons "HOME=/" process-environment)) ;; cheat read-file-name
-		 (read-file-name-function nil)
+	  (let* ((read-file-name-function nil)
 		 (edit (eq ido-exit 'edit))
 		 (d ido-current-directory)
 		 (f ido-text-init)
@@ -1635,7 +1839,11 @@
 	    (setq ido-text-init "")
 	    (while new
 	      (setq new (if edit
-			     (read-file-name (concat prompt "[EDIT] ") d (concat d f) nil f)
+			    (condition-case nil
+				(read-file-name (concat prompt "[EDIT] ")
+						(expand-file-name d)
+						(concat d f) nil f)
+			      (quit (concat d f)))
 			   f)
 		    d (or (file-name-directory new) "/")
 		    f (file-name-nondirectory new)
@@ -1654,16 +1862,20 @@
 		    (setq ido-text-init f
 			  new nil))))))
 	 (t
-	  (setq ido-text-init (read-string (concat prompt "[EDIT] ") ido-final-text))))
+	  (setq ido-text-init
+		(condition-case nil
+		    (read-string (concat prompt "[EDIT] ") ido-final-text)
+		  (quit ido-final-text)))))
+
 	nil)
 
        ((eq ido-exit 'keep)
 	(setq ido-keep-item-list t))
 
-       ((memq ido-exit '(dired fallback findfile findbuffer))
+       ((memq ido-exit '(dired fallback find-file switch-to-buffer insert-buffer insert-file))
 	(setq done t))
 
-       ((eq ido-exit 'updir)
+       ((memq ido-exit '(updir push))
 	;; cannot go up if already at the root-dir (Unix) or at the
 	;; root-dir of a certain drive (Windows or MS-DOS).
         (if (ido-is-tramp-root)
@@ -1672,11 +1884,36 @@
 	      (ido-set-current-directory (match-string 1 ido-current-directory))
 	      (setq ido-set-default-item t))
 	  (unless (ido-is-root-directory)
+	    (when (eq ido-exit 'push)
+	      (setq ido-input-stack (cons (cons ido-cur-item ido-text) ido-input-stack))
+	      (setq ido-cur-item 'dir)
+	      (setq ido-text-init (file-name-nondirectory (substring ido-current-directory 0 -1)))
+	      (ido-trace "push" ido-input-stack))
 	    (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1)))
 	    (setq ido-set-default-item t))))
 
+       ((eq ido-exit 'pop)
+	(ido-trace "pop" ido-input-stack)
+	(let ((elt (car ido-input-stack)))
+	  (setq ido-input-stack (cdr ido-input-stack))
+	  (ido-set-current-directory (concat ido-current-directory ido-text))
+	  (setq ido-cur-item (car elt))
+	  (setq ido-text-init (cdr elt))))
+
+       ((eq ido-exit 'pop-all)
+	(ido-trace "pop-all" ido-input-stack)
+	(while ido-input-stack
+	  (let ((elt (car ido-input-stack)))
+	    (setq ido-input-stack (cdr ido-input-stack))
+	    (ido-set-current-directory (concat ido-current-directory ido-text))
+	    (setq ido-cur-item (car elt))
+	    (setq ido-text-init (cdr elt)))))
+
        ;; Handling the require-match must be done in a better way.
-       ((and require-match (not (ido-existing-item-p)))
+       ((and require-match
+	     (not (if ido-directory-too-big
+		      (file-exists-p (concat ido-current-directory ido-final-text))
+		    (ido-existing-item-p))))
 	(error "must specify valid item"))
 
        (t
@@ -1688,7 +1925,7 @@
 		(ido-name (car ido-matches))))
 
 	(cond
-	 ((eq item 'buffer)
+	 ((memq item '(buffer list))
 	  (setq done t))
 
 	 ((string-equal "./" ido-selected)
@@ -1726,7 +1963,14 @@
 		  (setq ido-last-directory-list
 			(cons (cons ido-current-directory ido-selected) ido-last-directory-list)))))
 	  (ido-set-current-directory ido-current-directory ido-selected)
-	  (setq ido-set-default-item t))
+	  (if ido-input-stack
+	      (while ido-input-stack
+		(let ((elt (car ido-input-stack)))
+		  (if (setq ido-input-stack (cdr ido-input-stack))
+		      (ido-set-current-directory ido-current-directory (cdr elt))
+		    (setq ido-text-init (cdr elt)))
+		  (setq ido-cur-item (car elt))))
+	    (setq ido-set-default-item t)))
 
 	 (t
 	  (setq done t))))))
@@ -1740,21 +1984,33 @@
   (exit-minibuffer))
 
 ;;; MAIN FUNCTIONS
-(defun ido-buffer-internal (method &optional fallback prompt default initial)
+(defun ido-buffer-internal (method &optional fallback prompt default initial switch-cmd)
   ;; Internal function for ido-switch-buffer and friends
   (if (not ido-mode)
-      (call-interactively (or fallback 'switch-to-buffer))
-    (let ((buf (ido-read-buffer (or prompt "Buffer: ") default nil initial)))
+      (progn
+	(run-hook-with-args 'ido-before-fallback-functions
+			    (or fallback 'switch-to-buffer))
+	(call-interactively (or fallback 'switch-to-buffer)))
+    (let* ((ido-context-switch-command switch-cmd)
+	   (ido-current-directory nil)
+	   (ido-directory-nonreadable nil)
+	   (ido-directory-too-big nil)
+	   (buf (ido-read-internal 'buffer (or prompt "Buffer: ") 'ido-buffer-history default nil initial)))
 
       ;; Choose the buffer name: either the text typed in, or the head
       ;; of the list of matches
 
       (cond
-       ((eq ido-exit 'findfile)
+       ((eq ido-exit 'find-file)
 	(ido-file-internal ido-default-file-method nil nil nil nil ido-text))
 
+       ((eq ido-exit 'insert-file)
+	(ido-file-internal 'insert 'insert-file nil "Insert file: " nil ido-text 'ido-enter-insert-buffer))
+
        ((eq ido-exit 'fallback)
 	(let ((read-buffer-function nil))
+	  (run-hook-with-args 'ido-before-fallback-functions
+			      (or fallback 'switch-to-buffer))
 	  (call-interactively (or fallback 'switch-to-buffer))))
 
        ;; Check buf is non-nil.
@@ -1766,7 +2022,9 @@
 	(if (eq method 'insert)
 	    (progn
 	      (ido-record-command 'insert-buffer buf)
-	      (insert-buffer buf))
+	      (with-no-warnings
+		;; we really want to run insert-buffer here
+		(insert-buffer buf)))
 	  (ido-visit-buffer buf method t)))
 
        ;; buffer doesn't exist
@@ -1784,17 +2042,6 @@
 	    (set-buffer-major-mode buf))
 	(ido-visit-buffer buf method t))))))
 
-;;;###autoload
-(defun ido-read-buffer (prompt &optional default require-match initial)
-  "Replacement for the built-in `read-buffer'.
-Return the name of a buffer selected.
-PROMPT is the prompt to give to the user.  DEFAULT if given is the default
-buffer to be selected, which will go to the front of the list.
-If REQUIRE-MATCH is non-nil, an existing-buffer must be selected.
-If INITIAL is non-nil, it specifies the initial input string."
-  (let ((ido-current-directory nil))
-    (ido-read-internal 'buffer prompt 'ido-buffer-history default require-match initial)))
-
 (defun ido-record-work-directory (&optional dir)
   (when (and (numberp ido-max-work-directory-list) (> ido-max-work-directory-list 0))
     (if (and (setq dir (or dir ido-current-directory)) (> (length dir) 0))
@@ -1831,24 +2078,63 @@
     (if (> (length ido-work-file-list) ido-max-work-file-list)
 	(setcdr (nthcdr (1- ido-max-work-file-list) ido-work-file-list) nil))))
 
-(defun ido-file-internal (method &optional fallback default prompt item initial)
+(defun ido-expand-directory (dir)
+  ;; Expand DIR or use DEFAULT-DIRECTORY if nil.
+  ;; Add final slash to result in case it was missing from DEFAULT-DIRECTORY.
+  (ido-final-slash (expand-file-name (or dir default-directory)) t))
+
+(defun ido-file-internal (method &optional fallback default prompt item initial switch-cmd)
   ;; Internal function for ido-find-file and friends
-  (let ((ido-current-directory (expand-file-name (or default default-directory)))
+  (unless item
+    (setq item 'file))
+  (let ((ido-current-directory (ido-expand-directory default))
+	(ido-context-switch-command switch-cmd)
+	ido-directory-nonreadable ido-directory-too-big
+	(minibuffer-completing-file-name t)
 	filename)
 
     (if (or (not ido-mode) (ido-is-slow-ftp-host))
 	(setq filename t
-	      ido-exit 'fallback))
-
-    (let (ido-saved-vc-mt
-	  (vc-master-templates (and (boundp 'vc-master-templates) vc-master-templates))
+	      ido-exit 'fallback)
+      (setq ido-directory-nonreadable
+	    (ido-nonreadable-directory-p ido-current-directory)
+	    ido-directory-too-big
+	    (and (not ido-directory-nonreadable)
+		 (ido-directory-too-big-p ido-current-directory))))
+
+    (when (and (eq item 'file)
+	   (or ido-use-url-at-point ido-use-filename-at-point))
+      (let (fn d)
+	(require 'ffap)
+	;; Duplicate code from ffap-guesser as we want different behaviour for files and URLs.
+	(cond
+	 ((with-no-warnings
+	    (and ido-use-url-at-point
+		 ffap-url-regexp
+		 (ffap-fixup-url (or (ffap-url-at-point)
+				     (ffap-gopher-at-point)))))
+	  (setq ido-exit 'ffap
+		filename t))
+
+	 ((and ido-use-filename-at-point
+	       (setq fn (if (eq ido-use-filename-at-point 'guess)
+			    (with-no-warnings (ffap-guesser))
+			  (ffap-string-at-point)))
+	       (not (string-match "^http:/" fn))
+	       (setq d (file-name-directory fn))
+	       (file-directory-p d))
+	  (setq ido-current-directory d)
+	  (setq initial (file-name-nondirectory fn))))))
+
+    (let (ido-saved-vc-hb
+	  (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends))
 	  (ido-work-directory-index -1)
 	  (ido-work-file-index -1)
        	  (ido-find-literal nil))
 
       (unless filename
-	(setq ido-saved-vc-mt vc-master-templates)
-	(setq filename (ido-read-internal (or item 'file)
+	(setq ido-saved-vc-hb vc-handled-backends)
+	(setq filename (ido-read-internal item
 					  (or prompt "Find file: ")
 					  'ido-file-history nil nil initial)))
 
@@ -1861,14 +2147,22 @@
 	;; we don't want to change directory of current buffer.
 	(let ((default-directory ido-current-directory)
 	      (read-file-name-function nil))
+	  (run-hook-with-args 'ido-before-fallback-functions
+			      (or fallback 'find-file))
 	  (call-interactively (or fallback 'find-file))))
 
-       ((eq ido-exit 'findbuffer)
+       ((eq ido-exit 'switch-to-buffer)
 	(ido-buffer-internal ido-default-buffer-method nil nil nil ido-text))
 
+       ((eq ido-exit 'insert-buffer)
+	(ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil ido-text 'ido-enter-insert-file))
+
        ((eq ido-exit 'dired)
 	(dired (concat ido-current-directory (or ido-text ""))))
 
+       ((eq ido-exit 'ffap)
+	(find-file-at-point))
+
        ((eq method 'alt-file)
 	(ido-record-work-file filename)
 	(setq default-directory ido-current-directory)
@@ -1892,13 +2186,14 @@
 	      (ido-record-work-directory)
 	      (funcall method ido-current-directory)
 	      (if (eq method 'dired)
-		  (dired-goto-file (expand-file-name file))))
+		  (with-no-warnings
+		    (dired-goto-file (expand-file-name file)))))
 	     ((string-match "[[*?]" filename)
 	      (setq dirname (concat ido-current-directory filename))
 	      (ido-record-command method dirname)
 	      (ido-record-work-directory)
 	      (funcall method dirname))
-	     ((y-or-n-p (format "Directory %s does not exist. Create it " filename))
+	     ((y-or-n-p (format "Directory %s does not exist. Create it? " filename))
 	      (ido-record-command method dirname)
 	      (ido-record-work-directory dirname)
 	      (make-directory-internal dirname)
@@ -1920,6 +2215,7 @@
 	(setq filename (concat ido-current-directory filename))
 	(ido-record-command fallback filename)
 	(ido-record-work-directory)
+	(run-hook-with-args 'ido-before-fallback-functions fallback)
 	(funcall fallback filename))
 
        ((eq method 'insert)
@@ -1964,6 +2260,9 @@
   (interactive)
   (let (res)
     (cond
+     (ido-incomplete-regexp
+      ;; Do nothing
+      )
      ((and (memq ido-cur-item '(file dir))
 	   (string-match "[$]" ido-text))
       (let ((evar (substitute-in-file-name (concat ido-current-directory ido-text))))
@@ -1979,6 +2278,12 @@
 	  (setq ido-exit 'refresh)
 	  (exit-minibuffer))))
 
+     (ido-directory-too-big
+      (setq ido-directory-too-big nil)
+      (setq ido-text-init ido-text)
+      (setq ido-exit 'refresh)
+      (exit-minibuffer))
+
      ((not ido-matches)
       (when ido-completion-buffer
 	(call-interactively (setq this-command ido-cannot-complete-command))))
@@ -1988,7 +2293,11 @@
 		     (string-equal ido-current-directory "/")
 		     (string-match "..[@:]\\'" (car ido-matches)))))
       ;; only one choice, so select it.
-      (exit-minibuffer))
+      (if (not ido-confirm-unique-completion)
+	  (exit-minibuffer)
+	(setq ido-rescan (not ido-enable-prefix))
+	(delete-region (minibuffer-prompt-end) (point))
+	(insert (car ido-matches))))
 
      (t ;; else there could be some completions
       (setq res ido-common-match-string)
@@ -2052,6 +2361,62 @@
    ((not ido-use-merged-list)
     (ido-merge-work-directories))))
 
+;;; Magic C-f
+
+(defun ido-magic-forward-char ()
+  "Move forward in user input or perform magic action.
+If no user input is present, or at end of input, perform magic actions:
+C-x C-b ... C-f  switch to ido-find-file.
+C-x C-f ... C-f  fallback to non-ido find-file.
+C-x C-d ... C-f  fallback to non-ido brief dired.
+C-x d ... C-f    fallback to non-ido dired."
+  (interactive)
+  (cond
+   ((not (eobp))
+    (forward-char 1))
+   ((memq ido-cur-item '(file dir))
+    (ido-fallback-command))
+   (ido-context-switch-command
+    (call-interactively ido-context-switch-command))
+   ((eq ido-cur-item 'buffer)
+    (ido-enter-find-file))))
+
+;;; Magic C-b
+
+(defun ido-magic-backward-char ()
+  "Move backward in user input or perform magic action.
+If no user input is present, or at start of input, perform magic actions:
+C-x C-f C-b  switch to ido-switch-buffer.
+C-x C-d C-b  switch to ido-switch-buffer.
+C-x d C-b    switch to ido-switch-buffer.
+C-x C-b C-b  fallback to non-ido switch-to-buffer."
+  (interactive)
+  (cond
+   ((> (point) (minibuffer-prompt-end))
+    (forward-char -1))
+   ((eq ido-cur-item 'buffer)
+    (ido-fallback-command))
+   (ido-context-switch-command
+    (call-interactively ido-context-switch-command))
+   (t
+    (ido-enter-switch-buffer))))
+
+;;; Magic C-d
+
+(defun ido-magic-delete-char ()
+  "Delete following char in user input or perform magic action.
+If at end of user input, perform magic actions:
+C-x C-f ... C-d  enter dired on current directory."
+  (interactive)
+  (cond
+   ((not (eobp))
+    (delete-char 1))
+   (ido-context-switch-command
+    nil)
+   ((memq ido-cur-item '(file dir))
+    (ido-enter-dired))))
+
+
 ;;; TOGGLE FUNCTIONS
 
 (defun ido-toggle-case ()
@@ -2078,7 +2443,9 @@
 (defun ido-toggle-ignore ()
   "Toggle ignoring files specified with `ido-ignore-files'."
   (interactive)
-  (setq ido-process-ignore-lists (not ido-process-ignore-lists))
+  (if ido-directory-too-big
+      (setq ido-directory-too-big nil)
+    (setq ido-process-ignore-lists (not ido-process-ignore-lists)))
   (setq ido-text-init ido-text)
   (setq ido-exit 'refresh)
   (exit-minibuffer))
@@ -2088,8 +2455,8 @@
   (interactive)
   (if (and ido-mode (eq ido-cur-item 'file))
       (progn
-	(setq vc-master-templates
-	      (if vc-master-templates nil ido-saved-vc-mt))
+	(setq vc-handled-backends
+	      (if vc-handled-backends nil ido-saved-vc-hb))
 	(setq ido-text-init ido-text)
 	(setq ido-exit 'keep)
 	(exit-minibuffer))))
@@ -2120,9 +2487,10 @@
 (defun ido-exit-minibuffer ()
   "Exit minibuffer, but make sure we have a match if one is needed."
   (interactive)
-  (if (or (not ido-require-match)
-	   (ido-existing-item-p))
-      (throw 'exit nil)))
+  (if (and (or (not ido-require-match)
+               (ido-existing-item-p))
+           (not ido-incomplete-regexp))
+      (exit-minibuffer)))
 
 (defun ido-select-text ()
   "Select the buffer or file named by the prompt.
@@ -2134,19 +2502,22 @@
 (defun ido-fallback-command ()
   "Fallback to non-ido version of current command."
   (interactive)
+  (let ((i (length ido-text)))
+    (while (> i 0)
+      (push (aref ido-text (setq i (1- i))) unread-command-events)))
   (setq ido-exit 'fallback)
   (exit-minibuffer))
 
 (defun ido-enter-find-file ()
-  "Drop into find-file from buffer switching."
+  "Drop into `find-file' from buffer switching."
   (interactive)
-  (setq ido-exit 'findfile)
+  (setq ido-exit 'find-file)
   (exit-minibuffer))
 
 (defun ido-enter-switch-buffer ()
-  "Drop into ido-switch-buffer from file switching."
+  "Drop into `ido-switch-buffer' from file switching."
   (interactive)
-  (setq ido-exit 'findbuffer)
+  (setq ido-exit 'switch-to-buffer)
   (exit-minibuffer))
 
 (defun ido-enter-dired ()
@@ -2155,6 +2526,18 @@
   (setq ido-exit 'dired)
   (exit-minibuffer))
 
+(defun ido-enter-insert-buffer ()
+  "Drop into insert buffer from insert file."
+  (interactive)
+  (setq ido-exit 'insert-buffer)
+  (exit-minibuffer))
+
+(defun ido-enter-insert-file ()
+  "Drop into insert file from insert buffer."
+  (interactive)
+  (setq ido-exit 'insert-file)
+  (exit-minibuffer))
+
 
 (defun ido-up-directory (&optional clear)
   "Go up one directory level."
@@ -2208,10 +2591,11 @@
 	       (not (equal dir ido-current-directory))
 	       (file-directory-p dir)
 	       (or (not must-match)
-		   (ido-set-matches1
+		   ;; TODO. check for nonreadable and too-big.
+		   (ido-set-matches-1
 		    (if (eq ido-cur-item 'file)
-			(ido-make-file-list1 dir)
-		      (ido-make-dir-list1 dir)))))
+			(ido-make-file-list-1 dir)
+		      (ido-make-dir-list-1 dir)))))
 	  (setq j n)
 	(setq dir nil)))
     (if dir
@@ -2253,7 +2637,11 @@
   "Prompt for FILE to search for using find, starting from current directory."
   (interactive)
   (unless file
-    (setq file (read-string (concat "Wide find file: " ido-current-directory) ido-text)))
+    (let ((enable-recursive-minibuffers t))
+      (setq file
+	    (condition-case nil
+		(read-string (concat "Wide find file: " ido-current-directory) ido-text)
+	      (quit "")))))
   (when (> (length file) 0)
     (setq ido-use-merged-list t ido-try-merged-list 'wide)
     (setq ido-exit 'refresh)
@@ -2265,7 +2653,11 @@
   "Prompt for DIR to search for using find, starting from current directory."
   (interactive)
   (unless dir
-    (setq dir (read-string (concat "Wide find directory: " ido-current-directory) ido-text)))
+    (let ((enable-recursive-minibuffers t))
+      (setq dir
+	    (condition-case nil
+		(read-string (concat "Wide find directory: " ido-current-directory) ido-text)
+	      (quit "")))))
   (when (> (length dir) 0)
     (setq ido-use-merged-list t ido-try-merged-list 'wide)
     (setq ido-exit 'refresh)
@@ -2273,11 +2665,41 @@
     (setq ido-rotate-temp t)
     (exit-minibuffer)))
 
+(defun ido-wide-find-dir-or-delete-dir (&optional dir)
+  "Prompt for DIR to search for using find, starting from current directory.
+If input stack is non-empty, delete current directory component."
+  (interactive)
+  (if ido-input-stack
+      (ido-delete-backward-word-updir 1)
+    (ido-wide-find-dir)))
+
+(defun ido-push-dir ()
+  "Move to previous directory in file name, push current input on stack."
+  (interactive)
+  (setq ido-exit 'push)
+  (exit-minibuffer))
+
+(defun ido-pop-dir (arg)
+  "Pop directory from input stack back to input.
+With \\[universal-argument], pop all element."
+  (interactive "P")
+  (when ido-input-stack
+    (setq ido-exit (if arg 'pop-all 'pop))
+    (exit-minibuffer)))
+
+(defun ido-wide-find-file-or-pop-dir (arg)
+  (interactive "P")
+  (if ido-input-stack
+      (ido-pop-dir arg)
+    (ido-wide-find-file)))
+
 (defun ido-make-directory (&optional dir)
   "Prompt for DIR to create in current directory."
   (interactive)
   (unless dir
-    (setq dir (read-string (concat "Make directory: " ido-current-directory) ido-text)))
+    (let ((enable-recursive-minibuffers t))
+      (setq dir
+	    (read-string (concat "Make directory: " ido-current-directory) ido-text))))
   (when (> (length dir) 0)
     (setq dir (concat ido-current-directory dir))
     (unless (file-exists-p dir)
@@ -2459,20 +2881,83 @@
 
 (defun ido-all-completions ()
   ;; Return unsorted list of all competions.
-  (let ((ido-process-ignore-lists nil))
+  (let ((ido-process-ignore-lists nil)
+	(ido-directory-too-big nil))
     (cond
      ((eq ido-cur-item 'file)
-      (ido-make-file-list1 ido-current-directory))
+      (ido-make-file-list-1 ido-current-directory))
      ((eq ido-cur-item 'dir)
-      (ido-make-dir-list1 ido-current-directory))
+      (ido-make-dir-list-1 ido-current-directory))
      ((eq ido-cur-item 'buffer)
-      (ido-make-buffer-list1))
+      (ido-make-buffer-list-1))
+     ((eq ido-cur-item 'list)
+      ido-choice-list)
      (t nil))))
 
 
-(defun ido-sort-list (items)
-  ;; Simple list of file or buffer names
-  (sort items (lambda (a b) (string-lessp a b))))
+;; File list sorting
+
+(defun ido-file-lessp (a b)
+  ;; Simple compare two file names.
+  (string-lessp (ido-no-final-slash a) (ido-no-final-slash b)))
+
+
+(defun ido-file-extension-lessp (a b)
+  ;; Compare file names according to ido-file-extensions-order list.
+  (let ((n (compare-strings a 0 nil b 0 nil nil))
+	lessp p)
+    (if (eq n t)
+	nil
+      (if (< n 0)
+	  (setq n (1- (- n))
+		p a a b b p
+		lessp t)
+	(setq n (1- n)))
+      (cond
+       ((= n 0)
+	lessp)
+       ((= (aref a n) ?.)
+	(ido-file-extension-aux a b n lessp))
+       (t
+	(while (and (> n 2) (/= (aref a n) ?.))
+	  (setq n (1- n)))
+	(if (> n 1)
+	    (ido-file-extension-aux a b n lessp)
+	  lessp))))))
+
+(defun ido-file-extension-aux (a b n lessp)
+  (let ((oa (ido-file-extension-order a n))
+	(ob (ido-file-extension-order b n)))
+    (cond
+     ((= oa ob)
+      lessp)
+     ((and oa ob)
+      (if lessp
+	  (> oa ob)
+	(< oa ob)))
+     (oa
+      (not lessp))
+     (ob
+      lessp)
+     (t
+      lessp))))
+
+(defun ido-file-extension-order (s n)
+  (let ((l ido-file-extensions-order)
+	(i 0) o do)
+    (while l
+      (cond
+       ((eq (car l) t)
+	(setq do i
+	      l (cdr l)))
+       ((eq (compare-strings s n nil (car l) 0 nil nil) t)
+	(setq o i
+	      l nil))
+       (t
+	(setq l (cdr l))))
+      (setq i (1+ i)))
+    (or o do)))
+
 
 (defun ido-sort-merged-list (items promote)
   ;; Input is list of ("file" . "dir") cons cells.
@@ -2522,9 +3007,9 @@
       (setq items (cdr items)))
     res))
 
-(defun ido-make-merged-file-list (text auto wide)
+
+(defun ido-make-merged-file-list-1 (text auto wide)
   (let (res)
-    (message "Searching for `%s'...." text)
     (if (and (ido-final-slash text) ido-dir-file-cache)
 	(if wide
 	    (setq res (ido-wide-find-dirs-or-files
@@ -2575,18 +3060,33 @@
 		       (or ido-merge-ftp-work-directories
 			   (not (ido-is-ftp-directory dir)))
 		       (file-directory-p dir)
+		       ;; TODO. check for nonreadable and too-big.
 		       (setq fl (if (eq ido-cur-item 'file)
-				    (ido-make-file-list1 dir t)
-				  (ido-make-dir-list1 dir t))))
+				    (ido-make-file-list-1 dir t)
+				  (ido-make-dir-list-1 dir t))))
 	      (if must-match
-		  (setq fl (ido-set-matches1 fl)))
+		  (setq fl (ido-set-matches-1 fl)))
 	      (if fl
 		  (setq res (nconc fl res))))
 	    (if (and auto (input-pending-p))
 		(setq dirs nil
 		      res t))))))
-    (if (and res (not (eq res t)))
-	(setq res (ido-sort-merged-list res auto)))
+    res))
+
+(defun ido-make-merged-file-list (text auto wide)
+  (let (res)
+    (message "Searching for `%s'...." text)
+    (condition-case nil
+	(if (eq t (setq res
+			(while-no-input
+			  (ido-make-merged-file-list-1 text auto wide))))
+	    (setq res 'input-pending-p))
+      (quit
+       (setq res t
+	     ido-try-merged-list nil
+	     ido-use-merged-list nil)))
+    (when (and res (listp res))
+      (setq res (ido-sort-merged-list res auto)))
     (when (and (or ido-rotate-temp ido-rotate-file-list-default)
 	       (listp res)
 	       (> (length text) 0))
@@ -2597,7 +3097,7 @@
     (message nil)
     res))
 
-(defun ido-make-buffer-list1 (&optional frame visible)
+(defun ido-make-buffer-list-1 (&optional frame visible)
   ;; Return list of non-ignored buffer names
   (delq nil
 	(mapcar
@@ -2610,12 +3110,12 @@
 (defun ido-make-buffer-list (default)
   ;; Return the current list of buffers.
   ;; Currently visible buffers are put at the end of the list.
-  ;; The hook `ido-make-buflist-hook' is run after the list has been
+  ;; The hook `ido-make-buffer-list-hook' is run after the list has been
   ;; created to allow the user to further modify the order of the buffer names
   ;; in this list.  If DEFAULT is non-nil, and corresponds to an existing buffer,
   ;; it is put to the start of the list.
   (let* ((ido-current-buffers (ido-get-buffers-in-frames 'current))
-	 (ido-temp-list (ido-make-buffer-list1 (selected-frame) ido-current-buffers)))
+	 (ido-temp-list (ido-make-buffer-list-1 (selected-frame) ido-current-buffers)))
     (if ido-temp-list
 	(nconc ido-temp-list ido-current-buffers)
       (setq ido-temp-list ido-current-buffers))
@@ -2628,6 +3128,20 @@
     (run-hooks 'ido-make-buffer-list-hook)
     ido-temp-list))
 
+(defun ido-make-choice-list (default)
+  ;; Return the current list of choices.
+  ;; If DEFAULT is non-nil, and corresponds to an element of choices,
+  ;; it is put to the start of the list.
+  (let ((ido-temp-list ido-choice-list))
+    (if default
+	(progn
+	  (setq ido-temp-list
+		(delete default ido-temp-list))
+	  (setq ido-temp-list
+		(cons default ido-temp-list))))
+    ; (run-hooks 'ido-make-choice-list-hook)
+    ido-temp-list))
+
 (defun ido-to-end (items)
   ;; Move the elements from ITEMS to the end of `ido-temp-list'
   (mapcar
@@ -2638,31 +3152,38 @@
       (nconc ido-temp-list items)
     (setq ido-temp-list items)))
 
-(defun ido-file-name-all-completions1 (dir)
-  (if (and ido-enable-tramp-completion
-	   (string-match "\\`/\\([^/:]+:\\([^/:@]+@\\)?\\)\\'" dir))
-
-      ;; Trick tramp's file-name-all-completions handler to DTRT, as it
-      ;; has some pretty obscure requirements.  This seems to work...
-      ;; /ftp:		=> (f-n-a-c "/ftp:" "")
-      ;; /ftp:kfs:	=> (f-n-a-c "" "/ftp:kfs:")
-      ;; /ftp:kfs@      => (f-n-a-c "ftp:kfs@" "/")
-      ;; /ftp:kfs@kfs:  => (f-n-a-c "" "/ftp:kfs@kfs:")
-      ;; Currently no attempt is made to handle multi: stuff.
-
-      (let* ((prefix (match-string 1 dir))
-	     (user-flag (match-beginning 2))
-	     (len (and prefix (length prefix)))
-	     compl)
-	(if user-flag
-	    (setq dir (substring dir 1)))
-	(require 'tramp nil t)
-	(ido-trace "tramp complete" dir)
-	(setq compl (file-name-all-completions dir (if user-flag "/" "")))
-	(if (> len 0)
-	    (mapcar (lambda (c) (substring c len)) compl)
-	  compl))
-    (file-name-all-completions "" dir)))
+(defun ido-file-name-all-completions-1 (dir)
+  (cond
+   ((ido-nonreadable-directory-p dir) '())
+   ;; do not check (ido-directory-too-big-p dir) here.
+   ;; Caller must have done that if necessary.
+
+   ((and ido-enable-tramp-completion
+	 (or (fboundp 'tramp-completion-mode)
+	     (require 'tramp nil t))
+	 (string-match "\\`/[^/]+[:@]\\'" dir))
+    ;; Strip method:user@host: part of tramp completions.
+    ;; Tramp completions do not include leading slash.
+    (let ((len (1- (length dir)))
+	  (compl
+	   (or (file-name-all-completions "" dir)
+	       ;; work around bug in ange-ftp.
+	       ;; /ftp:user@host: => nil
+	       ;; /ftp:user@host:./ => ok
+	       (and
+		(not (string= "/ftp:" dir))
+		(tramp-tramp-file-p dir)
+		(fboundp 'tramp-ftp-file-name-p)
+		(funcall 'tramp-ftp-file-name-p dir)
+		(string-match ":\\'" dir)
+		(file-name-all-completions "" (concat dir "./"))))))
+      (if (and compl
+	       (> (length (car compl)) len)
+	       (string= (substring (car compl) 0 len) (substring dir 1)))
+	  (mapcar (lambda (c) (substring c len)) compl)
+	compl)))
+   (t
+    (file-name-all-completions "" dir))))
 
 (defun ido-file-name-all-completions (dir)
   ;; Return name of all files in DIR
@@ -2690,13 +3211,13 @@
 	  (if (and ftp (file-readable-p dir))
 	      (setq mtime (cons 'ftp (ido-time-stamp))))
 	  (if mtime
-	      (setq cached (cons dir (cons mtime (ido-file-name-all-completions1 dir)))
+	      (setq cached (cons dir (cons mtime (ido-file-name-all-completions-1 dir)))
 		    ido-dir-file-cache (cons cached ido-dir-file-cache)))
 	  (if (> (length ido-dir-file-cache) ido-max-dir-file-cache)
 	      (setcdr (nthcdr (1- ido-max-dir-file-cache) ido-dir-file-cache) nil)))
 	(and cached
 	     (cdr (cdr cached))))
-    (ido-file-name-all-completions1 dir)))
+    (ido-file-name-all-completions-1 dir)))
 
 (defun ido-remove-cached-dir (dir)
   ;; Remove dir from ido-dir-file-cache
@@ -2707,7 +3228,7 @@
 	    (setq ido-dir-file-cache (delq cached ido-dir-file-cache))))))
 
 
-(defun ido-make-file-list1 (dir &optional merged)
+(defun ido-make-file-list-1 (dir &optional merged)
   ;; Return list of non-ignored files in DIR
   ;; If MERGED is non-nil, each file is cons'ed with DIR
   (and (or (ido-is-tramp-root dir) (file-directory-p dir))
@@ -2724,15 +3245,19 @@
   ;; The hook `ido-make-file-list-hook' is run after the list has been
   ;; created to allow the user to further modify the order of the file names
   ;; in this list.
-  (let ((ido-temp-list (ido-make-file-list1 ido-current-directory)))
-    (setq ido-temp-list (ido-sort-list ido-temp-list))
-    (let ((default-directory ido-current-directory))
-      (ido-to-end ;; move ftp hosts and visited files to end
-       (delq nil (mapcar
-		  (lambda (x) (if (or (string-match "..:\\'" x)
-				      (and (not (ido-final-slash x))
-					   (get-file-buffer x))) x))
-		  ido-temp-list))))
+  (let ((ido-temp-list (ido-make-file-list-1 ido-current-directory)))
+    (setq ido-temp-list (sort ido-temp-list
+			      (if ido-file-extensions-order
+				  #'ido-file-extension-lessp
+				#'ido-file-lessp)))
+    (unless (ido-is-tramp-root ido-current-directory)
+      (let ((default-directory ido-current-directory))
+	(ido-to-end ;; move ftp hosts and visited files to end
+	 (delq nil (mapcar
+		    (lambda (x) (if (or (string-match "..:\\'" x)
+					(and (not (ido-final-slash x))
+					     (get-file-buffer x))) x))
+		    ido-temp-list)))))
     (ido-to-end  ;; move . files to end
      (delq nil (mapcar
 		(lambda (x) (if (string-equal (substring x 0 1) ".") x))
@@ -2757,7 +3282,7 @@
     (run-hooks 'ido-make-file-list-hook)
     ido-temp-list))
 
-(defun ido-make-dir-list1 (dir &optional merged)
+(defun ido-make-dir-list-1 (dir &optional merged)
   ;; Return list of non-ignored subdirs in DIR
   ;; If MERGED is non-nil, each subdir is cons'ed with DIR
   (and (or (ido-is-tramp-root dir) (file-directory-p dir))
@@ -2773,8 +3298,8 @@
   ;; The hook `ido-make-dir-list-hook' is run after the list has been
   ;; created to allow the user to further modify the order of the
   ;; directory names in this list.
-  (let ((ido-temp-list (ido-make-dir-list1 ido-current-directory)))
-    (setq ido-temp-list (ido-sort-list ido-temp-list))
+  (let ((ido-temp-list (ido-make-dir-list-1 ido-current-directory)))
+    (setq ido-temp-list (sort ido-temp-list #'ido-file-lessp))
     (ido-to-end  ;; move . files to end
      (delq nil (mapcar
 		(lambda (x) (if (string-equal (substring x 0 1) ".") x))
@@ -2794,7 +3319,8 @@
 	  (setq ido-temp-list
 		(cons default ido-temp-list))))
     (setq ido-temp-list (delete "." ido-temp-list))
-    (setq ido-temp-list (cons "." ido-temp-list))
+    (unless ido-input-stack
+      (setq ido-temp-list (cons "." ido-temp-list)))
     (run-hooks 'ido-make-dir-list-hook)
     ido-temp-list))
 
@@ -2826,7 +3352,7 @@
 
 ;;; FIND MATCHING ITEMS
 
-(defun ido-set-matches1 (items &optional do-full)
+(defun ido-set-matches-1 (items &optional do-full)
   ;; Return list of matches in items
   (let* ((case-fold-search  ido-case-fold)
 	 (slash (and (not ido-enable-prefix) (ido-final-slash ido-text)))
@@ -2837,21 +3363,38 @@
 		       (concat "\\`" re "\\'")))
 	 (prefix-re (and full-re (not ido-enable-prefix)
 			 (concat "\\`" rexq)))
+	 (non-prefix-dot (or (not ido-enable-dot-prefix)
+			     (not ido-process-ignore-lists)
+			     ido-enable-prefix
+			     (= (length ido-text) 0)))
+
 	 full-matches
 	 prefix-matches
 	 matches)
-    (mapcar
-     (lambda (item)
-       (let ((name (ido-name item)))
-	 (if (string-match re name)
-	     (cond
-	      ((and full-re (string-match full-re name))
-	       (setq full-matches (cons item full-matches)))
-	      ((and prefix-re (string-match prefix-re name))
-	       (setq prefix-matches (cons item prefix-matches)))
-	      (t (setq matches (cons item matches))))))
-       t)
-     items)
+    (setq ido-incomplete-regexp nil)
+    (condition-case error
+        (mapcar
+         (lambda (item)
+           (let ((name (ido-name item)))
+             (if (and (or non-prefix-dot
+                          (if (= (aref ido-text 0) ?.)
+                              (= (aref name 0) ?.)
+                            (/= (aref name 0) ?.)))
+                      (string-match re name))
+                 (cond
+                  ((and full-re (string-match full-re name))
+                   (setq full-matches (cons item full-matches)))
+                  ((and prefix-re (string-match prefix-re name))
+                   (setq prefix-matches (cons item prefix-matches)))
+                  (t (setq matches (cons item matches))))))
+           t)
+         items)
+      (invalid-regexp
+       (setq ido-incomplete-regexp t
+             ;; Consider the invalid regexp message internally as a
+             ;; special-case single match, and handle appropriately
+             ;; elsewhere.
+             matches (cdr error))))
     (if prefix-matches
 	(setq matches (nconc prefix-matches matches)))
     (if full-matches
@@ -2875,7 +3418,7 @@
 (defun ido-set-matches ()
   ;; Set `ido-matches' to the list of items matching prompt
   (when ido-rescan
-    (setq ido-matches (ido-set-matches1 (reverse ido-cur-list) (not ido-rotate))
+    (setq ido-matches (ido-set-matches-1 (reverse ido-cur-list) (not ido-rotate))
 	  ido-rotate nil)))
 
 (defun ido-ignore-item-p (name re-list &optional ignore-ext)
@@ -2883,38 +3426,37 @@
   (or (member name ido-ignore-item-temp-list)
       (and
        ido-process-ignore-lists re-list
-       (let ((data       (match-data))
-	     (ext-list   (and ignore-ext ido-ignore-extensions
+       (save-match-data
+	 (let ((ext-list (and ignore-ext ido-ignore-extensions
 			      completion-ignored-extensions))
-	     ignorep nextstr
-	     (flen (length name)) slen)
-	 (while ext-list
-	   (setq nextstr (car ext-list))
-	   (if (cond
-		((stringp nextstr)
-		 (and (>= flen (setq slen (length nextstr)))
-		      (string-equal (substring name (- flen slen)) nextstr)))
-		((fboundp nextstr) (funcall nextstr name))
-		(t nil))
-	       (setq ignorep t
-		     ext-list nil
-		     re-list nil)
-	     (setq ext-list (cdr ext-list))))
-	 (while re-list
-	   (setq nextstr (car re-list))
-	   (if (cond
-		((stringp nextstr) (string-match nextstr name))
-		((fboundp nextstr) (funcall nextstr name))
-		(t nil))
-	       (setq ignorep t
-		     re-list nil)
-	     (setq re-list (cdr re-list))))
-	 ;; return the result
-	 (if ignorep
-	     (setq ido-ignored-list (cons name ido-ignored-list)))
-	 (set-match-data data)
-	 ignorep))))
-
+	       (case-fold-search ido-case-fold)
+	       ignorep nextstr
+	       (flen (length name)) slen)
+	   (while ext-list
+	     (setq nextstr (car ext-list))
+	     (if (cond
+		  ((stringp nextstr)
+		   (and (>= flen (setq slen (length nextstr)))
+			(string-equal (substring name (- flen slen)) nextstr)))
+		  ((fboundp nextstr) (funcall nextstr name))
+		  (t nil))
+		 (setq ignorep t
+		       ext-list nil
+		       re-list nil)
+	       (setq ext-list (cdr ext-list))))
+	   (while re-list
+	     (setq nextstr (car re-list))
+	     (if (cond
+		  ((stringp nextstr) (string-match nextstr name))
+		  ((fboundp nextstr) (funcall nextstr name))
+		  (t nil))
+		 (setq ignorep t
+		       re-list nil)
+	       (setq re-list (cdr re-list))))
+	   ;; return the result
+	   (if ignorep
+	       (setq ido-ignored-list (cons name ido-ignored-list)))
+	   ignorep)))))
 
 ;; Private variable used by `ido-word-matching-substring'.
 (defvar ido-change-word-sub)
@@ -2987,7 +3529,8 @@
 	  (if (pos-visible-in-window-p (point-max) win)
 	      (if (or ido-completion-buffer-all-completions (boundp 'ido-completion-buffer-full))
 		  (set-window-start win (point-min))
-		(set (make-local-variable 'ido-completion-buffer-full) t)
+		(with-no-warnings
+		  (set (make-local-variable 'ido-completion-buffer-full) t))
 		(setq full-list t
 		      display-it t))
 	    (scroll-other-window))
@@ -2995,14 +3538,15 @@
       (setq display-it t))
     (if display-it
 	(with-output-to-temp-buffer ido-completion-buffer
-	  (let ((completion-list (ido-sort-list
+	  (let ((completion-list (sort
 				  (cond
 				   (ido-use-merged-list
 				    (ido-flatten-merged-list (or ido-matches ido-cur-list)))
 				   ((or full-list ido-completion-buffer-all-completions)
 				    (ido-all-completions))
 				   (t
-				    (copy-sequence (or ido-matches ido-cur-list)))))))
+				    (copy-sequence (or ido-matches ido-cur-list))))
+				  #'ido-file-lessp)))
 	    (if (featurep 'xemacs)
 		;; XEmacs extents are put on by default, doesn't seem to be
 		;; any way of switching them off.
@@ -3043,7 +3587,7 @@
 	       (file-exists-p file)
 	       (not (file-directory-p file))
 	       (file-writable-p ido-current-directory)
-	       (yes-or-no-p (concat "Delete " file " ")))
+	       (yes-or-no-p (concat "Delete " file "? ")))
       (delete-file file)
       ;; Check if file still exists.
       (if (file-exists-p file)
@@ -3056,7 +3600,7 @@
 ;;; VISIT CHOSEN BUFFER
 (defun ido-visit-buffer (buffer method &optional record)
   "Visit file named FILE according to METHOD.
-Record command in command-history if optional RECORD is non-nil."
+Record command in `command-history' if optional RECORD is non-nil."
 
   (let (win newframe)
     (cond
@@ -3129,9 +3673,9 @@
 
 As you type in a string, all of the buffers matching the string are
 displayed if substring-matching is used \(default). Look at
-`ido-enable-prefix' and `ido-toggle-prefix'. When you have found the
-buffer you want, it can then be selected. As you type, most keys have their
-normal keybindings, except for the following: \\<ido-mode-map>
+`ido-enable-prefix' and `ido-toggle-prefix'.  When you have found the
+buffer you want, it can then be selected.  As you type, most keys have
+their normal keybindings, except for the following: \\<ido-buffer-completion-map>
 
 RET Select the buffer at the front of the list of matches.  If the
 list is empty, possibly prompt to create new buffer.
@@ -3171,7 +3715,7 @@
 The buffer name is selected interactively by typing a substring.
 For details of keybindings, do `\\[describe-function] ido'."
   (interactive)
-  (ido-buffer-internal 'display 'display-buffer))
+  (ido-buffer-internal 'display 'display-buffer nil nil nil 'ignore))
 
 ;;;###autoload
 (defun ido-kill-buffer ()
@@ -3179,7 +3723,7 @@
 The buffer name is selected interactively by typing a substring.
 For details of keybindings, do `\\[describe-function] ido'."
   (interactive)
-  (ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer))))
+  (ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer)) nil 'ignore))
 
 ;;;###autoload
 (defun ido-insert-buffer ()
@@ -3187,7 +3731,7 @@
 The buffer name is selected interactively by typing a substring.
 For details of keybindings, do `\\[describe-function] ido'."
   (interactive)
-  (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: "))
+  (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil nil 'ido-enter-insert-file))
 
 ;;;###autoload
 (defun ido-switch-buffer-other-frame ()
@@ -3205,7 +3749,7 @@
   (interactive "DDir: ")
   (if (not (equal (substring dir -1) "/"))
       (setq dir (concat dir "/")))
-  (ido-file-internal ido-default-file-method nil dir))
+  (ido-file-internal ido-default-file-method nil dir nil nil nil 'ignore))
 
 ;;;###autoload
 (defun ido-find-file ()
@@ -3214,12 +3758,12 @@
 default is to show it in the same window, unless it is already
 visible in another frame.
 
-The file name is selected interactively by typing a substring. As you type
-in a string, all of the filenames matching the string are displayed if
-substring-matching is used \(default). Look at `ido-enable-prefix' and
-`ido-toggle-prefix'. When you have found the filename you want, it can
-then be selected. As you type, most keys have their normal keybindings,
-except for the following: \\<ido-mode-map>
+The file name is selected interactively by typing a substring.  As you
+type in a string, all of the filenames matching the string are displayed
+if substring-matching is used \(default).  Look at `ido-enable-prefix' and
+`ido-toggle-prefix'.  When you have found the filename you want, it can
+then be selected.  As you type, most keys have their normal keybindings,
+except for the following: \\<ido-file-completion-map>
 
 RET Select the file at the front of the list of matches.  If the
 list is empty, possibly prompt to create new file.
@@ -3238,7 +3782,7 @@
 \\[ido-merge-work-directories] search for file in the work directory history.
 \\[ido-forget-work-directory] removes current directory from the work directory history.
 \\[ido-prev-work-file] or \\[ido-next-work-file] cycle through the work file history.
-\\[ido-wide-find-file] and \\[ido-wide-find-dir] prompts and uses find to locate files or directories.
+\\[ido-wide-find-file-or-pop-dir] and \\[ido-wide-find-dir-or-delete-dir] prompts and uses find to locate files or directories.
 \\[ido-make-directory] prompts for a directory to create in current directory.
 \\[ido-fallback-command] Fallback to non-ido version of current command.
 \\[ido-toggle-regexp] Toggle regexp searching.
@@ -3298,7 +3842,7 @@
 The file name is selected interactively by typing a substring.
 For details of keybindings, do `\\[describe-function] ido-find-file'."
   (interactive)
-  (ido-file-internal 'display))
+  (ido-file-internal 'display nil nil nil nil nil 'ignore))
 
 ;;;###autoload
 (defun ido-find-file-other-frame ()
@@ -3318,8 +3862,9 @@
 	(ido-work-directory-match-only nil)
 	(ido-ignore-files (cons "[^/]\\'" ido-ignore-files))
 	(ido-report-no-match nil)
+	(ido-confirm-unique-completion t)
 	(ido-auto-merge-work-directories-length -1))
-    (ido-file-internal 'write 'write-file nil "Write file: ")))
+    (ido-file-internal 'write 'write-file nil "Write file: " nil nil 'ignore)))
 
 ;;;###autoload
 (defun ido-insert-file ()
@@ -3327,7 +3872,7 @@
 The file name is selected interactively by typing a substring.
 For details of keybindings, do `\\[describe-function] ido-find-file'."
   (interactive)
-  (ido-file-internal 'insert 'insert-file nil "Insert file: "))
+  (ido-file-internal 'insert 'insert-file nil "Insert file: " nil nil 'ido-enter-insert-buffer))
 
 ;;;###autoload
 (defun ido-dired ()
@@ -3408,7 +3953,7 @@
 
 	;; Handle explicit directory changes
 	(cond
-	 ((eq ido-cur-item 'buffer)
+	 ((memq ido-cur-item '(buffer list))
 	  )
 
 	 ((= (length contents) 0)
@@ -3464,6 +4009,11 @@
 		 (expand-file-name "/" ido-current-directory)
 	       "/"))
 	    (setq refresh t))
+	   ((and (or ido-directory-nonreadable ido-directory-too-big)
+		 (file-directory-p (concat ido-current-directory (file-name-directory contents))))
+	    (ido-set-current-directory
+	     (concat ido-current-directory (file-name-directory contents)))
+	    (setq refresh t))
 	   (t
 	    (ido-trace "try single dir")
 	    (setq try-single-dir-match t))))
@@ -3507,12 +4057,13 @@
 	(ido-set-matches)
 	(ido-trace "new    " ido-matches)
 
-	(when (and ido-enter-single-matching-directory
+	(when (and ido-enter-matching-directory
 		   ido-matches
-		   (null (cdr ido-matches))
+		   (or (eq ido-enter-matching-directory 'first)
+		       (null (cdr ido-matches)))
 		   (ido-final-slash (car ido-matches))
 		   (or try-single-dir-match
-		       (eq ido-enter-single-matching-directory t)))
+		       (eq ido-enter-matching-directory t)))
 	  (ido-trace "single match" (car ido-matches))
 	  (ido-set-current-directory
 	   (concat ido-current-directory (car ido-matches)))
@@ -3520,6 +4071,8 @@
 	  (exit-minibuffer))
 
 	(when (and (not ido-matches)
+		   (not ido-directory-nonreadable)
+		   (not ido-directory-too-big)
 		   ;; ido-rescan ?
 		   ido-process-ignore-lists
 		   ido-ignored-list)
@@ -3542,7 +4095,9 @@
 	       (memq ido-cur-item '(file dir))
 	       (not (ido-is-root-directory))
 	       (> (length contents) 1)
-	       (not (string-match "[$]" contents)))
+	       (not (string-match "[$]" contents))
+	       (not ido-directory-nonreadable)
+	       (not ido-directory-too-big))
 	  (ido-trace "merge?")
 	  (if ido-use-merged-list
 	      (ido-undo-merge-work-directory contents nil)
@@ -3589,7 +4144,7 @@
 	 first)
 
     (if (and ind ido-use-faces)
-	(put-text-property 0 1 'face 'ido-indicator-face ind))
+	(put-text-property 0 1 'face 'ido-indicator ind))
 
     (if (and ido-use-faces comps)
 	(let* ((fn (ido-name (car comps)))
@@ -3597,24 +4152,39 @@
 	  (setq first (format "%s" fn))
 	  (put-text-property 0 ln 'face
 			     (if (= (length comps) 1)
-				 'ido-only-match-face
-			       'ido-first-match-face)
+                                 (if ido-incomplete-regexp
+                                     'ido-incomplete-regexp
+                                   'ido-only-match)
+			       'ido-first-match)
 			     first)
 	  (if ind (setq first (concat first ind)))
 	  (setq comps (cons first (cdr comps)))))
 
     (cond ((null comps)
-	   (if ido-report-no-match
-	       (nth 6 ido-decorations)  ;; [No Match]
-	     ""))
-
+	   (cond
+	    (ido-directory-nonreadable
+	     (or (nth 8 ido-decorations) " [Not readable]"))
+	    (ido-directory-too-big
+	     (or (nth 9 ido-decorations) " [Too big]"))
+	    (ido-report-no-match
+	     (nth 6 ido-decorations))  ;; [No match]
+	    (t "")))
+	  (ido-incomplete-regexp
+           (concat " " (car comps)))
 	  ((null (cdr comps))		;one match
-	   (concat (if (> (length (ido-name (car comps))) (length name))
-		       ;; when there is one match, show the matching file name in full
-		       (concat (nth 4 ido-decorations)  ;; [ ... ]
-			       (ido-name (car comps))
-			       (nth 5 ido-decorations))
-		     "")
+	   (concat (if (if (not ido-enable-regexp)
+                           (= (length (ido-name (car comps))) (length name))
+                         ;; We can't rely on the length of the input
+                         ;; for regexps, so explicitly check for a
+                         ;; complete match
+                         (string-match name (ido-name (car comps)))
+                         (string-equal (match-string 0 (ido-name (car comps)))
+                                       (ido-name (car comps))))
+                       ""
+                     ;; when there is one match, show the matching file name in full
+                     (concat (nth 4 ido-decorations)  ;; [ ... ]
+                             (ido-name (car comps))
+                             (nth 5 ido-decorations)))
 		   (if (not ido-use-faces) (nth 7 ido-decorations))))  ;; [Matched]
 	  (t				;multiple matches
 	   (let* ((items (if (> ido-max-prospects 0) (1+ ido-max-prospects) 999))
@@ -3636,7 +4206,7 @@
 				       (if (and ido-use-faces
 						(not (string= str first))
 						(ido-final-slash str))
-					   (put-text-property 0 (length str) 'face 'ido-subdir-face str))
+					   (put-text-property 0 (length str) 'face 'ido-subdir str))
 				       str)))))
 			   comps))))))
 
@@ -3707,40 +4277,91 @@
 
 ;;; Helper functions for other programs
 
+(put 'dired-do-rename 'ido 'ignore)
+(put 'ibuffer-find-file 'ido 'find-file)
+(put 'dired-other-window 'ido 'dir)
+
+;;;###autoload
+(defun ido-read-buffer (prompt &optional default require-match)
+  "Ido replacement for the built-in `read-buffer'.
+Return the name of a buffer selected.
+PROMPT is the prompt to give to the user.  DEFAULT if given is the default
+buffer to be selected, which will go to the front of the list.
+If REQUIRE-MATCH is non-nil, an existing buffer must be selected."
+  (let* ((ido-current-directory nil)
+	 (ido-directory-nonreadable nil)
+	 (ido-directory-too-big nil)
+	 (ido-context-switch-command 'ignore)
+	 (buf (ido-read-internal 'buffer prompt 'ido-buffer-history default require-match)))
+    (if (eq ido-exit 'fallback)
+	(let ((read-buffer-function nil))
+	  (run-hook-with-args 'ido-before-fallback-functions 'read-buffer)
+	  (read-buffer prompt default require-match))
+      buf)))
+
 ;;;###autoload
 (defun ido-read-file-name (prompt &optional dir default-filename mustmatch initial predicate)
-  "Read file name, prompting with PROMPT and completing in directory DIR.
+  "Ido replacement for the built-in `read-file-name'.
+Read file name, prompting with PROMPT and completing in directory DIR.
 See `read-file-name' for additional parameters."
-  (cond
-  ((or (eq predicate 'file-directory-p)
-       (memq this-command ido-read-file-name-as-directory-commands))
-   (ido-read-directory-name prompt dir default-filename mustmatch initial))
-  ((and (not (memq this-command ido-read-file-name-non-ido))
-	(or (null predicate) (eq predicate 'file-exists-p)))
-   (let (filename
-	 ido-saved-vc-mt
-	 (vc-master-templates (and (boundp 'vc-master-templates) vc-master-templates))
-	 (ido-current-directory (expand-file-name (or dir default-directory)))
-	 (ido-work-directory-index -1)
-	 (ido-work-file-index -1)
-	 (ido-find-literal nil))
-     (setq filename
-	   (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial))
-     (if filename
-	 (concat ido-current-directory filename))))
-  (t
-   (let ((read-file-name-function nil))
-     (read-file-name prompt dir default-filename mustmatch initial predicate)))))
+  (let (filename)
+    (cond
+     ((or (eq predicate 'file-directory-p)
+	  (eq (get this-command 'ido) 'dir)
+	  (memq this-command ido-read-file-name-as-directory-commands))
+      (setq filename
+	    (ido-read-directory-name prompt dir default-filename mustmatch initial))
+      (if (eq ido-exit 'fallback)
+	  (setq filename 'fallback)))
+     ((and (not (eq (get this-command 'ido) 'ignore))
+	   (not (memq this-command ido-read-file-name-non-ido))
+	   (or (null predicate) (eq predicate 'file-exists-p)))
+      (let* (ido-saved-vc-hb
+	     (ido-context-switch-command
+	      (if (eq (get this-command 'ido) 'find-file) nil 'ignore))
+	     (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends))
+	     (minibuffer-completing-file-name t)
+	     (ido-current-directory (ido-expand-directory dir))
+	     (ido-directory-nonreadable (not (file-readable-p ido-current-directory)))
+	     (ido-directory-too-big (and (not ido-directory-nonreadable)
+					 (ido-directory-too-big-p ido-current-directory)))
+	     (ido-work-directory-index -1)
+	     (ido-work-file-index -1)
+	     (ido-find-literal nil))
+	(setq ido-exit nil)
+	(setq filename
+	      (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial))
+	(cond
+	 ((eq ido-exit 'fallback)
+	  (setq filename 'fallback))
+	 ((eq ido-exit 'dired)
+	  (setq filename ido-current-directory))
+	 (filename
+	  (setq filename
+		(concat ido-current-directory filename))))))
+     (t
+      (setq filename 'fallback)))
+    (if (eq filename 'fallback)
+	(let ((read-file-name-function nil))
+	  (run-hook-with-args 'ido-before-fallback-functions 'read-file-name)
+	  (read-file-name prompt dir default-filename mustmatch initial predicate))
+      filename)))
 
 ;;;###autoload
 (defun ido-read-directory-name (prompt &optional dir default-dirname mustmatch initial)
-  "Read directory name, prompting with PROMPT and completing in directory DIR.
-See `read-file-name' for additional parameters."
-  (let (filename
-	ido-saved-vc-mt
-	(ido-current-directory (expand-file-name (or dir default-directory)))
-	(ido-work-directory-index -1)
-	(ido-work-file-index -1))
+  "Ido replacement for the built-in `read-directory-name'.
+Read directory name, prompting with PROMPT and completing in directory DIR.
+See `read-directory-name' for additional parameters."
+  (let* (filename
+	 (minibuffer-completing-file-name t)
+	 (ido-context-switch-command 'ignore)
+	 ido-saved-vc-hb
+	 (ido-current-directory (ido-expand-directory dir))
+	 (ido-directory-nonreadable (not (file-readable-p ido-current-directory)))
+	 (ido-directory-too-big (and (not ido-directory-nonreadable)
+				     (ido-directory-too-big-p ido-current-directory)))
+	 (ido-work-directory-index -1)
+	 (ido-work-file-index -1))
     (setq filename
 	  (ido-read-internal 'dir prompt 'ido-file-history default-dirname mustmatch initial))
     (if filename
@@ -3748,4 +4369,29 @@
 	    ido-current-directory
 	  (concat ido-current-directory filename)))))
 
+;;;###autoload
+(defun ido-completing-read (prompt choices &optional predicate require-match initial-input hist def)
+  "Ido replacement for the built-in `completing-read'.
+Read a string in the minibuffer with ido-style completion.
+PROMPT is a string to prompt with; normally it ends in a colon and a space.
+CHOICES is a list of strings which are the possible completions.
+PREDICATE is currently ignored; it is included to be compatible
+ with `completing-read'.
+If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless
+ the input is (or completes to) an element of CHOICES or is null.
+ If the input is null, `ido-completing-read' returns DEF, or an empty
+ string if DEF is nil, regardless of the value of REQUIRE-MATCH.
+If INITIAL-INPUT is non-nil, insert it in the minibuffer initially,
+ with point positioned at the end.
+HIST, if non-nil, specifies a history list.
+DEF, if non-nil, is the default value."
+  (let ((ido-current-directory nil)
+	(ido-directory-nonreadable nil)
+	(ido-directory-too-big nil)
+	(ido-context-switch-command 'ignore)
+	(ido-choice-list choices))
+    (ido-read-internal 'list prompt hist def require-match initial-input)))
+
+
+;;; arch-tag: b63a3500-1735-41bd-8a01-05373f0864da
 ;;; ido.el ends here