* ido.el (ido-tidy): Handle read-only text.
[bpt/emacs.git] / lisp / ido.el
index 008561a..9a17c0c 100644 (file)
 ;; ---------------
 ;;
 ;; The standard way of completion with Unix-shells and Emacs is to insert a
-;; PREFIX and then hitting TAB (or another completion key). Cause of this
-;; behavior has become second nature to a lot of emacs users `ido' offers in
+;; PREFIX and then hitting TAB (or another completion key).  Cause of this
+;; behavior has become second nature to a lot of Emacs users `ido' offers in
 ;; addition to the default substring-matching-method (look above) also the
-;; prefix-matching-method. The kind of matching is the only difference to
+;; prefix-matching-method.  The kind of matching is the only difference to
 ;; the description of the substring-matching above.
 ;;
 ;; You can toggle prefix matching with C-p.
 ;; To use ido for all buffer and file selections in Emacs, customize the
 ;; variable `ido-everywhere'.
 
-;; Using ido-like behavior in other lisp packages
+;; Using ido-like behavior in other Lisp packages
 ;; -----------------------------------------------
 
 ;; If you don't want to rely on the `ido-everywhere' functionality,
 ;; 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
+;; 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
 ;; These are some things you might want to change.
 
 (defun ido-fractionp (n)
+  "Return t if N is a fraction."
   (and (numberp n) (> n 0.0) (<= n 1.0)))
 
 (defgroup ido nil
 
 ;;;###autoload
 (defcustom ido-mode nil
-  "Determines for which functional group \(buffer and files) ido behavior
-should be enabled.  The following values are possible:
-- `buffer': Turn only on ido buffer behavior \(switching, killing,
+  "Determines for which buffer/file Ido 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...)
+- `file': Turn only on ido file behavior (finding, writing, inserting...)
 - `both': Turn on ido buffer and file behavior.
-- `nil': Turn off any ido switching.
+-  nil: Turn off any ido switching.
 
 Setting this variable directly does not take effect;
 use either \\[customize] or the function `ido-mode'."
@@ -522,21 +523,26 @@ window with completion alternatives, or `ido-next-match' or
 
 
 (defcustom ido-record-commands t
-  "Non-nil means that `ido' will record commands in command history.
-Note that the non-ido equivalent command is recorded."
+  "Non-nil means that Ido will record commands in command history.
+Note that the non-Ido equivalent command is recorded."
   :type 'boolean
   :group 'ido)
 
 (defcustom ido-max-prospects 12
-  "Non-zero means that the prospect list will be limited to that number of items.
-For a long list of prospects, building the full list for the minibuffer can take a
-non-negligible amount of time; setting this variable reduces that time."
+  "Upper limit of the prospect list if non-zero.
+Zero means no limit for the prospect list.
+For a long list of prospects, building the full list for the
+minibuffer can take a non-negligible amount of time; setting this
+variable reduces that time."
   :type 'integer
   :group 'ido)
 
 (defcustom ido-max-file-prompt-width 0.35
-  "Non-zero means that the prompt string be limited to that number of characters.
-If value is a floating point number, it specifies a fraction of the frame width."
+  "Upper limit of the prompt string.
+If value is an integer, it specifies the number of characters of
+the string.
+If value is a floating point number, it specifies a fraction of
+the frame width."
   :type '(choice
          (integer :tag "Characters" :value 20)
          (restricted-sexp :tag "Fraction of frame width"
@@ -612,7 +618,8 @@ A tramp file name uses the following syntax: /method:user@host:filename."
 
 (defcustom ido-cache-ftp-work-directory-time 1.0
   "Maximum time to cache contents of an ftp directory (in hours).
-Use C-l in prompt to refresh list.
+\\<ido-file-completion-map>
+Use \\[ido-reread-directory] in prompt to refresh list.
 If zero, ftp directories are not cached."
   :type 'number
   :group 'ido)
@@ -630,7 +637,7 @@ equivalent function, e.g. `find-file' rather than `ido-find-file'."
   :group 'ido)
 
 (defvar ido-unc-hosts-cache t
-  "Cached value from `ido-unc-hosts' function.")
+  "Cached value from the function `ido-unc-hosts'.")
 
 (defcustom ido-unc-hosts nil
   "List of known UNC host names to complete after initial //.
@@ -658,7 +665,8 @@ Case is ignored if `ido-downcase-unc-hosts' is set."
 
 (defcustom ido-cache-unc-host-shares-time 8.0
   "Maximum time to cache shares of an UNC host (in hours).
-Use C-l in prompt to refresh list.
+\\<ido-file-completion-map>
+Use \\[ido-reread-directory] in prompt to refresh list.
 If zero, UNC host shares are not cached."
   :type 'number
   :group 'ido)
@@ -704,20 +712,22 @@ When a (partial) file name matches this regexp, merging is inhibited."
 
 (defcustom ido-max-dir-file-cache 100
   "Maximum number of working directories to be cached.
+\\<ido-file-completion-map>
 This is the size of the cache of `file-name-all-completions' results.
 Each cache entry is time stamped with the modification time of the
 directory.  Some systems, like Windows, have unreliable directory
 modification times, so you may choose to disable caching on such
 systems, or explicitly refresh the cache contents using the command
-`ido-reread-directory' command (C-l) in the minibuffer.
+`ido-reread-directory' command (\\[ido-reread-directory]) in the minibuffer.
 See also `ido-dir-file-cache' and `ido-save-directory-list-file'."
   :type 'integer
   :group 'ido)
 
 (defcustom ido-max-directory-size nil
   "Maximum size (in bytes) for directories to use ido completion.
+\\<ido-completion-map>
 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."
+not provide the normal completion.  To show the completions, use \\[ido-toggle-ignore]."
   :type '(choice (const :tag "No limit" nil)
                 (integer :tag "Size in bytes" 30000))
   :group 'ido)
@@ -765,9 +775,10 @@ Obsolete.  Set 3rd element of `ido-decorations' instead."
 
 (defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")
   "List of strings used by ido to display the alternatives in the minibuffer.
-There are 11 elements in this list:
+There are between 11 and 13 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),
+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,
@@ -775,26 +786,36 @@ can be completed using TAB,
 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',
-11th element is displayed to confirm creating new file or buffer."
+11th element is displayed to confirm creating new file or buffer.
+12th and 13th elements (if present) are used as brackets around the sole
+remaining completion.  If absent, elements 5 and 6 are used instead."
   :type '(repeat string)
   :group 'ido)
 
 (defcustom ido-use-virtual-buffers nil
-  "If non-nil, refer to past buffers as well as existing ones.
+  "Specify how virtual buffers should be used.
+The value can be one of the following:
+
+  nil:  No virtual buffers are used.
+  auto: Use virtual bufferw when the current input matches no
+        existing buffers.
+  t:    Always use virtual buffers.
+
 Essentially it works as follows: Say you are visiting a file and
 the buffer gets cleaned up by midnight.el.  Later, you want to
-switch to that buffer, but find it's no longer open.  With
-virtual buffers enabled, the buffer name stays in the buffer
-list (using the `ido-virtual' face, and always at the end), and if
-you select it, it opens the file back up again.  This allows you
-to think less about whether recently opened files are still open
-or not.  Most of the time you can quit Emacs, restart, and then
-switch to a file buffer that was previously open as if it still
-were.
-    This feature relies upon the `recentf' package, which will be
-enabled if this variable is configured to a non-nil value."
-  :version "24.1"
-  :type 'boolean
+switch to that buffer, but find it's no longer open.  With virtual
+buffers enabled, the buffer name stays in the buffer list (using
+the `ido-virtual' face, and always at the end), and if you select
+it, it opens the file back up again.  This allows you to think
+less about whether recently opened files are still open or not.
+Most of the time you can quit Emacs, restart, and then switch to
+a file buffer that was previously open as if it still were.  This
+feature relies upon the `recentf' package, which will be enabled
+if this variable is configured to a non-nil value."
+  :version "24.4"
+  :type '(choice (const :tag "Always" t)
+                (const :tag "Automatic" auto)
+                (const :tag "Never" nil))
   :group 'ido)
 
 (defcustom ido-use-faces t
@@ -927,7 +948,8 @@ ido is running.  Copied from `icomplete-minibuffer-setup-hook'."
   :type 'hook
   :group 'ido)
 
-(defcustom ido-save-directory-list-file (convert-standard-filename "~/.ido.last")
+(defcustom ido-save-directory-list-file
+  (locate-user-emacs-file "ido.last" ".ido.last")
   "File in which the ido state is saved between invocations.
 Variables stored are: `ido-last-directory-list', `ido-work-directory-list',
 `ido-work-file-list', and `ido-dir-file-cache'.
@@ -1100,6 +1122,9 @@ Only used if `ido-use-virtual-buffers' is non-nil.")
 ;; Don't process ido-ignore- lists once.
 (defvar ido-process-ignore-lists-inhibit)
 
+;; Is ido using virtual buffers?
+(defvar ido-enable-virtual-buffers)
+
 ;; Buffer from which ido was entered.
 (defvar ido-entry-buffer)
 
@@ -1585,6 +1610,8 @@ This function also adds a hook to the minibuffer."
     (define-key map "\C-p" 'ido-toggle-prefix)
     (define-key map "\C-r" 'ido-prev-match)
     (define-key map "\C-s" 'ido-next-match)
+    (define-key map [?\C-.] 'ido-next-match)
+    (define-key map [?\C-,] 'ido-prev-match)
     (define-key map "\C-t" 'ido-toggle-regexp)
     (define-key map "\C-z" 'ido-undo-merge-work-directory)
     (define-key map [(control ?\s)] 'ido-restrict-to-matches)
@@ -1762,10 +1789,10 @@ This function also adds a hook to the minibuffer."
   (ido-set-current-directory (expand-file-name (or dir "~/"))))
 
 (defun ido-record-command (command arg)
-  ;; Add (command arg) to command-history if ido-record-commands is t
-  (if ido-record-commands
+  "Add (COMMAND ARG) to `command-history' if `ido-record-commands' is non-nil."
+  (if ido-record-commands              ; FIXME: use `when' instead of `if'?
       (let ((cmd (list command arg)))
-       (if (or (not command-history)
+       (if (or (not command-history)   ; FIXME: ditto
                (not (equal cmd (car command-history))))
            (setq command-history (cons cmd command-history))))))
 
@@ -2136,9 +2163,10 @@ If INITIAL is non-nil, it specifies the initial input string."
                    done t)
            (setq ido-set-default-item t)))
 
-        ((or (string-match "[/\\][^/\\]" ido-selected)
-             (and (memq system-type '(windows-nt ms-dos))
-                  (string-match "\\`[a-zA-Z]:" ido-selected)))
+        ((string-match (if (memq system-type '(windows-nt ms-dos))
+                           "\\`[a-zA-Z]:\\|[/\\][^/\\]"
+                         "/[^/]")
+                       ido-selected)
          (ido-set-current-directory (file-name-directory ido-selected))
          (setq ido-set-default-item t))
 
@@ -2196,7 +2224,8 @@ If cursor is not at the end of the user input, move to end of input."
           (ido-current-directory nil)
           (ido-directory-nonreadable nil)
           (ido-directory-too-big nil)
-          (ido-use-virtual-buffers ido-use-virtual-buffers)
+          (ido-enable-virtual-buffers (and ido-use-virtual-buffers
+                                           (not (eq ido-use-virtual-buffers 'auto))))
           (require-match (confirm-nonexistent-file-or-buffer))
           (buf (ido-read-internal 'buffer (or prompt "Buffer: ") 'ido-buffer-history default
                                   require-match initial))
@@ -2237,7 +2266,8 @@ If cursor is not at the end of the user input, move to end of input."
          (ido-visit-buffer buf method t)))
 
        ;; check for a virtual buffer reference
-       ((and ido-use-virtual-buffers ido-virtual-buffers
+       ((and ido-enable-virtual-buffers
+            ido-virtual-buffers
             (setq filename (assoc buf ido-virtual-buffers)))
        (ido-visit-buffer (find-file-noselect (cdr filename)) method t))
 
@@ -2728,7 +2758,11 @@ C-x C-f ... C-d  enter `dired' on current directory."
 See `ido-use-virtual-buffers' for explanation of virtual buffer."
   (interactive)
   (when (and ido-mode (eq ido-cur-item 'buffer))
-    (setq ido-use-virtual-buffers (not ido-use-virtual-buffers))
+    (setq ido-enable-virtual-buffers
+         (if ido-enable-virtual-buffers
+             nil
+           ;; Use `always' instead of t for `ido-exhibit'.
+           'always))
     (setq ido-text-init ido-text)
     (setq ido-exit 'refresh)
     (exit-minibuffer)))
@@ -3271,14 +3305,18 @@ for first matching file."
 (defun ido-wide-find-dirs-or-files (dir file &optional prefix finddir)
   ;; As ido-run-find-command, but returns a list of cons pairs ("file" . "dir")
   (let ((filenames
-        (split-string
-         (shell-command-to-string
-          (concat "find "
-                  (shell-quote-argument dir)
-                  " -name "
-                  (shell-quote-argument
-                   (concat (if prefix "" "*") file "*"))
-                  " -type " (if finddir "d" "f") " -print"))))
+         (delq nil
+               (mapcar (lambda (name)
+                         (unless (ido-ignore-item-p name ido-ignore-files t)
+                           name))
+                       (split-string
+                        (shell-command-to-string
+                         (concat "find "
+                                 (shell-quote-argument dir)
+                                 (if ido-case-fold " -iname " " -name ")
+                                 (shell-quote-argument
+                                  (concat (if prefix "" "*") file "*"))
+                                 " -type " (if finddir "d" "f") " -print"))))))
        filename d f
        res)
     (while filenames
@@ -3292,7 +3330,7 @@ for first matching file."
     res))
 
 (defun ido-flatten-merged-list (items)
-  ;; Create a list of directory names based on a merged directory list.
+  "Create a list of directory names based on a merged directory list."
   (let (res)
     (while items
       (let* ((item (car items))
@@ -3395,7 +3433,7 @@ for first matching file."
     res))
 
 (defun ido-make-buffer-list-1 (&optional frame visible)
-  ;; Return list of non-ignored buffer names
+  "Return list of non-ignored buffer names."
   (delq nil
        (mapcar
         (lambda (x)
@@ -3405,21 +3443,21 @@ for first matching file."
         (buffer-list frame))))
 
 (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-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.
+  "Return the current list of buffers.
+Currently visible buffers are put at the end of the list.
+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-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))
     (if default
-        (setq ido-temp-list
-              (cons default (delete default ido-temp-list))))
-    (if ido-use-virtual-buffers
+       (setq ido-temp-list
+             (cons default (delete default ido-temp-list))))
+    (if (bound-and-true-p ido-enable-virtual-buffers)
        (ido-add-virtual-buffers-to-list))
     (run-hooks 'ido-make-buffer-list-hook)
     ido-temp-list))
@@ -3434,8 +3472,14 @@ This is to make them appear as if they were \"virtual buffers\"."
   (setq ido-virtual-buffers nil)
   (let (name)
     (dolist (head recentf-list)
-      (and (setq name (file-name-nondirectory head))
-           (null (get-file-buffer head))
+      (setq name (file-name-nondirectory head))
+      ;; In case HEAD is a directory with trailing /.  See bug#14552.
+      (when (equal name "")
+       (setq name (file-name-nondirectory (directory-file-name head))))
+      (when (equal name "")
+       (setq name head))
+      (and (not (equal name ""))
+          (null (get-file-buffer head))
            (not (assoc name ido-virtual-buffers))
            (not (member name ido-temp-list))
            (not (ido-ignore-item-p name ido-ignore-buffers))
@@ -3452,9 +3496,9 @@ This is to make them appear as if they were \"virtual buffers\"."
                 (nreverse (mapcar #'car ido-virtual-buffers))))))
 
 (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.
+  "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
@@ -3466,7 +3510,7 @@ This is to make them appear as if they were \"virtual buffers\"."
     ido-temp-list))
 
 (defun ido-to-end (items)
-  ;; Move the elements from ITEMS to the end of `ido-temp-list'
+  "Move the elements from ITEMS to the end of `ido-temp-list'."
   (mapc
    (lambda (elem)
      (setq ido-temp-list (delq elem ido-temp-list)))
@@ -3510,8 +3554,8 @@ This is to make them appear as if they were \"virtual buffers\"."
     (file-name-all-completions "" dir))))
 
 (defun ido-file-name-all-completions (dir)
-  ;; Return name of all files in DIR
-  ;; Uses and updates ido-dir-file-cache
+  "Return name of all files in DIR.
+Uses and updates `ido-dir-file-cache'."
   (cond
    ((ido-is-unc-root dir)
     (mapcar
@@ -3560,7 +3604,7 @@ This is to make them appear as if they were \"virtual buffers\"."
     (ido-file-name-all-completions-1 dir))))
 
 (defun ido-remove-cached-dir (dir)
-  ;; Remove dir from ido-dir-file-cache
+  "Remove DIR from `ido-dir-file-cache'."
   (if (and ido-dir-file-cache
           (stringp dir) (> (length dir) 0))
       (let ((cached (assoc dir ido-dir-file-cache)))
@@ -3569,8 +3613,8 @@ This is to make them appear as if they were \"virtual buffers\"."
 
 
 (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
+  "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) (ido-is-unc-root dir)
           (file-directory-p dir))
        (delq nil
@@ -3581,11 +3625,11 @@ This is to make them appear as if they were \"virtual buffers\"."
              (ido-file-name-all-completions dir)))))
 
 (defun ido-make-file-list (default)
-  ;; Return the current list of files.
-  ;; Currently visible files are put at the end of the list.
-  ;; 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.
+  "Return the current list of files.
+Currently visible files are put at the end of the list.
+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-list-1 ido-current-directory)))
     (setq ido-temp-list (sort ido-temp-list
                              (if ido-file-extensions-order
@@ -3626,8 +3670,8 @@ This is to make them appear as if they were \"virtual buffers\"."
     ido-temp-list))
 
 (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
+  "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))
        (delq nil
             (mapcar
@@ -3637,10 +3681,10 @@ This is to make them appear as if they were \"virtual buffers\"."
              (ido-file-name-all-completions dir)))))
 
 (defun ido-make-dir-list (default)
-  ;; Return the current list of directories.
-  ;; 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.
+  "Return the current list of directories.
+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-list-1 ido-current-directory)))
     (setq ido-temp-list (sort ido-temp-list #'ido-file-lessp))
     (ido-to-end  ;; move . files to end
@@ -3671,10 +3715,9 @@ This is to make them appear as if they were \"virtual buffers\"."
 (defvar ido-bufs-in-frame)
 
 (defun ido-get-buffers-in-frames (&optional current)
-  ;; Return the list of buffers that are visible in the current frame.
-  ;; If optional argument `current' is given, restrict searching to the
-  ;; current frame, rather than all frames, regardless of value of
-  ;; `ido-all-frames'.
+  "Return the list of buffers that are visible in the current frame.
+If optional argument CURRENT is given, restrict searching to the current
+frame, rather than all frames, regardless of value of `ido-all-frames'."
   (let ((ido-bufs-in-frame nil))
     (walk-windows 'ido-get-bufname nil
                  (if current
@@ -3683,7 +3726,7 @@ This is to make them appear as if they were \"virtual buffers\"."
     ido-bufs-in-frame))
 
 (defun ido-get-bufname (win)
-  ;; Used by `ido-get-buffers-in-frames' to walk through all windows
+  "Used by `ido-get-buffers-in-frames' to walk through all windows."
   (let ((buf (buffer-name (window-buffer win))))
        (unless (or (member buf ido-bufs-in-frame)
                    (member buf ido-ignore-item-temp-list))
@@ -3696,7 +3739,7 @@ This is to make them appear as if they were \"virtual buffers\"."
 ;;; FIND MATCHING ITEMS
 
 (defun ido-set-matches-1 (items &optional do-full)
-  ;; Return list of matches in items
+  "Return list of matches in ITEMS."
   (let* ((case-fold-search  ido-case-fold)
         (slash (and (not ido-enable-prefix) (ido-final-slash ido-text)))
         (text (if slash (substring ido-text 0 -1) ido-text))
@@ -3780,17 +3823,17 @@ This is to make them appear as if they were \"virtual buffers\"."
           (if (string-match re name)
               (setq matches (cons item matches)))))
        items))
-    matches))
+    (delete-consecutive-dups matches t)))
 
 
 (defun ido-set-matches ()
-  ;; Set `ido-matches' to the list of items matching prompt
+  "Set `ido-matches' to the list of items matching prompt."
   (when ido-rescan
     (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)
-  ;; Return t if the buffer or file NAME should be ignored.
+  "Return t if the buffer or file NAME should be ignored."
   (or (member name ido-ignore-item-temp-list)
       (and
        ido-process-ignore-lists re-list
@@ -3830,7 +3873,7 @@ This is to make them appear as if they were \"virtual buffers\"."
 (defvar ido-change-word-sub)
 
 (defun ido-find-common-substring (items subs)
-  ;; Return common string following SUBS in each element of ITEMS.
+  "Return common string following SUBS in each element of ITEMS."
   (let (res
         alist
         ido-change-word-sub)
@@ -3850,8 +3893,8 @@ This is to make them appear as if they were \"virtual buffers\"."
        comp))))
 
 (defun ido-word-matching-substring (word)
-  ;; Return part of WORD before 1st match to `ido-change-word-sub'.
-  ;; If `ido-change-word-sub' cannot be found in WORD, return nil.
+  "Return part of WORD before first match to `ido-change-word-sub'.
+If `ido-change-word-sub' cannot be found in WORD, return nil."
   (let ((case-fold-search ido-case-fold))
     (let ((m (string-match ido-change-word-sub (ido-name word))))
       (if m
@@ -3860,7 +3903,7 @@ This is to make them appear as if they were \"virtual buffers\"."
         nil))))
 
 (defun ido-makealist (res)
-  ;; Return dotted pair (RES . 1).
+  "Return dotted pair (RES . 1)."
   (cons res 1))
 
 (defun ido-choose-completion-string (choice &rest ignored)
@@ -3929,12 +3972,11 @@ This is to make them appear as if they were \"virtual buffers\"."
            (if (featurep 'xemacs)
                ;; XEmacs extents are put on by default, doesn't seem to be
                ;; any way of switching them off.
-               ;; This obscure code avoids a byte compiler warning in Emacs.
-               (let ((f 'display-completion-list))
-                 (funcall f completion-list
-                          :help-string "ido "
-                          :activate-callback
-                          (lambda (x y z) (message "Doesn't work yet, sorry!"))))
+                (display-completion-list
+                 completion-list
+                 :help-string "ido "
+                 :activate-callback
+                 (lambda (&rest _) (message "Doesn't work yet, sorry!")))
              ;; else running Emacs
              ;;(add-hook 'completion-setup-hook 'completion-setup-function)
              (display-completion-list completion-list)))))))
@@ -3977,6 +4019,7 @@ If cursor is not at the end of the user input, delete to end of input."
 ;;; DELETE CURRENT FILE
 (defun ido-delete-file-at-head ()
   "Delete the file at the head of `ido-matches'.
+Trash the file if `delete-by-moving-to-trash' is non-nil.
 If cursor is not at the end of the user input, delete to end of input."
   (interactive)
   (if (not (eobp))
@@ -3989,8 +4032,9 @@ If cursor is not at the end of the user input, delete to end of input."
                 (file-exists-p file)
                 (not (file-directory-p file))
                 (file-writable-p ido-current-directory)
-                (yes-or-no-p (concat "Delete " file "? ")))
-       (delete-file file)
+                (or delete-by-moving-to-trash
+                    (yes-or-no-p (concat "Delete " file "? "))))
+       (delete-file file 'trash)
        ;; Check if file still exists.
        (if (file-exists-p file)
            ;; file could not be deleted
@@ -4043,8 +4087,8 @@ Record command in `command-history' if optional RECORD is non-nil."
 
 
 (defun ido-buffer-window-other-frame  (buffer)
-  ;; Return window pointer if BUFFER is visible in another frame.
-  ;; If BUFFER is visible in the current frame, return nil.
+  "Return window pointer if BUFFER is visible in another frame.
+If BUFFER is visible in the current frame, return nil."
   (let ((blist (ido-get-buffers-in-frames 'current)))
     ;;If the buffer is visible in current frame, return nil
     (if (member buffer blist)
@@ -4448,11 +4492,6 @@ For details of keybindings, see `ido-find-file'."
          (setq ido-exit 'refresh)
          (exit-minibuffer))
 
-       ;; Update the list of matches
-       (setq ido-text contents)
-       (ido-set-matches)
-       (ido-trace "new    " ido-matches)
-
        (when (and ido-enter-matching-directory
                   ido-matches
                   (or (eq ido-enter-matching-directory 'first)
@@ -4466,6 +4505,32 @@ For details of keybindings, see `ido-find-file'."
          (setq ido-exit 'refresh)
          (exit-minibuffer))
 
+       ;; Update the list of matches
+       (setq ido-text contents)
+       (ido-set-matches)
+       (ido-trace "new    " ido-matches)
+
+       (when (and (boundp 'ido-enable-virtual-buffers)
+                  (not (eq ido-enable-virtual-buffers 'always))
+                  (eq ido-cur-item 'buffer)
+                  (eq ido-use-virtual-buffers 'auto))
+
+         (when (and (not ido-enable-virtual-buffers)
+                    (not ido-matches))
+           (setq ido-text-init ido-text)
+           (setq ido-enable-virtual-buffers t)
+           (setq ido-exit 'refresh)
+           (exit-minibuffer))
+
+         ;; If input matches real buffers turn off virtual buffers.
+         (when (and ido-enable-virtual-buffers
+                    ido-matches
+                    (ido-set-matches-1 (ido-make-buffer-list-1)))
+           (setq ido-enable-virtual-buffers nil)
+           (setq ido-text-init ido-text)
+           (setq ido-exit 'refresh)
+           (exit-minibuffer)))
+
        (when (and (not ido-matches)
                   (not ido-directory-nonreadable)
                   (not ido-directory-too-big)
@@ -4528,9 +4593,8 @@ For details of keybindings, see `ido-find-file'."
        ))))
 
 (defun ido-completions (name)
-  ;; Return the string that is displayed after the user's text.
-  ;; Modified from `icomplete-completions'.
-
+  "Return the string that is displayed after the user's text.
+Modified from `icomplete-completions'."
   (let* ((comps ido-matches)
         (ind (and (consp (car comps)) (> (length (cdr (car comps))) 1)
                   ido-merged-indicator))
@@ -4576,10 +4640,12 @@ For details of keybindings, see `ido-find-file'."
                          (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)))
+                     ;; When there is only one match, show the matching file
+                     ;; name in full, wrapped in [ ... ].
+                     (concat
+                      (or (nth 11 ido-decorations) (nth 4 ido-decorations))
+                      (ido-name (car comps))
+                      (or (nth 12 ido-decorations) (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))
@@ -4641,19 +4707,18 @@ For details of keybindings, see `ido-find-file'."
     (cancel-timer ido-auto-merge-timer)
     (setq ido-auto-merge-timer nil))
 
-  (if (ido-active)
-      (if (and (boundp 'ido-eoinput)
-              ido-eoinput)
-
-         (if (> ido-eoinput (point-max))
-             ;; Oops, got rug pulled out from under us - reinit:
-             (setq ido-eoinput (point-max))
-           (let ((buffer-undo-list t))
-             (delete-region ido-eoinput (point-max))))
-
-       ;; Reestablish the local variable 'cause minibuffer-setup is weird:
-       (make-local-variable 'ido-eoinput)
-       (setq ido-eoinput 1))))
+  (when (ido-active)
+    (if (bound-and-true-p ido-eoinput)
+       (if (> ido-eoinput (point-max))
+           ;; Oops, got rug pulled out from under us - reinit:
+           (setq ido-eoinput (point-max))
+         (let ((inhibit-read-only t)
+               (buffer-undo-list t))
+           (delete-region ido-eoinput (point-max))))
+
+      ;; Reestablish the local variable 'cause minibuffer-setup is weird:
+      (make-local-variable 'ido-eoinput)
+      (setq ido-eoinput 1))))
 
 (defun ido-summary-buffers-to-end ()
   ;; Move the summaries to the end of the buffer list.
@@ -4671,9 +4736,13 @@ For details of keybindings, see `ido-find-file'."
 
 ;;; Helper functions for other programs
 
-(put 'dired-do-rename 'ido 'ignore)
 (put 'ibuffer-find-file 'ido 'find-file)
+(put 'dired 'ido 'dir)
 (put 'dired-other-window 'ido 'dir)
+(put 'dired-other-frame 'ido 'dir)
+;; See http://debbugs.gnu.org/11954 for reasons.
+(put 'dired-do-copy 'ido 'ignore)
+(put 'dired-do-rename 'ido 'ignore)
 
 ;;;###autoload
 (defun ido-read-buffer (prompt &optional default require-match)
@@ -4701,18 +4770,20 @@ See `read-file-name' for additional parameters."
   (let (filename)
     (cond
      ((or (eq predicate 'file-directory-p)
-         (eq (get this-command 'ido) 'dir)
+         (eq (and (symbolp this-command)
+                  (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))
+           (ido-read-directory-name prompt dir default-filename mustmatch initial)))
+     ((and (not (eq (and (symbolp this-command)
+                        (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))
+             (if (eq (and (symbolp this-command)
+                          (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))
@@ -4726,7 +4797,15 @@ See `read-file-name' for additional parameters."
             (ido-find-literal nil))
        (setq ido-exit nil)
        (setq filename
-             (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial))
+             (ido-read-internal 'file prompt 'ido-file-history
+                                (cond  ; Bug#11861.
+                                 ((stringp default-filename) default-filename)
+                                 ((consp default-filename) (car default-filename))
+                                 ((and (not default-filename) initial)
+                                  (expand-file-name initial dir))
+                                 (buffer-file-name buffer-file-name))
+                                mustmatch initial))
+       (setq dir ido-current-directory) ; See bug#1516.
        (cond
         ((eq ido-exit 'fallback)
          (setq filename 'fallback))
@@ -4758,12 +4837,21 @@ See `read-directory-name' for additional parameters."
                                     (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
-       (if (and (stringp filename) (string-equal filename "."))
-           ido-current-directory
-         (concat ido-current-directory filename)))))
+    (setq filename (ido-read-internal
+                   'dir prompt 'ido-file-history
+                   (or default-dirname ; Bug#11861.
+                       (if initial
+                           (expand-file-name initial ido-current-directory)
+                         ido-current-directory))
+                   mustmatch initial))
+    (cond
+     ((eq ido-exit 'fallback)
+      (let ((read-file-name-function nil))
+       (run-hook-with-args 'ido-before-fallback-functions 'read-directory-name)
+       (read-directory-name prompt ido-current-directory
+                            default-dirname mustmatch initial)))
+     ((equal filename ".") ido-current-directory)
+     (t (concat ido-current-directory filename)))))
 
 ;;;###autoload
 (defun ido-completing-read (prompt choices &optional _predicate require-match