--- /dev/null
+;;; ido.el --- interactively do things with buffers and files.
+
+;; Copyright (C) 1996-2002 Free Software Foundation, Inc.
+
+;; Author: Kim F. Storm <storm@cua.dk>
+;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
+;; Keywords: extensions convenience
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with 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.
+
+
+;;; Commentary:
+
+;; Ido - interactive do - switches between buffers and opens files and
+;; directories with a minimum of keystrokes. It is a superset of
+;; iswitchb, the interactive buffer switching package by Stephen Eglen.
+
+;; Interactive substring matching
+;; ------------------------------
+;;
+;; As you type in a substring, the list of buffers or files currently
+;; matching the substring are displayed as you type. The list is
+;; ordered so that the most recent buffers or files visited come at
+;; the start of the list.
+;;
+;; The buffer or file at the start of the list will be the one visited
+;; when you press RETURN. By typing more of the substring, the list is
+;; narrowed down so that gradually the buffer or file you want will be
+;; at the top of the list. Alternatively, you can use C-s and C-r (or
+;; the right and left arrow keys) to rotate buffer or file names in the
+;; list until the one you want is at the top of the list.
+;;
+;; Completion is also available so that you can see what is common to
+;; all of the matching buffers or files as you type.
+;;
+;; Example:
+;;
+;; If I have two buffers called "123456" and "123", with "123456" the
+;; most recent, when I use ido-switch-buffer, I first of all get
+;; presented with the list of all the buffers
+;;
+;; Buffer: {123456,123}
+;;
+;; If I then press 2:
+;; 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 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}
+;;
+;; At this point, I still have two matching buffers.
+;; If I want the first buffer in the list, I simply press RET. If I
+;; wanted the second in the list, I could press C-s to move it to the
+;; 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]
+;;
+;; 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.
+;;
+;; If however, I now 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".
+;;
+;; Of course, where this function comes in really useful is when you
+;; can specify the buffer using only a few keystrokes. In the above
+;; example, the quickest way to get to the "123456" file would be
+;; just to type 4 and then RET (assuming there isn't any newer buffer
+;; with 4 in its name).
+
+;; Likewise, if you use C-x C-f (ido-find-file), the list of files and
+;; directories in the current directory is provided in the same
+;; fashion as the buffers above. The files and directories are
+;; normally sorted in alphabetical order, but the most recently
+;; visited directory is placed first to speed up navigating to
+;; directories that you have visited recently.
+;;
+;; In addition to scrolling through the list using [right] and [left],
+;; you can use [up] and [down] to quickly scroll the list to the next
+;; or previous subdirectory.
+;;
+;; To go down into a subdirectory, and continue the file selection on
+;; the files in that directory, simply move the directory to the head
+;; of the list and hit RET.
+;;
+;; To go up to the parent directory, delete any partial file name
+;; already specified (e.g. using [backspace]) and hit [backspace].
+;;
+;; To go to the root directory (on the current drive), enter two
+;; slashes. On MS-DOS or Windows, to select the root of another
+;; drive, enter X:/ where X is the drive letter. You can also visit
+;; files on other hosts using the ange-ftp notations `/host:' and
+;; `/user@host:'. See the variable `ido-slow-ftp-hosts' if you want
+;; to inhibit the ido substring matching for ftp access.
+;;
+;; If for some reason you cannot specify the proper file using
+;; ido-find-file, you can press C-f to enter the normal find-file.
+;; You can also press C-b to drop into ido-switch-buffer.
+
+;; See the doc string of ido-switch-buffer and ido-find-file for full
+;; keybindings and features.
+;; (describe-function 'ido-find-file)
+
+;; Hidden buffers and files
+;; ------------------------
+;;
+;; Normally, ido does not include hidden buffers (whose name starts
+;; with a space) and hidden files and directories (whose name starts
+;; with `.') in the list of possible completions. However, if the
+;; substring you enter does not match any of the visible buffers or
+;; files, ido will automatically look for completions among the hidden
+;; buffers or files.
+;;
+;; You can toggle display of the hidden buffers and files with C-a.
+
+;; Additional functionality
+;; ------------------------
+;;
+;; After C-x b, the buffer at the head of the list can be killed by
+;; pressing C-k. If the buffer needs saving, you will be queried
+;; before the buffer is killed.
+;;
+;; Likewise, after C-x C-f, you can delete (i.e. physically remove)
+;; the file at the head of the list with C-k. You will always be
+;; asked for confirmation before the file is deleted.
+;;
+;; If you enter C-x b to switch to a buffer visiting a given file, and
+;; you find that the file you are after is not in any buffer, you can
+;; press C-f to immediately drop into ido-find-file. And you can
+;; switch back to buffer selection with C-b.
+
+;; Prefix matching
+;; ---------------
+;;
+;; 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
+;; addition to the default substring-matching-method (look above) also the
+;; 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.
+;;
+;; 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.
+
+;; Flexible matching
+;; -----------------
+;;
+;; If you set ido-enable-flex-matching, ido will do a more flexible
+;; matching (unless regexp matching is active) to find possible matches
+;; among the available buffer or file names if no matches are found using
+;; the normal prefix or substring matching.
+;;
+;; The flexible matching implies that any item which simply contains all
+;; of the entered characters in the specified sequence will match.
+;;
+;; Example:
+;;
+;; If you have four files "alpha", "beta", "gamma", and "delta",
+;; entering "aa" will match "alpha" and "gamma", while "ea" matches
+;; "beta" and "delta". If prefix matching is also active, "aa" only
+;; matches "alpha", while "ea" does not match any files.
+
+;; Regexp matching
+;; ---------------
+;;
+;; 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.
+
+
+;; Customization
+;; -------------
+;;
+;; 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)
+;;
+;;(defun ido-my-keys ()
+;; "Add my keybindings for ido."
+;; (define-key ido-mode-map " " 'ido-next-match)
+;; )
+
+;; Seeing all the matching buffers or files
+;; ----------------------------------------
+;;
+;; If you have many matching files, they may not all fit onto one
+;; line of the minibuffer. Normally, the minibuffer window will grow
+;; to show you more of the matching files (depending on the setting
+;; of the variables `resize-mini-windows' and `max-mini-window-height').
+;; If you want ido to behave differently from the default minibuffer
+;; resizing behaviour, set the variable `ido-max-window-height'.
+;;
+;; Also, to improve the responsiveness of ido, the maximum number of
+;; matching items is limited to 12, but you can increase or removed
+;; this limit via the `ido-max-prospects' variable.
+
+;; To see a full list of all matching buffers in a separate buffer,
+;; hit ? or press TAB when there are no further completions to the
+;; substring. Repeated TAB presses will scroll you through this
+;; separate buffer.
+
+;; Changing the list of files
+;; --------------------------
+
+;; By default, the list of current files is most recent first,
+;; oldest last, with the exception that the files visible in the
+;; current frame are put at the end of the list. A hook exists to
+;; allow other functions to order the list. For example, if you add:
+;;
+;; (add-hook 'ido-make-buffer-list-hook 'ido-summary-buffers-to-end)
+;;
+;; 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.)
+;; Other functions could be made available which alter the list of
+;; matching files (either deleting or rearranging elements.)
+
+;; Highlighting
+;; ------------
+
+;; 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.
+;; Colouring of the matching item was suggested by
+;; Carsten Dominik (dominik@strw.leidenuniv.nl).
+
+;; Replacement for read-buffer and read-file-name
+;; ----------------------------------------------
+
+;; ido-read-buffer and ido-read-file-name have been written to be drop
+;; in replacements for the normal buffer and file name reading
+;; functions `read-buffer' and `read-file-name'.
+
+;; To use ido for all buffer and file selections in Emacs, customize the
+;; variable `ido-everywhere'.
+
+;; Using ido-like behaviour in other lisp packages
+;; -----------------------------------------------
+
+;; If you don't want to rely on the `ido-everywhere' functionality,
+;; ido-read-buffer, ido-read-file-name, and ido-read-directory-name
+;; can be used by other packages to read a buffer name, a file name,
+;; or a directory name in the `ido' way.
+
+
+;;; Code:
+
+(provide 'ido)
+
+;;; User Variables
+;;
+;; These are some things you might want to change.
+
+(defun ido-fractionp (n)
+ (and (numberp n) (> n 0.0) (<= n 1.0)))
+
+(defgroup ido nil
+ "Switch between files using substrings."
+ :group 'extensions
+ :group 'convenience
+ :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:
+- 'buffer: Turn only on ido buffer behavior \(switching, killing,
+ displaying...)
+- 'file: Turn only on ido file behavior \(finding, writing, inserting...)
+- 'both: Turn on ido buffer and file behavior.
+- nil: Turn off any ido switching.
+
+Setting this variable directly does not take effect;
+use either \\[customize] or the function `ido-mode'."
+ :set #'(lambda (symbol value)
+ (ido-mode value))
+ :initialize 'custom-initialize-default
+ :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)
+ (const :tag "Switch off all" nil))
+ :group 'ido)
+
+(defcustom ido-everywhere nil
+ "Use ido everywhere for reading file names and directories.
+Setting this variable directly does not work. Use `customize' or
+call the function `ido-everywhere'."
+ :set #'(lambda (symbol value)
+ (ido-everywhere value))
+ :initialize 'custom-initialize-default
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-case-fold case-fold-search
+ "*Non-nil if searching of buffer and file names should ignore case."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-ignore-buffers
+ '("\\` ")
+ "*List of regexps or functions matching buffer names to ignore.
+For example, traditional behavior is not to list buffers whose names begin
+with a space, for which the regexp is `\\` '. See the source file for
+example functions that filter buffernames."
+ :type '(repeat (choice regexp function))
+ :group 'ido)
+
+(defcustom ido-ignore-files
+ '("\\`CVS/" "\\`#" "\\`.#" "\\`\\.\\./" "\\`\\./")
+ "*List of regexps or functions matching file names to ignore.
+For example, traditional behavior is not to list files whose names begin
+with a #, for which the regexp is `\\`#'. See the source file for
+example functions that filter filenames."
+ :type '(repeat (choice regexp function))
+ :group 'ido)
+
+(defcustom ido-ignore-extensions t
+ "*Non-nil means ignore files in completion-ignored-extensions list."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-show-dot-for-dired nil
+ "*Non-nil means to always put . as the first item in file name lists.
+This allows the current directory to be opened immediate with `dired'."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-ignore-directories
+ '("\\`CVS/" "\\`\\.\\./" "\\`\\./")
+ "*List of regexps or functions matching sub-directory names to ignore."
+ :type '(repeat (choice regexp function))
+ :group 'ido)
+
+(defcustom ido-ignore-directories-merge nil
+ "*List of regexps or functions matching directory path names to ignore during merge.
+Directory paths matched by one of the regexps in this list are not inserted
+in merged file and directory lists."
+ :type '(repeat (choice regexp function))
+ :group 'ido)
+
+;;; Examples for setting the value of ido-ignore-buffers
+;(defun ido-ignore-c-mode (name)
+; "Ignore all c mode buffers -- example function for ido."
+; (save-excursion
+; (set-buffer name)
+; (string-match "^C$" mode-name)))
+;
+;(setq ido-ignore-buffers '("^ " ido-ignore-c-mode))
+
+;;; Examples for setting the value of ido-ignore-files
+;(setq ido-ignore-files '("^ " "\\.c$" "\\.h$"))
+
+(defcustom ido-default-file-method 'always-frame
+ "*How to switch to new file when using `ido-find-file'.
+Possible values:
+`samewindow' Show new file in same window
+`otherwindow' Show new file in another window (same frame)
+`display' Display file in another window without switching to it
+`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.
+`always-frame' If a file is visible in another frame, raise that
+ frame. Otherwise, visit the file in the same window."
+ :type '(choice (const samewindow)
+ (const otherwindow)
+ (const display)
+ (const otherframe)
+ (const maybe-frame)
+ (const always-frame))
+ :group 'ido)
+
+(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."
+ :type '(choice (const samewindow)
+ (const otherwindow)
+ (const display)
+ (const otherframe)
+ (const maybe-frame)
+ (const always-frame))
+ :group 'ido)
+
+(defcustom ido-enable-flex-matching nil
+ "*Non-nil means that `ido' will do flexible string matching.
+Flexible matching means that if the entered string does not
+match any item, any item containing the entered characters
+in the given sequence will match."
+ :type 'boolean
+ :group 'ido)
+
+
+(defcustom ido-enable-regexp nil
+ "*Non-nil means that `ido' will do regexp matching.
+Value can be toggled within `ido' using `ido-toggle-regexp'."
+ :type 'boolean
+ :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).
+Value can be toggled within `ido' using `ido-toggle-prefix'."
+ :type 'boolean
+ :group 'ido)
+
+(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."
+ :type 'boolean
+ :group 'ido)
+
+(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."
+ :type 'integer
+ :group 'ido)
+
+(defcustom ido-max-prompt-path 0.35
+ "*Non-zero means that the prompt string be limited to than number of characters.
+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"
+ :value 0.35
+ :match-alternatives (ido-fractionp)))
+ :group 'ido)
+
+(defcustom ido-max-window-height nil
+ "*Non-nil specifies a value to override `max-mini-window-height'."
+ :type '(choice
+ (const :tag "Don't override" nil)
+ (integer :tag "Number of lines" :value 1)
+ (restricted-sexp
+ :tag "Fraction of window height"
+ :value 0.25
+ :match-alternatives (ido-fractionp)))
+ :group 'ido)
+
+(defcustom ido-enable-last-directory-history t
+ "*Non-nil means that `ido' will remember latest selected directory paths.
+See `ido-last-directory-list' and `ido-save-directory-list-file'."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-max-work-directory-list 50
+ "*Maximum number of working directories to record.
+This is the list of directories where files have most recently been opened.
+See `ido-work-directory-list' and `ido-save-directory-list-file'."
+ :type 'integer
+ :group 'ido)
+
+(defcustom ido-work-directory-list-ignore-regexps nil
+ "*List of regexps matching directories which should not be recorded.
+Directory paths matched by one of the regexps in this list are not inserted in
+the `ido-work-directory-list' list."
+ :type '(repeat regexp)
+ :group 'ido)
+
+(defcustom ido-record-ftp-work-directories t
+ "*Non-nil means that ftp paths are recorded in work directory list."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-merge-ftp-work-directories nil
+ "*Nil means that ftp paths in work directory list are ignored during merge."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-cache-ftp-work-directory-time 1.0
+ "*Maximum time to cache contents of an ftp directory (in hours).
+If zero, ftp directories are not cached."
+ :type 'number
+ :group 'ido)
+
+(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."
+ :type '(repeat string)
+ :group 'ido)
+
+(defcustom ido-slow-ftp-host-regexps nil
+ "*List of regexps matching slow ftp hosts (see `ido-slow-ftp-hosts')."
+ :type '(repeat regexp)
+ :group 'ido)
+
+(defcustom ido-max-work-file-list 10
+ "*Maximum number of names of recently opened files to record.
+This is the list the file names (sans directory) which have most recently
+been opened. See `ido-work-file-list' and `ido-save-directory-list-file'."
+ :type 'integer
+ :group 'ido)
+
+(defcustom ido-work-directory-match-only t
+ "*Non-nil means to skip non-matching directories in the directory history.
+When some text is already entered at the `ido-find-file' prompt, using
+\\[ido-prev-work-directory] or \\[ido-next-work-directory] will skip directories
+without any matching entries."
+ :type 'boolean
+ :group 'ido)
+
+(defcustom ido-auto-merge-work-directories-length 0
+ "*Automatically switch to merged work directories during file name input.
+The value is number of characters to type before switching to merged mode.
+If zero, the switch happens when no matches are found in the current directory.
+Automatic merging is disabled if the value is negative."
+ :type 'integer
+ :group 'ido)
+
+(defcustom ido-auto-merge-delay-time 0.70
+ "*Delay in seconds to wait for more input before doing auto merge."
+ :type 'number
+ :group 'ido)
+
+(defcustom ido-auto-merge-inhibit-characters-regexp "[][*?~]"
+ "*Regexp matching characters which should inhibit automatic merging.
+When a (partial) file name matches this regexp, merging is inhibited."
+ :type 'regexp
+ :group 'ido)
+
+(defcustom ido-merged-indicator "^"
+ "The string appended to first choice if it has multiple directory choices."
+ :type 'string
+ :group 'ido)
+
+(defcustom ido-max-dir-file-cache 100
+ "*Maximum number of working directories to be cached.
+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.
+See also `ido-dir-file-cache' and `ido-save-directory-list-file'."
+ :type 'integer
+ :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 nil
+ "*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."
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "When typing /" slash)
+ (other :tag "Always" t))
+ :group 'ido)
+
+Non-nil means if typing / results in only one matching directory, enter it
+(defcustom ido-create-new-buffer 'prompt
+ "*Specify whether a new buffer is created if no buffer matches substring.
+Choices are 'always to create new buffers unconditionally, 'prompt to
+ask user whether to create buffer, or 'never to never create new buffer."
+ :type '(choice (const always)
+ (const prompt)
+ (const never))
+ :group 'ido)
+
+(defcustom ido-define-mode-map-hook nil
+ "*Hook to define keys in `ido-mode-map' for extra keybindings."
+ :type 'hook
+ :group 'ido)
+
+(defcustom ido-separator nil
+ "*String used by ido to separate the alternatives in the minibuffer.
+Obsolete. Set 3rd element of `ido-decorations' instead."
+ :type 'string
+ :group 'ido)
+
+(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]")
+ "*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:
+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)."
+ :type '(repeat string)
+ :group 'ido)
+
+(defcustom ido-use-faces t
+ "*Non-nil means use ido faces to highlighting first match, only match and
+subdirs in the alternatives."
+ :type 'boolean
+ :group 'ido)
+
+(defface ido-first-match-face '((t (:bold t)))
+ "*Font used by ido for highlighting first match."
+ :group 'ido)
+
+(defface ido-only-match-face '((((class color))
+ (:foreground "ForestGreen"))
+ (t (:italic t)))
+ "*Font used by ido for highlighting only match."
+ :group 'ido)
+
+(defface ido-subdir-face '((((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))
+ (:foreground "yellow"
+ :background "red"
+ :width condensed))
+ (t (:inverse-video t)))
+ "*Font used by ido for highlighting its indicators."
+ :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
+`ido-temp-list' which contains the current list of matching files."
+ :type 'hook
+ :group 'ido)
+
+(defcustom ido-make-dir-list-hook nil
+ "*List of functions to run when the list of matching directories is created.
+Each function on the list may modify the dynamically bound variable
+`ido-temp-list' which contains the current list of matching directories."
+ :type 'hook
+ :group 'ido)
+
+(defcustom ido-make-buffer-list-hook nil
+ "*List of functions to run when the list of matching buffers is created.
+Each function on the list may modify the dynamically bound variable
+`ido-temp-list' which contains the current list of matching buffer names."
+ :type 'hook
+ :group 'ido)
+
+(defcustom ido-make-file-prompt-hook nil
+ "*List of functions to run when the find-file prompt is created.
+Each function on the list may modify the following dynamically bound
+variables:
+ path - the (abbreviated) directory path
+ max-width - the max width of the path; set to nil to inhibit truncation
+ prompt - the basic prompt (e.g. \"Find File: \")
+ literal - the string shown if doing `literal' find; set to nil to omit
+ vc-off - the string shown if version control is inhibited; set to nit to omit
+ prefix - normally nil, but may be set to a fixed prefix for the path
+The following variables are available, but should not be changed:
+ ido-current-directory - the unabbreviated directory path
+ item - equals 'file or 'dir depending on the current mode."
+ :type 'hook
+ :group 'ido)
+
+(defvar ido-rewrite-prompt-path-rules nil
+ "*Alist of rewriting rules for file paths.
+A list of elements of the form (FROM . TO) or (FROM . FUNC),
+each meaning to rewrite the path if matched by FROM by either
+substituting the matched string by TO or calling the function
+FUNC with the current path as its only argument and using the
+return value as the new path. In addition, each FUNC may
+also modify the dynamic variables described for the
+variable `ido-make-file-prompt-hook'.")
+
+(defcustom ido-completion-buffer "*Ido Completions*"
+ "*Name of completion buffer used by ido.
+Set to nil to disable completion buffers popping up."
+ :type 'string
+ :group 'ido)
+
+(defcustom ido-completion-buffer-all-completions nil
+ "*Non-nil means to show all completions in completion buffer.
+Otherwise, only the current list of matches is shown."
+ :type 'boolean
+ :group 'ido)
+
+(defvar ido-all-frames 'visible
+ "*Argument to pass to `walk-windows' when finding visible files.
+See documentation of `walk-windows' for useful values.")
+
+(defcustom ido-minibuffer-setup-hook nil
+ "*Ido-specific customization of minibuffer setup.
+
+This hook is run during minibuffer setup iff `ido' will be active.
+It is intended for use in customizing ido for interoperation
+with other packages. For instance:
+
+ \(add-hook 'ido-minibuffer-setup-hook
+ \(function
+ \(lambda ()
+ \(make-local-variable 'resize-minibuffer-window-max-height)
+ \(setq resize-minibuffer-window-max-height 3))))
+
+will constrain rsz-mini to a maximum minibuffer height of 3 lines when
+ido is running. Copied from `icomplete-minibuffer-setup-hook'."
+ :type 'hook
+ :group 'ido)
+
+(defcustom ido-save-directory-list-file "~/.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'.
+Must be set before enabling ido mode."
+ :type 'string
+ :group 'ido)
+
+(defcustom ido-read-file-name-as-directory-commands '()
+ "List of commands which uses read-file-name to read a directory path.
+When `ido-everywhere' is non-nil, the commands in this list will read
+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."
+ :type '(repeat symbol)
+ :group 'ido)
+
+;;; Internal Variables
+
+;; Persistent variables
+
+(defvar ido-mode-map nil
+ "Keymap for `ido-find-file' and `ido-switch-buffer'.")
+
+(defvar ido-file-history nil
+ "History of files selected using `ido-find-file'.")
+
+(defvar ido-buffer-history nil
+ "History of buffers selected using `ido-switch-buffer'.")
+
+(defvar ido-xemacs (string-match "XEmacs" (emacs-version))
+ "Non-nil if we are running XEmacs. Otherwise, assume we are running Emacs.")
+
+(defvar ido-last-directory-list nil
+ "List of last selected directory paths.
+See `ido-enable-last-directory-history' for details.")
+
+(defvar ido-work-directory-list nil
+ "List of actual working directory paths.
+The current directory is inserted at the front of this list whenever a
+file is opened with ido-find-file and family.")
+
+(defvar ido-work-file-list nil
+ "List of actual work file names.
+The current file name (sans path) is inserted at the front of this list
+whenever a file is opened with ido-find-file and family.")
+
+(defvar ido-dir-file-cache nil
+ "List of file-name-all-completions results.
+Each element in the list is of the form (dir (mtime) file...).")
+
+;; Temporary storage
+
+(defvar ido-eoinput 1
+ "Point where minibuffer input ends and completion info begins.
+Copied from `icomplete-eoinput'.")
+(make-variable-buffer-local 'ido-eoinput)
+
+(defvar ido-common-match-string nil
+ "Stores the string that is common to all matching files.")
+
+(defvar ido-rescan nil
+ "Non-nil means we need to regenerate the list of matching items.")
+
+(defvar ido-rotate nil
+ "Non-nil means we are rotating list of matches.")
+
+(defvar ido-text nil
+ "Stores the users string as it is typed in.")
+
+(defvar ido-text-init nil
+ "The initial string for the users string it is typed in.")
+
+(defvar ido-matches nil
+ "List of files currently matching `ido-text'.")
+
+(defvar ido-report-no-match t
+ "Report [No Match] when no completions matches ido-text.")
+
+(defvar ido-exit nil
+ "Flag to monitor how `ido-find-file' exits.
+If equal to `takeprompt', we use the prompt as the file name to be
+selected.")
+
+(defvar ido-current-directory nil
+ "Current directory for ido-find-file.")
+
+(defvar ido-auto-merge-timer nil
+ "Delay timer for auto merge.")
+
+(defvar ido-use-mycompletion-depth 0
+ "Non-nil means use `ido' completion feedback.
+Is set by ido functions to the current minibuffer-depth, so that
+it doesn't interfere with other minibuffer usage.")
+
+
+;;; Variables with dynamic bindings.
+;;; Declared here to keep the byte compiler quiet.
+
+;; Stores the current ido item type ('file, 'dir or 'buffer).
+(defvar ido-cur-item)
+
+;; Stores the current list of items that will be searched through.
+;; The list is ordered, so that the most interesting item comes first,
+;; although by default, the files visible in the current frame are put
+;; at the end of the list. Created by `ido-make-item-list'.
+(defvar ido-cur-list)
+
+;; Stores the list of items which are ignored when building
+;; `ido-cur-list'. It is in no specific order.
+(defvar ido-ignored-list)
+
+;; Keep current item list if non-nil.
+(defvar ido-keep-item-list)
+
+;; Process ido-ignore-* lists.
+(defvar ido-process-ignore-lists)
+
+;; Don't process ido-ignore- lists once.
+(defvar ido-process-ignore-lists-inhibit)
+
+;; Buffer from which ido was entered.
+(defvar ido-entry-buffer)
+
+;; Non-nil if matching file must be selected.
+(defvar ido-require-match)
+
+;; Stores a temporary version of the file list being created.
+(defvar ido-temp-list)
+
+;; Non-nil if default list element should be rotated into place.
+(defvar ido-rotate-temp)
+
+;; Stores current index in ido-work-directory-list.
+(defvar ido-work-directory-index)
+
+;; Stores current index in ido-work-file-list.
+(defvar ido-work-file-index)
+
+;; Set when merged work directory list is in use.
+(defvar ido-use-merged-list)
+
+;; Set when merged work directory list not yet built.
+(defvar ido-try-merged-list)
+
+;; Saved state prior to last work directory merge.
+;; 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)
+
+;; Stores temporary state of literal find file.
+(defvar ido-find-literal)
+
+
+;;; FUNCTIONS
+
+(defun ido-active (&optional merge)
+ (if merge
+ ido-use-merged-list
+ (and (boundp 'ido-completing-read) (= ido-use-mycompletion-depth (minibuffer-depth)))))
+
+(defvar ido-trace-enable nil)
+
+(defun ido-trace (p &optional s retval)
+ (if ido-trace-enable
+ (let ((b (get-buffer-create " *IDO Trace*"))
+ (deactivate-mark deactivate-mark))
+ (save-excursion
+ (save-restriction
+ (set-buffer b)
+ (insert p ": " (if (stringp s) s (format "%S" s)) "\n")))))
+ retval)
+
+(defun ido-toggle-trace (arg)
+ (interactive "P")
+ (setq ido-trace-enable (or arg (not ido-trace-enable)))
+ (let ((b (get-buffer " *IDO Trace*")))
+ (if b
+ (if ido-trace-enable
+ (kill-buffer b)
+ (pop-to-buffer b t t)))))
+
+(defun ido-is-root-directory (&optional dir)
+ (setq dir (or dir ido-current-directory))
+ (if (memq system-type '(windows-nt ms-dos))
+ (string-match "\\`[a-zA-Z]:[/\\]\\'" dir)
+ (string-equal "/" dir)))
+
+(defun ido-is-ftp-directory (&optional dir)
+ (string-match "\\`/[^/:][^/:]+:/" (or dir ido-current-directory)))
+
+(defun ido-is-slow-ftp-host (&optional dir)
+ (and (or ido-slow-ftp-hosts ido-slow-ftp-host-regexps)
+ (setq dir (or dir ido-current-directory))
+ ;; (featurep 'ange-ftp)
+ ;; (ange-ftp-ftp-name dir)
+ (string-match "\\`/\\([^/:]*@\\)?\\([^@/:][^@/:]+\\):/" dir)
+ (let ((host (substring dir (match-beginning 2) (match-end 2))))
+ (or (member host ido-slow-ftp-hosts)
+ (let ((re ido-slow-ftp-host-regexps))
+ (while (and re (not (string-match (car re) host)))
+ (setq re (cdr re)))
+ re)))))
+
+(defun ido-time-stamp (&optional time)
+ ;; Time is a floating point number (fractions of 1 hour)
+ (setq time (or time (current-time)))
+ (/ (+ (* (car time) 65536.0) (car (cdr time))) 3600.0))
+
+(defun ido-cache-ftp-valid (&optional time)
+ (and (numberp ido-cache-ftp-work-directory-time)
+ (> ido-cache-ftp-work-directory-time 0)
+ (or (not time)
+ (< (- (ido-time-stamp) time) ido-cache-ftp-work-directory-time))))
+
+(defun ido-may-cache-directory (&optional dir)
+ (setq dir (or dir ido-current-directory))
+ (if (and (memq system-type '(windows-nt ms-dos))
+ (string-match "\\`[a-zA-Z]:[/\\]\\'" dir))
+ nil
+ (or (not (ido-is-ftp-directory dir))
+ (ido-cache-ftp-valid))))
+
+(defun ido-pp (list &optional sep)
+ (let ((print-level nil) (eval-expression-print-level nil)
+ (print-length nil) (eval-expression-print-length nil))
+ (insert "\n;; ----- " (symbol-name list) " -----\n(\n ")
+ (setq list (symbol-value list))
+ (while list
+ (let* ((elt (car list))
+ (s (if (consp elt) (car elt) elt)))
+ (if (and (stringp s) (= (length s) 0))
+ (setq s nil))
+ (if s
+ (prin1 elt (current-buffer)))
+ (if (and (setq list (cdr list)) s)
+ (insert (or sep "\n ")))))
+ (insert "\n)\n")))
+
+(defun ido-save-history ()
+ "Save ido history and cache information between sessions."
+ (interactive)
+ (if (and ido-last-directory-list ido-save-directory-list-file)
+ (save-excursion
+ (save-window-excursion
+ (if (find-buffer-visiting ido-save-directory-list-file)
+ (kill-buffer (find-buffer-visiting ido-save-directory-list-file)))
+ (if (file-exists-p ido-save-directory-list-file)
+ (delete-file ido-save-directory-list-file))
+ (set-buffer (let ((enable-local-variables nil))
+ (find-file-noselect ido-save-directory-list-file t)))
+ (goto-char (point-min))
+ (delete-region (point-min) (point-max))
+ (ido-pp 'ido-last-directory-list)
+ (ido-pp 'ido-work-directory-list)
+ (ido-pp 'ido-work-file-list)
+ (ido-pp 'ido-dir-file-cache "\n\n ")
+ (insert "\n")
+ (let ((version-control 'never))
+ (write-file ido-save-directory-list-file nil))
+ (kill-buffer (current-buffer))))))
+
+(defun ido-load-history (&optional arg)
+ "Load ido history and cache information from previous session.
+With prefix argument, reload history unconditionally."
+ (interactive "P")
+ (if (or arg (and ido-save-directory-list-file (not ido-last-directory-list)))
+ (let ((file (expand-file-name ido-save-directory-list-file))
+ buf)
+ (when (file-readable-p file)
+ (save-excursion
+ (save-window-excursion
+ (setq buf (set-buffer (let ((enable-local-variables nil))
+ (find-file-noselect file))))
+ (goto-char (point-min))
+ (condition-case nil
+ (setq ido-last-directory-list (read (current-buffer))
+ ido-work-directory-list (read (current-buffer))
+ ido-work-file-list (read (current-buffer))
+ ido-dir-file-cache (read (current-buffer)))
+ (error nil))))
+ (kill-buffer buf))))
+ (ido-wash-history))
+
+(defun ido-wash-history ()
+ "Clean-up ido history and cache information.
+Removes badly formatted data and ignored directories."
+ (interactive)
+ ;; Check format of each of our lists, discard bogus elements
+ (setq ido-last-directory-list
+ (and (listp ido-last-directory-list)
+ (let ((l ido-last-directory-list) r)
+ (while l
+ (if (and (consp (car l))
+ (stringp (car (car l)))
+ (stringp (cdr (car l))))
+ (setq r (cons (car l) r)))
+ (setq l (cdr l)))
+ (nreverse r))))
+ (setq ido-work-directory-list
+ (and (listp ido-work-directory-list)
+ (let ((l ido-work-directory-list) r)
+ (while l
+ (if (and (stringp (car l))
+ (or ido-record-ftp-work-directories
+ (not (ido-is-ftp-directory (car l)))))
+ (setq r (cons (car l) r)))
+ (setq l (cdr l)))
+ (nreverse r))))
+ (setq ido-work-file-list
+ (and (listp ido-work-file-list)
+ (let ((l ido-work-file-list) r)
+ (while l
+ (if (stringp (car l))
+ (setq r (cons (car l) r)))
+ (setq l (cdr l)))
+ (nreverse r))))
+ (setq ido-dir-file-cache
+ (and (listp ido-dir-file-cache)
+ (let ((l ido-dir-file-cache) r)
+ (while l
+ (if (and (listp (car l))
+ (> (length (car l)) 2)
+ (let ((dir (car (car l)))
+ (time (car (cdr (car l))))
+ (files (cdr (cdr (car l)))))
+ (and
+ (stringp dir)
+ (consp time)
+ (if (integerp (car time))
+ (and (/= (car time) 0)
+ (integerp (car (cdr time)))
+ (/= (car (cdr time)) 0)
+ (ido-may-cache-directory dir))
+ (and (eq (car time) 'ftp)
+ (numberp (cdr time))
+ (ido-is-ftp-directory dir)
+ (ido-cache-ftp-valid (cdr time))))
+ (let ((s files) (ok t))
+ (while s
+ (if (stringp (car s))
+ (setq s (cdr s))
+ (setq s nil ok nil)))
+ ok))))
+ (setq r (cons (car l) r)))
+ (setq l (cdr l)))
+ (nreverse r))))
+
+ ;; Remove ignored directories from work directory list
+ ;; according to ido-work-directory-list-ignore-regexps
+ (if ido-work-directory-list
+ (let ((dirs (reverse ido-work-directory-list)))
+ (setq ido-work-directory-list nil)
+ (while dirs
+ (ido-record-work-directory (car dirs))
+ (setq dirs (cdr dirs)))))
+ ;; Get rid of text properties
+ (let ((l ido-last-directory-list) e)
+ (while l
+ (setq e (car l) l (cdr l))
+ (set-text-properties 0 (length (car e)) nil (car e))
+ (set-text-properties 0 (length (cdr e)) nil (cdr e))))
+ (let ((l ido-work-directory-list) e)
+ (while l
+ (setq e (car l) l (cdr l))
+ (set-text-properties 0 (length e) nil e)))
+ (let ((l ido-work-file-list) e)
+ (while l
+ (setq e (car l) l (cdr l))
+ (set-text-properties 0 (length e) nil e)))
+ (let ((l ido-dir-file-cache) e d)
+ (while l
+ (setq e (car l) l (cdr l))
+ (if (listp e)
+ (while e
+ (setq d (car e) e (cdr e))
+ (if (not (consp d))
+ (set-text-properties 0 (length d) nil d))))))
+)
+
+
+(defun ido-kill-emacs-hook ()
+ ;; ido kill emacs hook
+ (ido-save-history))
+
+(defvar ido-minor-mode-map-entry nil)
+
+;;;###autoload
+(defun ido-mode (&optional arg nobind)
+ "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.
+This function also adds a hook to the minibuffer."
+ (interactive "P")
+ (setq ido-mode
+ (cond
+ ((null arg) (if ido-mode nil 'both))
+ ((eq arg t) 'both)
+ ((eq arg 'files) 'file)
+ ((eq arg 'buffers) 'buffer)
+ ((memq arg '(file buffer both)) arg)
+ ((> (prefix-numeric-value arg) 0) 'both)
+ (t nil)))
+
+ (ido-everywhere (if ido-everywhere 1 -1))
+
+ (when ido-mode
+ (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
+ (add-hook 'choose-completion-string-functions 'ido-choose-completion-string)
+ (ido-load-history)
+
+ (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)))
+ (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)
+ (define-key map [remap find-alternate-file] 'ido-find-alternate-file)
+ (define-key map [remap write-file] 'ido-write-file)
+ (define-key map [remap insert-file] 'ido-insert-file)
+ (define-key map [remap list-directory] 'ido-list-directory)
+ (define-key map [remap dired] 'ido-dired)
+ (define-key map [remap find-file-other-window] 'ido-find-file-other-window)
+ (define-key map [remap find-file-read-only-other-window] 'ido-find-file-read-only-other-window)
+ (define-key map [remap find-file-other-frame] 'ido-find-file-other-frame)
+ (define-key map [remap find-file-read-only-other-frame] 'ido-find-file-read-only-other-frame))
+
+ (when (memq ido-mode '(buffer both))
+ (define-key map [remap switch-to-buffer] 'ido-switch-buffer)
+ (define-key map [remap switch-to-buffer-other-window] 'ido-switch-buffer-other-window)
+ (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)))))
+
+(defun ido-everywhere (arg)
+ "Enable ido everywhere file and directory names are read."
+ (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)))
+
+
+;;; 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))
+ (define-key map "\C-a" 'ido-toggle-ignore)
+ (define-key map "\C-c" 'ido-toggle-case)
+ (define-key map "\C-e" 'ido-edit-input)
+ (define-key map "\t" 'ido-complete)
+ (define-key map "\C-j" 'ido-select-text)
+ (define-key map "\C-m" 'ido-exit-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-t" 'ido-toggle-regexp)
+ (define-key map "\C-z" 'ido-undo-merge-work-directory)
+ (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)
+ )
+
+ (setq ido-mode-map map)
+ (run-hooks 'ido-define-mode-map-hook)))
+
+(defun ido-final-slash (dir &optional fix-it)
+ ;; return DIR if DIR has final slash.
+ ;; else if FIX-IT is non-nil, return DIR/
+ ;; else return nil.
+ (setq dir (ido-name dir))
+ (cond
+ ((string-match "/\\'" dir) dir)
+ (fix-it (concat dir "/"))
+ (t nil)))
+
+(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))
+ (setq ido-use-merged-list nil
+ ido-try-merged-list (not no-merge))
+ (if subdir
+ (setq dir (ido-final-slash (concat dir subdir) 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))
+ t))
+
+(defun ido-set-current-home (&optional dir)
+ ;; Set ido's current directory to user's home directory
+ (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
+ (let ((cmd (list command arg)))
+ (if (or (not command-history)
+ (not (equal cmd (car command-history))))
+ (setq command-history (cons cmd command-history))))))
+
+(defun ido-make-prompt (item prompt)
+ ;; Make the prompt for ido-read-internal
+ (cond
+ ((and (memq item '(file dir)) ido-current-directory)
+ (let ((path (abbreviate-file-name ido-current-directory))
+ (max-width (if (and ido-max-prompt-path (floatp ido-max-prompt-path))
+ (floor (* (frame-width) ido-max-prompt-path))
+ ido-max-prompt-path))
+ (literal (and (boundp 'ido-find-literal) ido-find-literal "(literal) "))
+ (vc-off (and ido-saved-vc-mt (not vc-master-templates) "[-VC] "))
+ (prefix nil)
+ (rule ido-rewrite-prompt-path-rules))
+ (let ((case-fold-search nil))
+ (while rule
+ (if (and (consp (car rule))
+ (string-match (car (car rule)) path))
+ (setq path
+ (if (stringp (cdr (car rule)))
+ (replace-match (cdr (car rule)) t nil path)
+ (funcall (cdr (car rule)) path))))
+ (setq rule (cdr rule))))
+ (run-hooks 'ido-make-file-prompt-hook)
+ (concat prompt
+ ; (if ido-process-ignore-lists "" "&")
+ (or literal "")
+ (or vc-off "")
+ (or prefix "")
+ (let ((l (length path)))
+ (if (and max-width (> max-width 0) (> l max-width))
+ (let* ((s (substring path (- max-width)))
+ (i (string-match "/" s)))
+ (concat "..." (if i (substring s i) s)))
+ path)))))
+ (t prompt)))
+
+;; Here is very briefly how ido-find-file works:
+;;
+;; (ido-find-file)
+;; (ido-file-internal method)
+;; set ido-current-directory
+;; (ido-read-internal 'file ...)
+;; (while ...
+;; (ido-make-item-list ...)
+;; (ido-set-matches)
+;; (completing-read ... ido-text-init ...)
+;;
+;; ... here user is allowed to type characters and commands
+;; a command may set ido-exit and call (exit-minibuffer)
+;; to make ido-read-internal do advanced tasks (or return)
+;;
+;; ... ido-tidy and ido-exhibit are pre- and post-hooks
+;; which are run before and after each user command.
+;;
+;; return value from completing-read is stored in ido-final-text
+;; - ido-exit may cause further actions to be taken:
+;; 'refresh - repeat loop (make-item-list, set-matches)
+;; 'edit - edit the prompt string, then repeat loop
+;; 'keep - repeat loop but don't (re)make-item-list
+;; 'updir - go up one directory, repeat loop
+;; else set ido-selected based on ido-final-text,
+;; optionally update ido-current-directory and repeat loop, or
+;; exit with the return value of ido-selected (file name)
+;; selected file name is returned from ido-read-internal,
+;; ido-exit and method determines what action is taken
+;; e.g. the file name may be ignored or joined with ido-current-directory, and
+;; the relevant function is called (find-file, write-file, etc).
+
+(defun ido-read-internal (item prompt history &optional default require-match initial)
+ "Perform the ido-read-buffer and ido-read-file-name functions.
+Return the name of a buffer or file selected.
+PROMPT is the prompt to give to the user.
+DEFAULT if given is the default directory to start with.
+If REQUIRE-MATCH is non-nil, an existing file must be selected.
+If INITIAL is non-nil, it specifies the initial input string."
+ (let
+ ((ido-cur-item item)
+ (ido-entry-buffer (current-buffer))
+ (ido-process-ignore-lists t)
+ (ido-process-ignore-lists-inhibit nil)
+ (ido-set-default-item t)
+ ido-default-item
+ ido-selected
+ ido-final-text
+ (done nil)
+ (icomplete-mode nil) ;; prevent icomplete starting up
+ ;; Exported dynamic variables:
+ ido-cur-list
+ ido-ignored-list
+ (ido-rotate-temp nil)
+ (ido-keep-item-list nil)
+ (ido-use-merged-list nil)
+ (ido-try-merged-list t)
+ (ido-pre-merge-state nil)
+ (ido-case-fold ido-case-fold)
+ (ido-enable-prefix ido-enable-prefix)
+ (ido-enable-regexp ido-enable-regexp)
+ )
+
+ (ido-define-mode-map)
+ (setq ido-text-init initial)
+ (while (not done)
+ (ido-trace "\n_LOOP_")
+ (setq ido-exit nil)
+ (setq ido-rescan t)
+ (setq ido-rotate nil)
+ (setq ido-text "")
+ (if ido-set-default-item
+ (setq ido-default-item
+ (cond
+ ((eq item 'buffer)
+ (if (bufferp default) (buffer-name default) default))
+ ((stringp default) default)
+ ((eq item 'file)
+ (and ido-enable-last-directory-history
+ (let ((d (assoc ido-current-directory ido-last-directory-list)))
+ (and d (cdr d))))))
+ ido-set-default-item nil))
+
+ (if ido-process-ignore-lists-inhibit
+ (setq ido-process-ignore-lists nil))
+
+ (if (and ido-use-merged-list (memq ido-try-merged-list '(t wide)) (not ido-keep-item-list))
+ (let ((olist ido-cur-list)
+ (oign ido-ignored-list)
+ (omat ido-matches)
+ (l (ido-make-merged-file-list ido-text-init
+ (eq ido-use-merged-list 'auto)
+ (eq ido-try-merged-list 'wide))))
+ (cond
+ ((not l)
+ (if (eq ido-try-merged-list 'wide)
+ (setq ido-pre-merge-state
+ (list "" ido-current-directory olist oign omat)
+ ido-cur-list nil
+ ido-ignored-list nil
+ ido-matches nil
+ ido-keep-item-list t
+ ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil)
+ ido-use-merged-list nil)
+ (setq ido-cur-list olist
+ ido-ignored-list oign
+ ido-matches omat
+ ido-keep-item-list t
+ ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil)
+ ido-use-merged-list nil)))
+ ((eq l t)
+ (setq ido-use-merged-list nil))
+ (t
+ (setq ido-pre-merge-state
+ (list ido-text-init ido-current-directory olist oign omat))
+ (ido-set-current-directory (car (cdr (car l))))
+ (if (ido-final-slash ido-text-init)
+ (setq ido-text-init ""))
+ (setq ido-cur-list l
+ ido-ignored-list nil
+ ido-matches l
+ ido-rescan nil
+ ido-keep-item-list t
+ ido-use-merged-list t)
+ (ido-trace "Merged" t)
+ ))))
+
+ (cond
+ (ido-keep-item-list
+ (setq ido-keep-item-list nil
+ ido-rescan nil))
+ ((eq ido-cur-item 'file)
+ (setq ido-ignored-list nil
+ ido-cur-list (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)))
+ ((eq ido-cur-item 'buffer)
+ (setq ido-ignored-list nil
+ ido-cur-list (ido-make-buffer-list ido-default-item)))
+ (t nil))
+ (setq ido-rotate-temp nil)
+
+ (if ido-process-ignore-lists-inhibit
+ (setq ido-process-ignore-lists t
+ ido-process-ignore-lists-inhibit nil))
+
+ (ido-set-matches)
+ (if (and ido-matches (eq ido-try-merged-list 'auto))
+ (setq ido-try-merged-list t))
+ (let
+ ((minibuffer-local-completion-map ido-mode-map)
+ (max-mini-window-height (or ido-max-window-height
+ (and (boundp 'max-mini-window-height) max-mini-window-height)))
+ (ido-completing-read t)
+ (ido-require-match require-match)
+ (ido-use-mycompletion-depth (1+ (minibuffer-depth)))
+ (show-paren-mode nil))
+ ;; prompt the user for the file name
+ (setq ido-exit nil)
+ (setq ido-final-text
+ (catch 'ido
+ (completing-read
+ (ido-make-prompt item prompt)
+ '(("dummy".1)) nil nil ; table predicate require-match
+ (prog1 ido-text-init (setq ido-text-init nil)) ;initial-contents
+ history))))
+ (ido-trace "completing-read" ido-final-text)
+ (if (get-buffer ido-completion-buffer)
+ (kill-buffer ido-completion-buffer))
+
+ (ido-trace "\n_EXIT_" ido-exit)
+
+ (cond
+ ((eq ido-exit 'refresh)
+ (if (and (eq ido-use-merged-list 'auto)
+ (or (input-pending-p)))
+ (setq ido-use-merged-list nil
+ ido-keep-item-list t))
+ nil)
+
+ ((eq ido-exit 'done)
+ (setq done t
+ ido-selected ido-text
+ ido-exit nil))
+
+ ((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)
+ (edit (eq ido-exit 'edit))
+ (d ido-current-directory)
+ (f ido-text-init)
+ (path t))
+ (setq ido-text-init "")
+ (while path
+ (setq path (if edit
+ (read-file-name (concat prompt "[EDIT] ") d (concat d f) nil f)
+ f)
+ d (or (file-name-directory path) "/")
+ f (file-name-nondirectory path)
+ edit t)
+ (if (or
+ (file-directory-p d)
+ (and (yes-or-no-p (format "Create directory %s? " d))
+ (condition-case nil
+ (progn (make-directory d t) t)
+ (error
+ (message "Could not create directory")
+ (sit-for 1)
+ nil))))
+ (progn
+ (ido-set-current-directory d nil (eq ido-exit 'chdir))
+ (setq ido-text-init f
+ path nil))))))
+ (t
+ (setq ido-text-init nil)
+ (setq ido-text-init (read-string (concat prompt "[EDIT] ") ido-final-text))))
+ nil)
+
+ ((eq ido-exit 'keep)
+ (setq ido-keep-item-list t))
+
+ ((memq ido-exit '(dired fallback findfile findbuffer))
+ (setq done t))
+
+ ((eq ido-exit 'updir)
+ ;; cannot go up if already at the root-dir (Unix) or at the
+ ;; root-dir of a certain drive (Windows or MS-DOS).
+ (or (ido-is-root-directory)
+ (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))))
+ (setq ido-set-default-item t))
+
+ ;; Handling the require-match must be done in a better way.
+ ((and require-match (not (ido-existing-item-p)))
+ (error "must specify valid item"))
+
+ (t
+ (setq ido-selected
+ (if (and ido-matches (equal ido-final-text ""))
+ (ido-name (car ido-matches)) ;; possibly choose the default file
+ (if (or (eq ido-exit 'takeprompt)
+ (null ido-matches))
+ ido-final-text
+ ;; else take head of list
+ (ido-name (car ido-matches)))))
+
+ (cond
+ ((eq item 'buffer)
+ (setq done t))
+
+ ((string-equal "./" ido-selected)
+ nil)
+
+ ((string-equal "../" ido-selected)
+ ;; cannot go up if already at the root-dir (Unix) or at the
+ ;; root-dir of a certain drive (Windows or MS-DOS).
+ (or (ido-is-root-directory)
+ (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))))
+ (setq ido-set-default-item t))
+
+ ((and (string-equal ido-current-directory "/")
+ (string-match "..:\\'" ido-selected)) ;; Ange-ftp
+ (ido-set-current-directory "/" ido-selected)
+ (if (ido-is-slow-ftp-host)
+ (setq ido-exit 'fallback
+ done t)
+ (setq ido-set-default-item t)))
+
+ ((or (string-match "[/\\][^/\\]" ido-selected)
+ (and (memq system-type '(windows-nt ms-dos))
+ (string-match "\\`.:" ido-selected)))
+ (ido-set-current-directory (file-name-directory ido-selected))
+ (setq ido-set-default-item t))
+
+ ((string-match "\\`~" ido-selected)
+ (ido-set-current-home ido-selected))
+
+ ((ido-final-slash ido-selected)
+ (if ido-enable-last-directory-history
+ (let ((x (assoc ido-current-directory ido-last-directory-list)))
+ (if x
+ (setcdr x ido-selected)
+ (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))
+
+ (t
+ (setq done t))))))
+ ido-selected))
+
+(defun ido-edit-input ()
+ "Edit ido path and input string. Terminate by RET."
+ (interactive)
+ (setq ido-text-init ido-text)
+ (setq ido-exit 'edit)
+ (exit-minibuffer))
+
+;;; MAIN FUNCTIONS
+(defun ido-buffer-internal (method &optional fallback prompt default initial)
+ ;; 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)))
+
+ ;; Choose the buffer name: either the text typed in, or the head
+ ;; of the list of matches
+
+ (cond
+ ((eq ido-exit 'findfile)
+ (ido-file-internal ido-default-file-method nil nil nil nil ido-text))
+
+ ((eq ido-exit 'fallback)
+ (let ((read-buffer-function nil))
+ (call-interactively (or fallback 'switch-to-buffer))))
+
+ ;; Check buf is non-nil.
+ ((not buf) nil)
+
+ ;; View buffer if it exists
+ ((get-buffer buf)
+ (if (eq method 'insert)
+ (progn
+ (ido-record-command 'insert-buffer buf)
+ (insert-buffer buf))
+ (ido-visit-buffer buf method t)))
+
+ ;; buffer doesn't exist
+ ((eq ido-create-new-buffer 'never)
+ (message "no buffer matching `%s'" buf))
+
+ ((and (eq ido-create-new-buffer 'prompt)
+ (not (y-or-n-p (format "No buffer matching `%s', create one? " buf))))
+ nil)
+
+ ;; create a new buffer
+ (t
+ (setq buf (get-buffer-create buf))
+ (if (fboundp 'set-buffer-major-mode)
+ (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))
+ (let ((items ido-work-directory-list-ignore-regexps)
+ (case-fold-search nil))
+ (while (and items dir)
+ (if (string-match (car items) dir)
+ (setq dir nil))
+ (setq items (cdr items)))
+ (if dir
+ (setq ido-work-directory-list (cons dir (delete dir ido-work-directory-list))))))
+ (if (> (length ido-work-directory-list) ido-max-work-directory-list)
+ (setcdr (nthcdr (1- ido-max-work-directory-list) ido-work-directory-list) nil))))
+
+(defun ido-forget-work-directory ()
+ (interactive)
+ (when (and ido-current-directory ido-work-directory-list)
+ (setq ido-work-directory-list (delete ido-current-directory ido-work-directory-list))
+ (when ido-use-merged-list
+ (ido-undo-merge-work-directory)
+ (setq ido-exit 'refresh
+ ido-try-merged-list t
+ ido-use-merged-list t
+ ido-text-init ido-text
+ ido-rotate-temp t)
+ (exit-minibuffer))))
+
+(defun ido-record-work-file (name)
+ ;; Save NAME in ido-work-file-list
+ (when (and (numberp ido-max-work-file-list) (> ido-max-work-file-list 0))
+ (or
+ (and ido-work-file-list (equal (car ido-work-file-list) name))
+ (setq ido-work-file-list (cons name (delete name ido-work-file-list))))
+ (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)
+ ;; Internal function for ido-find-file and friends
+ (let ((ido-current-directory (expand-file-name (or default default-directory)))
+ 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-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)
+ (or prompt "Find file: ")
+ 'ido-file-history nil nil initial)))
+
+ ;; Choose the file name: either the text typed in, or the head
+ ;; of the list of matches
+
+ (cond
+ ((eq ido-exit 'fallback)
+ ;; Need to guard setting of default-directory here, since
+ ;; we don't want to change directory of current buffer.
+ (let ((default-directory ido-current-directory)
+ (read-file-name-function nil))
+ (call-interactively (or fallback 'find-file))))
+
+ ((eq ido-exit 'findbuffer)
+ (ido-buffer-internal ido-default-buffer-method nil nil nil ido-text))
+
+ ((eq ido-exit 'dired)
+ (dired (concat ido-current-directory (or ido-text ""))))
+
+ ((eq method 'alt-file)
+ (ido-record-work-file filename)
+ (setq default-directory ido-current-directory)
+ (ido-record-work-directory)
+ (find-alternate-file filename))
+
+ ((memq method '(dired list-directory))
+ (if (equal filename ".")
+ (setq filename ""))
+ (let* ((path (ido-final-slash (concat ido-current-directory filename) t))
+ (file (substring path 0 -1)))
+ (cond
+ ((file-directory-p path)
+ (ido-record-command method path)
+ (ido-record-work-directory path)
+ (funcall method path))
+ ((file-directory-p ido-current-directory)
+ (cond
+ ((file-exists-p file)
+ (ido-record-command method ido-current-directory)
+ (ido-record-work-directory)
+ (funcall method ido-current-directory)
+ (if (eq method 'dired)
+ (dired-goto-file (expand-file-name file))))
+ ((string-match "[[*?]" filename)
+ (setq path (concat ido-current-directory filename))
+ (ido-record-command method path)
+ (ido-record-work-directory)
+ (funcall method path))
+ ((y-or-n-p (format "Directory %s does not exist. Create it " filename))
+ (ido-record-command method path)
+ (ido-record-work-directory path)
+ (make-directory-internal path)
+ (funcall method path))
+ (t
+ ;; put make-directory command on history
+ (ido-record-command 'make-directory path))))
+ (t (error "No such directory")))))
+
+ ((eq method 'write)
+ (ido-record-work-file filename)
+ (setq default-directory ido-current-directory)
+ (ido-record-command 'write-file (concat ido-current-directory filename))
+ (ido-record-work-directory)
+ (write-file filename))
+
+ ((eq method 'read-only)
+ (ido-record-work-file filename)
+ (setq filename (concat ido-current-directory filename))
+ (ido-record-command fallback filename)
+ (ido-record-work-directory)
+ (funcall fallback filename))
+
+ ((eq method 'insert)
+ (ido-record-work-file filename)
+ (setq filename (concat ido-current-directory filename))
+ (ido-record-command
+ (if ido-find-literal 'insert-file-literally 'insert-file)
+ filename)
+ (ido-record-work-directory)
+ (if ido-find-literal
+ (insert-file-contents-literally filename)
+ (insert-file-contents filename)))
+
+ (filename
+ (ido-record-work-file filename)
+ (setq filename (concat ido-current-directory filename))
+ (ido-record-command 'find-file filename)
+ (ido-record-work-directory)
+ (ido-visit-buffer (find-file-noselect filename nil ido-find-literal) method))))))
+
+(defun ido-existing-item-p ()
+ ;; Return non-nil if there is a matching item
+ (not (null ido-matches)))
+
+;;; COMPLETION CODE
+
+(defun ido-set-common-completion ()
+ ;; Find common completion of `ido-text' in `ido-matches'
+ ;; The result is stored in `ido-common-match-string'
+ (let* (val)
+ (setq ido-common-match-string nil)
+ (if (and ido-matches
+ (not ido-enable-regexp) ;; testing
+ (stringp ido-text)
+ (> (length ido-text) 0))
+ (if (setq val (ido-find-common-substring ido-matches ido-text))
+ (setq ido-common-match-string val)))
+ val))
+
+(defun ido-complete ()
+ "Try and complete the current pattern amongst the file names."
+ (interactive)
+ (let (res)
+ (cond
+ ((and (memq ido-cur-item '(file dir))
+ (string-match "[$]" ido-text))
+ (let ((evar (substitute-in-file-name (concat ido-current-directory ido-text))))
+ (if (not (file-exists-p (file-name-directory evar)))
+ (message "Expansion generates non-existing directory path")
+ (if (file-directory-p evar)
+ (ido-set-current-directory evar)
+ (let ((d (or (file-name-directory evar) "/"))
+ (f (file-name-nondirectory evar)))
+ (when (file-directory-p d)
+ (ido-set-current-directory d)
+ (setq ido-text-init f))))
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))))
+
+ ((not ido-matches)
+ (when ido-completion-buffer
+ (setq this-command 'ido-completion-help)
+ (ido-completion-help)))
+
+ ((= 1 (length ido-matches))
+ ;; only one choice, so select it.
+ (exit-minibuffer))
+
+ (t ;; else there could be some completions
+ (setq res ido-common-match-string)
+ (if (and (not (memq res '(t nil)))
+ (not (equal res ido-text)))
+ ;; found something to complete, so put it in the minibuffer.
+ (progn
+ ;; move exact match to front if not in prefix mode
+ (setq ido-rescan (not ido-enable-prefix))
+ (delete-region (minibuffer-prompt-end) (point))
+ (insert res))
+ ;; else nothing to complete
+ (ido-completion-help)
+ )))))
+
+(defun ido-undo-merge-work-directory (&optional text try refresh)
+ "Undo or redo last ido directory merge operation.
+If no merge has yet taken place, toggle automatic merging option."
+ (interactive)
+ (cond
+ (ido-pre-merge-state
+ (ido-set-current-directory (nth 1 ido-pre-merge-state))
+ (setq ido-text-init (or text (car ido-pre-merge-state))
+ ido-cur-list (nth 2 ido-pre-merge-state)
+ ido-ignored-list (nth 3 ido-pre-merge-state)
+ ido-matches (nth 4 ido-pre-merge-state)
+ ido-use-merged-list nil
+ ido-try-merged-list try
+ ido-keep-item-list (not refresh)
+ ido-rescan nil
+ ido-exit 'refresh
+ ido-pre-merge-state nil)
+ (exit-minibuffer))
+ (text
+ nil)
+ (ido-try-merged-list
+ (setq ido-try-merged-list nil))
+ (ido-matches
+ (setq ido-try-merged-list t))
+ ((not ido-use-merged-list)
+ (ido-merge-work-directories))))
+
+;;; TOGGLE FUNCTIONS
+
+(defun ido-toggle-case ()
+ "Toggle the value of `ido-case-fold'."
+ (interactive)
+ (setq ido-case-fold (not ido-case-fold))
+ ;; ask for list to be regenerated.
+ (setq ido-rescan t))
+
+(defun ido-toggle-regexp ()
+ "Toggle the value of `ido-enable-regexp'."
+ (interactive)
+ (setq ido-enable-regexp (not ido-enable-regexp))
+ ;; ask for list to be regenerated.
+ (setq ido-rescan t))
+
+(defun ido-toggle-prefix ()
+ "Toggle the value of `ido-enable-prefix'."
+ (interactive)
+ (setq ido-enable-prefix (not ido-enable-prefix))
+ ;; ask for list to be regenerated.
+ (setq ido-rescan t))
+
+(defun ido-toggle-ignore ()
+ "Toggle ignoring files specified with `ido-ignore-files'."
+ (interactive)
+ (setq ido-process-ignore-lists (not ido-process-ignore-lists))
+ (setq ido-text-init ido-text)
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))
+
+(defun ido-toggle-vc ()
+ "Disable version control for this file."
+ (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 ido-text-init ido-text)
+ (setq ido-exit 'keep)
+ (exit-minibuffer))))
+
+(defun ido-toggle-literal ()
+ "Toggle literal reading of this file."
+ (interactive)
+ (if (and ido-mode (eq ido-cur-item 'file))
+ (progn
+ (setq ido-find-literal (not ido-find-literal))
+ (setq ido-text-init ido-text)
+ (setq ido-exit 'keep)
+ (exit-minibuffer))))
+
+(defun ido-reread-directory ()
+ "Read current directory again.
+May be useful if cached version is no longer valid, but directory
+timestamp has not changed (e.g. with ftp or on Windows)."
+ (interactive)
+ (if (and ido-mode (eq ido-cur-item 'file))
+ (progn
+ (ido-remove-cached-dir ido-current-directory)
+ (setq ido-text-init ido-text)
+ (setq ido-rotate-temp t)
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))))
+
+(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)))
+
+(defun ido-select-text ()
+ "Select the buffer or file named by the prompt.
+If no buffer or file exactly matching the prompt exists, maybe create a new one."
+ (interactive)
+ (setq ido-exit 'takeprompt)
+ (exit-minibuffer))
+
+(defun ido-fallback-command ()
+ "Fallback to non-ido version of current command."
+ (interactive)
+ (setq ido-exit 'fallback)
+ (exit-minibuffer))
+
+(defun ido-enter-find-file ()
+ "Drop into find-file from buffer switching."
+ (interactive)
+ (setq ido-exit 'findfile)
+ (exit-minibuffer))
+
+(defun ido-enter-switch-buffer ()
+ "Drop into ido-switch-buffer from file switching."
+ (interactive)
+ (setq ido-exit 'findbuffer)
+ (exit-minibuffer))
+
+(defun ido-enter-dired ()
+ "Drop into dired from file switching."
+ (interactive)
+ (setq ido-exit 'dired)
+ (exit-minibuffer))
+
+
+(defun ido-up-directory (&optional clear)
+ "Go up one directory level."
+ (interactive "P")
+ (setq ido-text-init (if clear nil ido-text))
+ (setq ido-exit 'updir)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer))
+
+(defun ido-delete-backward-updir (count)
+ "Delete char backwards, or at beginning of buffer, go up one level."
+ (interactive "P")
+ (cond
+ ((= (minibuffer-prompt-end) (point))
+ (if (not count)
+ (ido-up-directory t)))
+ ((and ido-pre-merge-state (string-equal (car ido-pre-merge-state) ido-text))
+ (ido-undo-merge-work-directory (substring ido-text 0 -1) t t))
+ (t
+ (delete-backward-char (prefix-numeric-value count)))))
+
+(defun ido-delete-backward-word-updir (count)
+ "Delete all chars backwards, or at beginning of buffer, go up one level."
+ (interactive "P")
+ (if (= (minibuffer-prompt-end) (point))
+ (if (not count)
+ (ido-up-directory t))
+ (backward-kill-word (prefix-numeric-value count))))
+
+(defun ido-get-work-directory (&optional incr must-match)
+ (let ((n (length ido-work-directory-list))
+ (i ido-work-directory-index)
+ (j 0)
+ dir)
+ (if (or (not ido-text) (= (length ido-text) 0))
+ (setq must-match nil))
+ (while (< j n)
+ (setq i (+ i incr)
+ j (1+ j))
+ (if (> incr 0)
+ (if (>= i n) (setq i 0))
+ (if (< i 0) (setq i (1- n))))
+ (setq dir (nth i ido-work-directory-list))
+ (if (and dir
+ (not (equal dir ido-current-directory))
+ (file-directory-p dir)
+ (or (not must-match)
+ (ido-set-matches1
+ (if (eq ido-cur-item 'file)
+ (ido-make-file-list1 dir)
+ (ido-make-dir-list1 dir)))))
+ (setq j n)
+ (setq dir nil)))
+ (if dir
+ (setq ido-work-directory-index i))
+ dir))
+
+(defun ido-prev-work-directory ()
+ "Change to next working directory in list."
+ (interactive)
+ (let ((dir (ido-get-work-directory 1 ido-work-directory-match-only)))
+ (when dir
+ (ido-set-current-directory dir)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init ido-text)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer))))
+
+(defun ido-next-work-directory ()
+ "Change to previous working directory in list."
+ (interactive)
+ (let ((dir (ido-get-work-directory -1 ido-work-directory-match-only)))
+ (when dir
+ (ido-set-current-directory dir)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init ido-text)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer))))
+
+(defun ido-merge-work-directories ()
+ "Search (and merge) work directories for files matching the current input string."
+ (interactive)
+ (setq ido-use-merged-list t ido-try-merged-list t)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init ido-text)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer))
+
+(defun ido-wide-find-file (&optional file)
+ "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)))
+ (when (> (length file) 0)
+ (setq ido-use-merged-list t ido-try-merged-list 'wide)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init file)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer)))
+
+(defun ido-wide-find-dir (&optional dir)
+ "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)))
+ (when (> (length dir) 0)
+ (setq ido-use-merged-list t ido-try-merged-list 'wide)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init (ido-final-slash dir t))
+ (setq ido-rotate-temp t)
+ (exit-minibuffer)))
+
+(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)))
+ (when (> (length dir) 0)
+ (setq dir (concat ido-current-directory dir))
+ (unless (file-exists-p dir)
+ (make-directory dir t)
+ (ido-set-current-directory dir)
+ (setq ido-exit 'refresh)
+ (setq ido-text-init nil)
+ (setq ido-rotate-temp t)
+ (exit-minibuffer))))
+
+(defun ido-get-work-file (incr)
+ (let ((n (length ido-work-file-list))
+ (i (+ ido-work-file-index incr))
+ name)
+ (if (> incr 0)
+ (if (>= i n) (setq i 0))
+ (if (< i 0) (setq i (1- n))))
+ (setq name (nth i ido-work-file-list))
+ (setq ido-work-file-index i)
+ name))
+
+(defun ido-prev-work-file ()
+ "Change to next working file name in list."
+ (interactive)
+ (let ((name (ido-get-work-file 1)))
+ (when name
+ (setq ido-text-init name)
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))))
+
+(defun ido-next-work-file ()
+ "Change to previous working file name in list."
+ (interactive)
+ (let ((name (ido-get-work-file -1)))
+ (when name
+ (setq ido-text-init name)
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))))
+
+(defun ido-copy-current-file-name (all)
+ "Insert file name of current buffer.
+If repeated, insert text from buffer instead."
+ (interactive "P")
+ (let* ((path (buffer-file-name ido-entry-buffer))
+ (name (and path (file-name-nondirectory path))))
+ (when name
+ (setq ido-text-init
+ (if (or all
+ (not (equal (file-name-directory path) ido-current-directory))
+ (not (string-match "\\.[^.]*\\'" name)))
+ name
+ (substring name 0 (1+ (match-beginning 0)))))
+ (setq ido-exit 'refresh
+ ido-try-merged-list nil)
+ (exit-minibuffer))))
+
+(defun ido-copy-current-word (all)
+ "Insert current word (file name or path) from current buffer."
+ (interactive "P")
+ (let ((word (save-excursion
+ (set-buffer ido-entry-buffer)
+ (let ((p (point)) start-line end-line start-name name)
+ (beginning-of-line)
+ (setq start-line (point))
+ (end-of-line)
+ (setq end-line (point))
+ (goto-char p)
+ (if (re-search-backward "[^-_a-zA-Z0-9:./\\~@]" start-line 1)
+ (forward-char 1))
+ (setq start-name (point))
+ (re-search-forward "[-_a-zA-Z0-9:./\\~@]*" end-line 1)
+ (if (= start-name (point))
+ nil
+ (buffer-substring-no-properties start-name (point)))))))
+ (if (cond
+ ((not word) nil)
+ ((string-match "\\`[~/]" word)
+ (setq ido-text-init word
+ ido-try-merged-list nil
+ ido-exit 'chdir))
+ ((string-match "/" word)
+ (setq ido-text-init (concat ido-current-directory word)
+ ido-try-merged-list nil
+ ido-exit 'chdir))
+ (t
+ (setq ido-text-init word
+ ido-try-merged-list nil
+ ido-exit 'refresh)))
+ (exit-minibuffer))))
+
+(defun ido-next-match ()
+ "Put first element of `ido-matches' at the end of the list."
+ (interactive)
+ (if ido-matches
+ (let ((next (cadr ido-matches)))
+ (setq ido-cur-list (ido-chop ido-cur-list next))
+ (setq ido-rescan t)
+ (setq ido-rotate t))))
+
+(defun ido-prev-match ()
+ "Put last element of `ido-matches' at the front of the list."
+ (interactive)
+ (if ido-matches
+ (let ((prev (car (last ido-matches))))
+ (setq ido-cur-list (ido-chop ido-cur-list prev))
+ (setq ido-rescan t)
+ (setq ido-rotate t))))
+
+(defun ido-next-match-dir ()
+ "Find next directory in match list.
+If work directories have been merged, cycle through directories for
+first matching file."
+ (interactive)
+ (if ido-use-merged-list
+ (if ido-matches
+ (let* ((elt (car ido-matches))
+ (dirs (cdr elt)))
+ (when (> (length dirs) 1)
+ (setcdr elt (ido-chop dirs (cadr dirs))))
+ (setq ido-rescan nil)))
+ (let ((cnt (length ido-matches))
+ (i 1))
+ (while (and (< i cnt) (not (ido-final-slash (nth i ido-matches))))
+ (setq i (1+ i)))
+ (if (< i cnt)
+ (setq ido-cur-list (ido-chop ido-cur-list (nth i ido-matches)))))))
+
+(defun ido-prev-match-dir ()
+ "Find previous directory in match list.
+If work directories have been merged, cycle through directories
+for first matching file."
+ (interactive)
+ (if ido-use-merged-list
+ (if ido-matches
+ (let* ((elt (car ido-matches))
+ (dirs (cdr elt)))
+ (when (> (length dirs) 1)
+ (setcdr elt (ido-chop dirs (car (last dirs)))))
+ (setq ido-rescan nil)))
+ (let* ((cnt (length ido-matches))
+ (i (1- cnt)))
+ (while (and (> i 0) (not (ido-final-slash (nth i ido-matches))))
+ (setq i (1- i)))
+ (if (> i 0)
+ (setq ido-cur-list (ido-chop ido-cur-list (nth i ido-matches)))))))
+
+(defun ido-chop (items elem)
+ "Remove all elements before ELEM and put them at the end of ITEMS."
+ (let ((ret nil)
+ (next nil)
+ (sofar nil))
+ (while (not ret)
+ (setq next (car items))
+ (if (equal next elem)
+ (setq ret (append items (nreverse sofar)))
+ ;; else
+ (progn
+ (setq items (cdr items))
+ (setq sofar (cons next sofar)))))
+ ret))
+
+(defun ido-name (item)
+ ;; Return file name for current item, whether in a normal list
+ ;; or a merged work directory list.
+ (if (consp item) (car item) item))
+
+
+;;; CREATE LIST OF ALL CURRENT FILES
+
+(defun ido-all-completions ()
+ ;; Return unsorted list of all competions.
+ (let ((ido-process-ignore-lists nil))
+ (cond
+ ((eq ido-cur-item 'file)
+ (ido-make-file-list1 ido-current-directory))
+ ((eq ido-cur-item 'dir)
+ (ido-make-dir-list1 ido-current-directory))
+ ((eq ido-cur-item 'buffer)
+ (ido-make-buffer-list1))
+ (t nil))))
+
+
+(defun ido-sort-list (items)
+ ;; Simple list of file or buffer names
+ (sort items (lambda (a b) (string-lessp a b))))
+
+(defun ido-sort-merged-list (items promote)
+ ;; Input is list of ("file" . "dir") cons cells.
+ ;; Output is sorted list of ("file "dir" ...) lists
+ (let ((l (sort items (lambda (a b) (string-lessp (car b) (car a)))))
+ res a cur dirs)
+ (while l
+ (setq a (car l)
+ l (cdr l))
+ (if (and res (string-equal (car (car res)) (car a)))
+ (progn
+ (setcdr (car (if cur (cdr res) res)) (cons (cdr a) (cdr (car res))))
+ (if (and promote (string-equal ido-current-directory (cdr a)))
+ (setq cur t)))
+ (setq res (cons (list (car a) (cdr a)) res)
+ cur nil)))
+ res))
+
+(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 ((paths
+ (split-string
+ (shell-command-to-string
+ (concat "find " dir " -name \"" (if prefix "" "*") file "*\" -type " (if finddir "d" "f") " -print"))))
+ path d f
+ res)
+ (while paths
+ (setq path (car paths)
+ paths (cdr paths)
+ paths (cdr paths))
+ (if (and (string-match "^/" path)
+ (file-exists-p path))
+ (setq d (file-name-directory path)
+ f (file-name-nondirectory path)
+ res (cons (cons (if finddir (ido-final-slash f t) f) d) res))))
+ res))
+
+(defun ido-flatten-merged-list (items)
+ ;; Create a list of path names based on a merged directory list.
+ (let (res)
+ (while items
+ (let* ((item (car items))
+ (file (car item))
+ (dirs (cdr item)))
+ (while dirs
+ (setq res (cons (concat (car dirs) file) res)
+ dirs (cdr dirs))))
+ (setq items (cdr items)))
+ res))
+
+(defun ido-make-merged-file-list (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
+ ido-current-directory (substring text 0 -1) ido-enable-prefix t))
+ ;; Use list of cached directories
+ (let ((re (concat (regexp-quote (substring text 0 -1)) "[^/:]*/\\'"))
+ (dirs ido-dir-file-cache)
+ dir b d f)
+ (if nil ;; simple
+ (while dirs
+ (setq dir (car (car dirs))
+ dirs (cdr dirs))
+ (when (and (string-match re dir)
+ (not (ido-ignore-item-p dir ido-ignore-directories-merge))
+ (file-directory-p dir))
+ (setq b (substring dir 0 -1)
+ f (concat (file-name-nondirectory b) "/")
+ d (file-name-directory b)
+ res (cons (cons f d) res))))
+ (while dirs
+ (setq dir (car dirs)
+ d (car dir)
+ dirs (cdr dirs))
+ (when (not (ido-ignore-item-p d ido-ignore-directories-merge))
+ (setq dir (cdr (cdr dir)))
+ (while dir
+ (setq f (car dir)
+ dir (cdr dir))
+ (if (and (string-match re f)
+ (not (ido-ignore-item-p f ido-ignore-directories)))
+ (setq res (cons (cons f d) res)))))
+ (if (and auto (input-pending-p))
+ (setq dirs nil
+ res t))))))
+ (if wide
+ (setq res (ido-wide-find-dirs-or-files
+ ido-current-directory text ido-enable-prefix nil))
+ (let ((ido-text text)
+ (dirs ido-work-directory-list)
+ (must-match (and text (> (length text) 0)))
+ dir fl)
+ (if (and auto (not (member ido-current-directory dirs)))
+ (setq dirs (cons ido-current-directory dirs)))
+ (while dirs
+ (setq dir (car dirs)
+ dirs (cdr dirs))
+ (when (and dir (stringp dir)
+ (or ido-merge-ftp-work-directories
+ (not (ido-is-ftp-directory dir)))
+ (file-directory-p dir)
+ (setq fl (if (eq ido-cur-item 'file)
+ (ido-make-file-list1 dir t)
+ (ido-make-dir-list1 dir t))))
+ (if must-match
+ (setq fl (ido-set-matches1 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)))
+ (message nil)
+ res))
+
+(defun ido-make-buffer-list1 (&optional frame visible)
+ ;; Return list of non-ignored buffer names
+ (delq nil
+ (mapcar
+ (lambda (x)
+ (let ((name (buffer-name x)))
+ (if (not (or (ido-ignore-item-p name ido-ignore-buffers) (memq name visible)))
+ name)))
+ (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-buflist-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)))
+ (if ido-temp-list
+ (nconc ido-temp-list ido-current-buffers)
+ (setq ido-temp-list ido-current-buffers))
+ (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-buffer-list-hook)
+ ido-temp-list))
+
+(defun ido-to-end (items)
+ ;; Move the elements from ITEMS to the end of `ido-temp-list'
+ (mapcar
+ (lambda (elem)
+ (setq ido-temp-list (delq elem ido-temp-list)))
+ items)
+ (if ido-temp-list
+ (nconc ido-temp-list items)
+ (setq ido-temp-list items)))
+
+(defun ido-file-name-all-completions (dir)
+ ;; Return name of all files in DIR
+ ;; Uses and updates ido-dir-file-cache
+ (if (and (numberp ido-max-dir-file-cache) (> ido-max-dir-file-cache 0)
+ (stringp dir) (> (length dir) 0)
+ (ido-may-cache-directory dir))
+ (let* ((cached (assoc dir ido-dir-file-cache))
+ (ctime (nth 1 cached))
+ (ftp (ido-is-ftp-directory dir))
+ (attr (if ftp nil (file-attributes dir)))
+ (mtime (nth 5 attr))
+ valid)
+ (when cached ; should we use the cached entry ?
+ (if ftp
+ (setq valid (and (eq (car ctime) 'ftp)
+ (ido-cache-ftp-valid (cdr ctime))))
+ (if attr
+ (setq valid (and (= (car ctime) (car mtime))
+ (= (car (cdr ctime)) (car (cdr mtime)))))))
+ (if (not valid)
+ (setq ido-dir-file-cache (delq cached ido-dir-file-cache)
+ cached nil)))
+ (unless cached
+ (if (and ftp (file-readable-p dir))
+ (setq mtime (cons 'ftp (ido-time-stamp))))
+ (if mtime
+ (setq cached (cons dir (cons mtime (file-name-all-completions "" 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))))
+ (file-name-all-completions "" dir)))
+
+(defun ido-remove-cached-dir (dir)
+ ;; 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)))
+ (if cached
+ (setq ido-dir-file-cache (delq cached ido-dir-file-cache))))))
+
+
+(defun ido-make-file-list1 (dir &optional merged)
+ ;; Return list of non-ignored files in DIR
+ ;; If MERGED is non-nil, each file is cons'ed with DIR
+ (and (file-directory-p dir)
+ (delq nil
+ (mapcar
+ (lambda (name)
+ (if (not (ido-ignore-item-p name ido-ignore-files t))
+ (if merged (cons name dir) name)))
+ (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.
+ (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) (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))
+ ido-temp-list)))
+ (if (and default (member default ido-temp-list))
+ (if (or ido-rotate-temp ido-rotate-file-list-default)
+ (unless (equal default (car ido-temp-list))
+ (let ((l ido-temp-list) k)
+ (while (and l (cdr l) (not (equal default (car (cdr l)))))
+ (setq l (cdr l)))
+ (setq k (cdr l))
+ (setcdr l nil)
+ (nconc k ido-temp-list)
+ (setq ido-temp-list k)))
+ (setq ido-temp-list
+ (delete default ido-temp-list))
+ (setq ido-temp-list
+ (cons default ido-temp-list))))
+ (when ido-show-dot-for-dired
+ (setq ido-temp-list (delete "." ido-temp-list))
+ (setq ido-temp-list (cons "." ido-temp-list)))
+ (run-hooks 'ido-make-file-list-hook)
+ ido-temp-list))
+
+(defun ido-make-dir-list1 (dir &optional merged)
+ ;; Return list of non-ignored subdirs in DIR
+ ;; If MERGED is non-nil, each subdir is cons'ed with DIR
+ (and (file-directory-p dir)
+ (delq nil
+ (mapcar
+ (lambda (name)
+ (and (ido-final-slash name) (not (ido-ignore-item-p name ido-ignore-directories))
+ (if merged (cons name dir) name)))
+ (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.
+ (let ((ido-temp-list (ido-make-dir-list1 ido-current-directory)))
+ (setq ido-temp-list (ido-sort-list ido-temp-list))
+ (let ((default-directory ido-current-directory))
+ (ido-to-end ;; move visited files to end
+ (delq nil (mapcar
+ (lambda (x) (if (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))
+ ido-temp-list)))
+ (if (and default (member default ido-temp-list))
+ (if (or ido-rotate-temp ido-rotate-file-list-default)
+ (unless (equal default (car ido-temp-list))
+ (let ((l ido-temp-list) k)
+ (while (and l (cdr l) (not (equal default (car (cdr l)))))
+ (setq l (cdr l)))
+ (setq k (cdr l))
+ (setcdr l nil)
+ (nconc k ido-temp-list)
+ (setq ido-temp-list k)))
+ (setq ido-temp-list
+ (delete default ido-temp-list))
+ (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))
+ (run-hooks 'ido-make-dir-list-hook)
+ ido-temp-list))
+
+;; List of the files visible in the current frame.
+(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'.
+ (let ((ido-bufs-in-frame nil))
+ (walk-windows 'ido-get-bufname nil
+ (if current
+ nil
+ ido-all-frames))
+ ido-bufs-in-frame))
+
+(defun ido-get-bufname (win)
+ ;; Used by `ido-get-buffers-in-frames' to walk through all windows
+ (let ((buf (buffer-name (window-buffer win))))
+ (if (not (member buf ido-bufs-in-frame))
+ ;; Only add buf if it is not already in list.
+ ;; This prevents same buf in two different windows being
+ ;; put into the list twice.
+ (setq ido-bufs-in-frame
+ (cons buf ido-bufs-in-frame)))))
+
+;;; FIND MATCHING ITEMS
+
+(defun ido-set-matches1 (items &optional do-full)
+ ;; Return list of matches in items
+ (let* ((case-fold-search ido-case-fold)
+ (rexq (if ido-enable-regexp ido-text (regexp-quote ido-text)))
+ (re (if ido-enable-prefix (concat "\\`" rexq) rexq))
+ (full-re (and do-full (not ido-enable-regexp) (not (string-match "\$\\'" re))
+ (concat "\\`" re "\\'")))
+ (prefix-re (and full-re (not ido-enable-prefix)
+ (concat "\\`" rexq)))
+ 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)
+ (if prefix-matches
+ (setq matches (nconc prefix-matches matches)))
+ (if full-matches
+ (setq matches (nconc full-matches matches)))
+ (when (and (null matches)
+ ido-enable-flex-matching
+ (> (length ido-text) 1)
+ (not ido-enable-regexp))
+ (setq re (mapconcat 'identity (split-string ido-text "") ".*"))
+ (if ido-enable-prefix
+ (setq re (concat "\\`" re)))
+ (mapcar
+ (lambda (item)
+ (let ((name (ido-name item)))
+ (if (string-match re name)
+ (setq matches (cons item matches)))))
+ items))
+ matches))
+
+
+(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))
+ 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.
+ (and ido-process-ignore-lists re-list
+ (let ((data (match-data))
+ (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)))
+
+
+;; Private variable used by `ido-word-matching-substring'.
+(defvar ido-change-word-sub)
+
+(defun ido-find-common-substring (items subs)
+ ;; Return common string following SUBS in each element of ITEMS.
+ (let (res
+ alist
+ ido-change-word-sub)
+ (setq ido-change-word-sub
+ (if ido-enable-regexp
+ subs
+ (regexp-quote subs)))
+ (setq res (mapcar 'ido-word-matching-substring items))
+ (setq res (delq nil res)) ;; remove any nil elements (shouldn't happen)
+ (setq alist (mapcar 'ido-makealist res)) ;; could use an OBARRAY
+
+ ;; try-completion returns t if there is an exact match.
+ (let ((completion-ignore-case ido-case-fold))
+
+ (try-completion subs alist))))
+
+(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.
+ (let ((case-fold-search ido-case-fold))
+ (let ((m (string-match ido-change-word-sub (ido-name word))))
+ (if m
+ (substring (ido-name word) m)
+ ;; else no match
+ nil))))
+
+(defun ido-makealist (res)
+ ;; Return dotted pair (RES . 1).
+ (cons res 1))
+
+(defun ido-choose-completion-string (choice buffer mini-p base-size)
+ (when (ido-active)
+ ;; Insert the completion into the buffer where completion was requested.
+ (if (get-buffer ido-completion-buffer)
+ (kill-buffer ido-completion-buffer))
+ (cond
+ ((ido-active t) ;; ido-use-merged-list
+ (setq ido-current-directory ""
+ ido-text choice
+ ido-exit 'done))
+ ((not (ido-final-slash choice))
+ (setq ido-text choice
+ ido-exit 'done))
+ (t
+ (ido-set-current-directory ido-current-directory choice)
+ (setq ido-exit 'refresh)))
+ (exit-minibuffer)
+ t))
+
+(defun ido-completion-help ()
+ "Show possible completions in a *File Completions* buffer."
+ (interactive)
+ (setq ido-rescan nil)
+ (let ((temp-buf (get-buffer ido-completion-buffer))
+ display-it full-list)
+ (if (and (eq last-command this-command) temp-buf)
+ ;; scroll buffer
+ (let (win (buf (current-buffer)))
+ (display-buffer temp-buf nil nil)
+ (set-buffer temp-buf)
+ (setq win (get-buffer-window temp-buf))
+ (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)
+ (setq full-list t
+ display-it t))
+ (scroll-other-window))
+ (set-buffer buf))
+ (setq display-it t))
+ (if display-it
+ (with-output-to-temp-buffer ido-completion-buffer
+ (let ((completion-list (ido-sort-list
+ (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)))))))
+ (if ido-xemacs
+ ;; XEmacs extents are put on by default, doesn't seem to be
+ ;; any way of switching them off.
+ (display-completion-list completion-list
+ :help-string "ido "
+ :activate-callback
+ '(lambda (x y z) (message "doesn't work yet, sorry!")))
+ ;; else running Emacs
+ ;;(add-hook 'completion-setup-hook 'completion-setup-function)
+ (display-completion-list completion-list)))))))
+
+;;; KILL CURRENT BUFFER
+(defun ido-kill-buffer-at-head ()
+ "Kill the buffer at the head of `ido-matches'."
+ (interactive)
+ (let ((enable-recursive-minibuffers t)
+ (buf (car ido-matches)))
+ (when buf
+ (kill-buffer buf)
+ ;; Check if buffer still exists.
+ (if (get-buffer buf)
+ ;; buffer couldn't be killed.
+ (setq ido-rescan t)
+ ;; else buffer was killed so remove name from list.
+ (setq ido-cur-list (delq buf ido-cur-list))))))
+
+;;; DELETE CURRENT FILE
+(defun ido-delete-file-at-head ()
+ "Delete the file at the head of `ido-matches'."
+ (interactive)
+ (let ((enable-recursive-minibuffers t)
+ (file (car ido-matches)))
+ (if file
+ (setq file (concat ido-current-directory file)))
+ (when (and file
+ (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)
+ ;; Check if file still exists.
+ (if (file-exists-p file)
+ ;; file could not be deleted
+ (setq ido-rescan t)
+ ;; else file was killed so remove name from list.
+ (setq ido-cur-list (delq (car ido-matches) ido-cur-list))))))
+
+
+;;; 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."
+
+ (let (win newframe)
+ (cond
+ ((eq method 'kill)
+ (if record
+ (ido-record-command 'kill-buffer buffer))
+ (kill-buffer buffer))
+
+ ((eq method 'samewindow)
+ (if record
+ (ido-record-command 'switch-to-buffer buffer))
+ (switch-to-buffer buffer))
+
+ ((memq method '(always-frame maybe-frame))
+ (cond
+ ((and window-system
+ (setq win (ido-window-buffer-p buffer))
+ (or (eq method 'always-frame)
+ (y-or-n-p "Jump to frame? ")))
+ (setq newframe (window-frame win))
+ (if (fboundp 'select-frame-set-input-focus)
+ (select-frame-set-input-focus newframe)
+ (raise-frame newframe)
+ (select-frame newframe)
+ (if (not ido-xemacs)
+ (set-mouse-position (selected-frame) (1- (frame-width)) 0)))
+ (select-window win))
+ (t
+ ;; No buffer in other frames...
+ (if record
+ (ido-record-command 'switch-to-buffer buffer))
+ (switch-to-buffer buffer)
+ )))
+
+ ((eq method 'otherwindow)
+ (if record
+ (ido-record-command 'switch-to-buffer buffer))
+ (switch-to-buffer-other-window buffer))
+
+ ((eq method 'display)
+ (display-buffer buffer))
+
+ ((eq method 'otherframe)
+ (progn
+ (switch-to-buffer-other-frame buffer)
+ (if (not ido-xemacs)
+ (if (fboundp 'select-frame-set-input-focus)
+ (select-frame-set-input-focus (selected-frame))
+ (set-mouse-position (selected-frame) (1- (frame-width)) 0)))
+ )))))
+
+
+(defun ido-window-buffer-p (buffer)
+ ;; 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 (memq buffer blist)
+ nil
+ ;; maybe in other frame or icon
+ (get-buffer-window buffer 0) ; better than 'visible
+ )))
+
+
+;;; ----------- IDONIZED FUNCTIONS ------------
+
+;;;###autoload
+(defun ido-switch-buffer ()
+ "Switch to another buffer.
+The buffer is displayed according to `ido-default-buffer-method' -- the
+default is to show it in the same window, unless it is already visible
+in another frame.
+
+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>
+
+RET Select the buffer at the front of the list of matches. If the
+list is empty, possibly prompt to create new buffer.
+
+\\[ido-select-text] Select the current prompt as the buffer.
+If no buffer is found, prompt for a new one.
+
+\\[ido-next-match] Put the first element at the end of the list.
+\\[ido-prev-match] Put the last element at the start of the list.
+\\[ido-complete] Complete a common suffix to the current string that
+matches all buffers. If there is only one match, select that buffer.
+If there is no common suffix, show a list of all matching buffers
+in a separate window.
+\\[ido-edit-input] Edit input string.
+\\[ido-fallback-command] Fallback to non-ido version of current command.
+\\[ido-toggle-regexp] Toggle regexp searching.
+\\[ido-toggle-prefix] Toggle between substring and prefix matching.
+\\[ido-toggle-case] Toggle case-sensitive searching of buffer names.
+\\[ido-completion-help] Show list of matching buffers in separate window.
+\\[ido-enter-find-file] Drop into ido-find-file.
+\\[ido-kill-buffer-at-head] Kill buffer at head of buffer list.
+\\[ido-toggle-ignore] Toggle ignoring buffers listed in `ido-ignore-buffers'."
+ (interactive)
+ (ido-buffer-internal ido-default-buffer-method))
+
+;;;###autoload
+(defun ido-switch-buffer-other-window ()
+ "Switch to another buffer and show it in another window.
+The buffer name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido'."
+ (interactive)
+ (ido-buffer-internal 'otherwindow 'switch-to-buffer-other-window))
+
+;;;###autoload
+(defun ido-display-buffer ()
+ "Display a buffer in another window but don't select it.
+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))
+
+;;;###autoload
+(defun ido-kill-buffer ()
+ "Kill a buffer.
+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))))
+
+;;;###autoload
+(defun ido-insert-buffer ()
+ "Insert contents of a buffer in current buffer after point.
+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: "))
+
+;;;###autoload
+(defun ido-switch-buffer-other-frame ()
+ "Switch to another buffer and show it in another frame.
+The buffer name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido'."
+ (interactive)
+ (if ido-mode
+ (ido-buffer-internal 'otherframe)
+ (call-interactively 'switch-to-buffer-other-frame)))
+
+;;;###autoload
+(defun ido-find-file-in-dir (dir)
+ "Switch to another file starting from DIR."
+ (interactive "DDir: ")
+ (if (not (equal (substring dir -1) "/"))
+ (setq dir (concat dir "/")))
+ (ido-file-internal ido-default-file-method nil dir))
+
+;;;###autoload
+(defun ido-find-file ()
+ "Edit file with name obtained via minibuffer.
+The file is displayed according to `ido-default-file-method' -- the
+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>
+
+RET Select the file at the front of the list of matches. If the
+list is empty, possibly prompt to create new file.
+
+\\[ido-select-text] Select the current prompt as the buffer or file.
+If no buffer or file is found, prompt for a new one.
+
+\\[ido-next-match] Put the first element at the end of the list.
+\\[ido-prev-match] Put the last element at the start of the list.
+\\[ido-complete] Complete a common suffix to the current string that
+matches all files. If there is only one match, select that file.
+If there is no common suffix, show a list of all matching files
+in a separate window.
+\\[ido-edit-input] Edit input string (including path).
+\\[ido-prev-work-directory] or \\[ido-next-work-directory] go to previous/next directory in work directory history.
+\\[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-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.
+\\[ido-toggle-prefix] Toggle between substring and prefix matching.
+\\[ido-toggle-case] Toggle case-sensitive searching of file names.
+\\[ido-toggle-vc] Toggle version control for this file.
+\\[ido-toggle-literal] Toggle literal reading of this file.
+\\[ido-completion-help] Show list of matching files in separate window.
+\\[ido-toggle-ignore] Toggle ignoring files listed in `ido-ignore-files'."
+
+ (interactive)
+ (ido-file-internal ido-default-file-method))
+
+;;;###autoload
+(defun ido-find-file-other-window ()
+ "Switch to another file and show it in another window.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'otherwindow 'find-file-other-window))
+
+;;;###autoload
+(defun ido-find-alternate-file ()
+ "Switch to another file and show it in another window.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'alt-file 'find-alternate-file nil "Find alternate file: "))
+
+;;;###autoload
+(defun ido-find-file-read-only ()
+ "Edit file read-only with name obtained via minibuffer.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'read-only 'find-file-read-only nil "Find file read-only: "))
+
+;;;###autoload
+(defun ido-find-file-read-only-other-window ()
+ "Edit file read-only in other window with name obtained via minibuffer.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'read-only 'find-file-read-only-other-window nil "Find file read-only other window: "))
+
+;;;###autoload
+(defun ido-find-file-read-only-other-frame ()
+ "Edit file read-only in other frame with name obtained via minibuffer.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'read-only 'find-file-read-only-other-frame nil "Find file read-only other frame: "))
+
+;;;###autoload
+(defun ido-display-file ()
+ "Display a file in another window but don't select it.
+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))
+
+;;;###autoload
+(defun ido-find-file-other-frame ()
+ "Switch to another file and show it in another frame.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (ido-file-internal 'otherframe 'find-file-other-frame))
+
+;;;###autoload
+(defun ido-write-file ()
+ "Write current buffer to a file.
+The file name is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (let ((ido-process-ignore-lists t)
+ (ido-work-directory-match-only nil)
+ (ido-ignore-files (cons "[^/]\\'" ido-ignore-files))
+ (ido-report-no-match nil)
+ (ido-auto-merge-work-directories-length -1))
+ (ido-file-internal 'write 'write-file nil "Write file: ")))
+
+;;;###autoload
+(defun ido-insert-file ()
+ "Insert contents of file in current buffer.
+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: "))
+
+;;;###autoload
+(defun ido-dired ()
+ "Call dired the ido way.
+The directory is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (let ((ido-report-no-match nil)
+ (ido-auto-merge-work-directories-length -1))
+ (ido-file-internal 'dired 'dired nil "Dired: " 'dir)))
+
+(defun ido-list-directory ()
+ "Call list-directory the ido way.
+The directory is selected interactively by typing a substring.
+For details of keybindings, do `\\[describe-function] ido-find-file'."
+ (interactive)
+ (let ((ido-report-no-match nil)
+ (ido-auto-merge-work-directories-length -1))
+ (ido-file-internal 'list-directory 'list-directory nil "List directory: " 'dir)))
+
+;;; XEmacs hack for showing default buffer
+
+;; The first time we enter the minibuffer, Emacs puts up the default
+;; buffer to switch to, but XEmacs doesn't -- presumably there is a
+;; subtle difference in the two versions of post-command-hook. The
+;; default is shown for both whenever we delete all of our text
+;; though, indicating its just a problem the first time we enter the
+;; function. To solve this, we use another entry hook for emacs to
+;; show the default the first time we enter the minibuffer.
+
+
+;;; ICOMPLETE TYPE CODE
+
+(defun ido-initiate-auto-merge (buffer)
+ (ido-trace "\n*merge timeout*" buffer)
+ (setq ido-auto-merge-timer nil)
+ (when (and (buffer-live-p buffer)
+ (= ido-use-mycompletion-depth (minibuffer-depth))
+ (boundp 'ido-eoinput) ido-eoinput)
+ (let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) ido-eoinput)))
+ (ido-trace "request merge")
+ (setq ido-use-merged-list 'auto
+ ido-text-init contents
+ ido-rotate-temp t
+ ido-exit 'refresh)
+ (save-excursion
+ (set-buffer buffer)
+ (ido-tidy))
+ (throw 'ido contents))))
+
+(defun ido-exhibit ()
+ "Post command hook for `ido'."
+ ;; Find matching files and display a list in the minibuffer.
+ ;; Copied from `icomplete-exhibit' with two changes:
+ ;; 1. It prints a default file name when there is no text yet entered.
+ ;; 2. It calls my completion routine rather than the standard completion.
+
+ (if (= ido-use-mycompletion-depth (minibuffer-depth))
+ (let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) (point-max)))
+ (buffer-undo-list t)
+ try-single-dir-match)
+
+ (ido-trace "\nexhibit" this-command)
+ (ido-trace "dir" ido-current-directory)
+ (ido-trace "contents" contents)
+ (ido-trace "list" ido-cur-list)
+ (ido-trace "matches" ido-matches)
+ (ido-trace "rescan" ido-rescan)
+
+ (save-excursion
+ (goto-char (point-max))
+ ;; Register the end of input, so we know where the extra stuff (match-status info) begins:
+ (if (not (boundp 'ido-eoinput))
+ ;; In case it got wiped out by major mode business:
+ (make-local-variable 'ido-eoinput))
+ (setq ido-eoinput (point))
+
+ ;; Handle explicit directory changes
+ (and
+ (memq ido-cur-item '(file dir))
+ (> (length contents) 1)
+ (cond
+ ((ido-final-slash contents) ;; xxx/
+ (ido-trace "final slash" contents)
+ (cond
+ ((string-equal contents "~/")
+ (ido-set-current-home)
+ t)
+ ((string-equal contents "../")
+ (ido-up-directory t)
+ t)
+ ((string-equal contents "./")
+ t)
+ ((string-match contents "\\`~[a-zA-Z0-9]/\\'")
+ (ido-set-current-home contents)
+ t)
+ ((string-match "[$][A-Za-z0-9_]+/\\'" contents)
+ (let ((exp (condition-case ()
+ (expand-file-name
+ (substitute-in-file-name (substring contents 0 -1))
+ ido-current-directory)
+ (error nil))))
+ (ido-trace contents exp)
+ (if (and exp (file-directory-p exp))
+ (progn
+ (ido-set-current-directory (file-name-directory exp))
+ (setq ido-text-init (file-name-nondirectory exp))
+ t)
+ nil)))
+ ((and (memq system-type '(windows-nt ms-dos))
+ (string-equal (substring contents 1) ":/"))
+ (ido-set-current-directory (file-name-directory contents))
+ t)
+ ((string-equal (substring contents -2 -1) "/")
+ (ido-set-current-directory
+ (if (memq system-type '(windows-nt ms-dos))
+ (expand-file-name "/" ido-current-directory)
+ "/"))
+ t)
+ (t
+ (setq try-single-dir-match t)
+ nil)))
+
+ ((and (string-equal ido-current-directory "/")
+ (string-match "..:\\'" contents)) ;; Ange-ftp
+ (ido-set-current-directory "/" contents)
+ (when (ido-is-slow-ftp-host)
+ (setq ido-exit 'fallback)
+ (exit-minibuffer))
+ t)
+
+ ((and (string-equal (substring contents -2 -1) "/")
+ (not (string-match "[$]" contents)))
+ (ido-set-current-directory
+ (cond
+ ((= (length contents) 2)
+ "/")
+ (ido-matches
+ (concat ido-current-directory (car ido-matches)))
+ (t
+ (concat ido-current-directory (substring contents 0 -1)))))
+ (setq ido-text-init (substring contents -1))
+ t)
+
+ ((and (not ido-use-merged-list)
+ (not (ido-final-slash contents))
+ (eq ido-try-merged-list t)
+ (numberp ido-auto-merge-work-directories-length)
+ (> ido-auto-merge-work-directories-length 0)
+ (= (length contents) ido-auto-merge-work-directories-length)
+ (not (and ido-auto-merge-inhibit-characters-regexp
+ (string-match ido-auto-merge-inhibit-characters-regexp contents)))
+ (not (input-pending-p)))
+ (setq ido-use-merged-list 'auto
+ ido-text-init contents
+ ido-rotate-temp t)
+ t))
+ (progn
+ (ido-trace "refresh on /" ido-text-init)
+ (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-single-matching-directory
+ ido-matches
+ (null (cdr ido-matches))
+ (ido-final-slash (car ido-matches))
+ (or try-single-dir-match
+ (eq ido-enter-single-matching-directory t)))
+ (ido-trace "single match" (car ido-matches))
+ (ido-set-current-directory
+ (concat ido-current-directory (car ido-matches)))
+ (setq ido-exit 'refresh)
+ (exit-minibuffer))
+
+ (when (and (not ido-matches)
+ ; ido-rescan
+ ido-process-ignore-lists
+ ido-ignored-list)
+ (let ((ido-process-ignore-lists nil)
+ (ido-rotate ido-rotate)
+ (ido-cur-list ido-ignored-list))
+ (ido-trace "try all" ido-ignored-list)
+ (ido-set-matches))
+ (when ido-matches
+ (ido-trace "found " ido-matches)
+ (setq ido-rescan t)
+ (setq ido-process-ignore-lists-inhibit t)
+ (setq ido-text-init ido-text)
+ (setq ido-exit 'refresh)
+ (exit-minibuffer)))
+
+ (when (and
+ ido-rescan
+ (not ido-matches)
+ (memq ido-cur-item '(file dir))
+ (not (ido-is-root-directory))
+ (> (length contents) 1)
+ (not (string-match "[$]" contents)))
+ (ido-trace "merge?")
+ (if ido-use-merged-list
+ (ido-undo-merge-work-directory contents nil)
+ (when (and (eq ido-try-merged-list t)
+ (numberp ido-auto-merge-work-directories-length)
+ (= ido-auto-merge-work-directories-length 0)
+ (not (and ido-auto-merge-inhibit-characters-regexp
+ (string-match ido-auto-merge-inhibit-characters-regexp contents)))
+ (not (input-pending-p)))
+ (ido-trace "\n*start timer*")
+ (setq ido-auto-merge-timer
+ (run-with-timer ido-auto-merge-delay-time nil 'ido-initiate-auto-merge (current-buffer))))))
+
+ (setq ido-rescan t)
+
+ (if (and ido-use-merged-list
+ ido-matches
+ (not (string-equal (car (cdr (car ido-matches))) ido-current-directory)))
+ (progn
+ (ido-set-current-directory (car (cdr (car ido-matches))))
+ (setq ido-use-merged-list t
+ ido-exit 'keep
+ ido-text-init ido-text)
+ (exit-minibuffer)))
+
+ ;; Insert the match-status information:
+ (ido-set-common-completion)
+ (let ((inf (ido-completions
+ contents
+ minibuffer-completion-table
+ minibuffer-completion-predicate
+ (not minibuffer-completion-confirm))))
+ (ido-trace "inf" inf)
+ (insert inf))
+
+ ))))
+
+(defun ido-completions (name candidates predicate require-match)
+ ;; 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))
+ first)
+
+ (if (and ind ido-use-faces)
+ (put-text-property 0 1 'face 'ido-indicator-face ind))
+
+ (if (and ido-use-faces comps)
+ (let* ((fn (ido-name (car comps)))
+ (ln (length fn)))
+ (setq first (format "%s" fn))
+ (put-text-property 0 ln 'face
+ (if (= (length comps) 1)
+ 'ido-only-match-face
+ 'ido-first-match-face)
+ 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]
+ ""))
+
+ ((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))
+ "")
+ (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))
+ (alternatives
+ (apply
+ (function concat)
+ (cdr (apply
+ (function nconc)
+ (mapcar '(lambda (com)
+ (setq com (ido-name com))
+ (setq items (1- items))
+ (cond
+ ((< items 0) ())
+ ((= items 0) (list (nth 3 ido-decorations))) ; " | ..."
+ (t
+ (list (or ido-separator (nth 2 ido-decorations)) ; " | "
+ (let ((str (substring com 0)))
+ (if (and ido-use-faces
+ (not (string= str first))
+ (ido-final-slash str))
+ (put-text-property 0 (length str) 'face 'ido-subdir-face str))
+ str)))))
+ comps))))))
+
+ (concat
+ ;; put in common completion item -- what you get by pressing tab
+ (if (> (length ido-common-match-string) (length name))
+ (concat (nth 4 ido-decorations) ;; [ ... ]
+ (substring ido-common-match-string (length name))
+ (nth 5 ido-decorations)))
+ ;; list all alternatives
+ (nth 0 ido-decorations) ;; { ... }
+ alternatives
+ (nth 1 ido-decorations)))))))
+
+(defun ido-minibuffer-setup ()
+ "Minibuffer setup hook for `ido'."
+ ;; Copied from `icomplete-minibuffer-setup-hook'.
+ (when (and (boundp 'ido-completing-read)
+ (or ido-xemacs (= ido-use-mycompletion-depth (minibuffer-depth))))
+ (add-hook 'pre-command-hook 'ido-tidy nil t)
+ (add-hook 'post-command-hook 'ido-exhibit nil t)
+ (setq cua-inhibit-cua-keys t)
+ (when ido-xemacs
+ (ido-exhibit)
+ (goto-char (point-min)))
+ (run-hooks 'ido-minibuffer-setup-hook)))
+
+(defun ido-tidy ()
+ "Pre command hook for `ido'."
+ ;; Remove completions display, if any, prior to new user input.
+ ;; Copied from `icomplete-tidy'."
+
+ (when ido-auto-merge-timer
+ (ido-trace "\n*cancel timer*" this-command)
+ (cancel-timer ido-auto-merge-timer)
+ (setq ido-auto-merge-timer nil))
+
+ (if (and (boundp 'ido-use-mycompletion-depth)
+ (= ido-use-mycompletion-depth (minibuffer-depth)))
+ (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))))
+
+(defun ido-summary-buffers-to-end ()
+ ;; Move the summaries to the end of the buffer list.
+ ;; This is an example function which can be hooked on to
+ ;; `ido-make-buffer-list-hook'. Any buffer matching the regexps
+ ;; `Summary' or `output\*$'are put to the end of the list.
+ (let ((summaries (delq nil (mapcar
+ (lambda (x)
+ (if (or
+ (string-match "Summary" x)
+ (string-match "output\\*\\'" x))
+ x))
+ ido-temp-list))))
+ (ido-to-end summaries)))
+
+;;; Helper functions for other programs
+
+;;;###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.
+See `read-file-name' for additional parameters."
+ (message "%S %S %S %S" this-command ido-read-file-name-non-ido
+ predicate (memq this-command ido-read-file-name-non-ido))
+ (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)))
+ (message "gotit")
+ (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)))))
+
+;;;###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))
+ (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)))))
+
+;;; ido.el ends here