X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0b3c2fe469050acc20439109361d2885f5453fc3..139bbb9cc4db48696ce8c48b8dd6ce09c2c07594:/lisp/ido.el diff --git a/lisp/ido.el b/lisp/ido.el index 4cbc88cf03..2ea7476ce4 100644 --- a/lisp/ido.el +++ b/lisp/ido.el @@ -1,6 +1,7 @@ ;;; ido.el --- interactively do things with buffers and files. -;; Copyright (C) 1996-2004 Free Software Foundation, Inc. +;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +;; 2004, 2005 Free Software Foundation, Inc. ;; Author: Kim F. Storm ;; Based on: iswitchb by Stephen Eglen @@ -20,8 +21,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Acknowledgements @@ -56,7 +57,7 @@ ;; 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.5 to use command remapping +;; gnu.emacs.sources adapted for emacs 22.1 to use command remapping ;; and optionally hooking the read-buffer and read-file-name functions. ;; ;; Prefix matching was added by Klaus Berndl based on @@ -101,9 +102,9 @@ ;; The list in {...} are the matching buffers, most recent first ;; (buffers visible in the current frame are put at the end of the ;; list by default). At any time I can select the item at the head of -;; the list by pressing RET. I can also bring the put the first -;; element at the end of the list by pressing C-s or [right], or put -;; the last element at the head of the list by pressing C-r or [left]. +;; the list by pressing RET. I can also put the first element at the +;; end of the list by pressing C-s or [right], or bring the last +;; element to the head of the list by pressing C-r or [left]. ;; ;; The item in [...] indicates what can be added to my input by ;; pressing TAB. In this case, I will get "3" added to my input. @@ -210,8 +211,7 @@ ;; Example: ;; ;; If you have again two Buffers "123456" and "123" then hitting "2" does -;; not match because "2" is not a PREFIX in any of the buffer-names. This -;; is the only difference between the substring and prefix matching. +;; not match because "2" is not a PREFIX in any of the buffer-names. ;; Flexible matching ;; ----------------- @@ -236,14 +236,10 @@ ;; ;; There is limited provision for regexp matching within ido, ;; enabled through `ido-enable-regexp' (toggle with C-t). -;; This allows you to type `c$' for example and see all file names -;; ending in `c'. This facility is quite limited though in two -;; respects. First, you can't currently type in expressions like -;; `[0-9]' directly -- you have to type them in when ido-enable-regexp -;; is nil and then toggle on the regexp functionality. Likewise, -;; don't enter an expression containing `\' in regexp mode. If you -;; try, ido gets confused, so just hit C-g and try again. Secondly, -;; no completion mechanism is currently offered with regexp searching. +;; This allows you to type `[ch]$' for example and see all file names +;; ending in `c' or `h'. +;; +;; Note: ido-style completion is inhibited when you enable regexp matching. ;; Customization @@ -251,8 +247,8 @@ ;; ;; Customize the `ido' group to change the `ido' functionality. ;; -;; To modify the keybindings, use the hook provided. For example: -;;(add-hook 'ido-define-mode-map-hook 'ido-my-keys) +;; To modify the keybindings, use the ido-setup-hook. For example: +;;(add-hook 'ido-setup-hook 'ido-my-keys) ;; ;;(defun ido-my-keys () ;; "Add my keybindings for ido." @@ -291,7 +287,7 @@ ;; then all files matching "Summary" are moved to the end of the ;; list. (I find this handy for keeping the INBOX Summary and so on ;; out of the way.) It also moves files matching "output\*$" to the -;; end of the list (these are created by AUC TeX when compiling.) +;; end of the list (these are created by AUCTeX when compiling.) ;; Other functions could be made available which alter the list of ;; matching files (either deleting or rearranging elements.) @@ -299,8 +295,8 @@ ;; ------------ ;; The highlighting of matching items is controlled via ido-use-faces. -;; The faces used are ido-first-match-face, ido-only-match-face and -;; ido-subdir-face. +;; The faces used are ido-first-match, ido-only-match and +;; ido-subdir. ;; Colouring of the matching item was suggested by ;; Carsten Dominik (dominik@strw.leidenuniv.nl). @@ -338,13 +334,14 @@ "Switch between files using substrings." :group 'extensions :group 'convenience + :version "22.1" :link '(emacs-commentary-link :tag "Commentary" "ido.el") :link '(emacs-library-link :tag "Lisp File" "ido.el")) ;;;###autoload (defcustom ido-mode nil "Determines for which functional group \(buffer and files) ido behavior -should be enabled. The following values are possible: +should be enabled. The following values are possible: - `buffer': Turn only on ido buffer behavior \(switching, killing, displaying...) - `file': Turn only on ido file behavior \(finding, writing, inserting...) @@ -359,7 +356,6 @@ use either \\[customize] or the function `ido-mode'." :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) @@ -371,7 +367,7 @@ use either \\[customize] or the function `ido-mode'." Setting this variable directly does not work. Use `customize' or call the function `ido-everywhere'." :set #'(lambda (symbol value) - (ido-everywhere value)) + (ido-everywhere (if value 1 -1))) :initialize 'custom-initialize-default :type 'boolean :group 'ido) @@ -410,6 +406,15 @@ This allows the current directory to be opened immediate with `dired'." :type 'boolean :group 'ido) +(defcustom ido-file-extensions-order nil + "*List of file extensions specifying preferred order of file selections. +Each element is either a string with `.' as the first char, an empty +string matching files without extension, or t which is the default order +for files with an unlisted file extension." + :type '(repeat (choice string + (const :tag "Default order" t))) + :group 'ido) + (defcustom ido-ignore-directories '("\\`CVS/" "\\`\\.\\./" "\\`\\./") "*List of regexps or functions matching sub-directory names to ignore." @@ -444,9 +449,9 @@ Possible values: `otherframe' Show new file in another frame `maybe-frame' If a file is visible in another frame, prompt to ask if you you want to see the file in the same window of the current - frame or in the other frame. + frame or in the other frame `always-frame' If a file is visible in another frame, raise that - frame. Otherwise, visit the file in the same window." + frame; otherwise, visit the file in the same window" :type '(choice (const samewindow) (const otherwindow) (const display) @@ -457,7 +462,7 @@ Possible values: (defcustom ido-default-buffer-method 'always-frame "*How to switch to new buffer when using `ido-switch-buffer'. -See ido-default-file-method for details." +See `ido-default-file-method' for details." :type '(choice (const samewindow) (const otherwindow) (const display) @@ -482,14 +487,20 @@ Value can be toggled within `ido' using `ido-toggle-regexp'." :group 'ido) (defcustom ido-enable-prefix nil - "*Nil means that `ido' will match if the inserted text is an -arbitrary substring (default). If non-nil `ido' will only match if the inserted -text is a prefix \(this behavior is like the standard unix- or -emacs-completion works). + "*Non-nil means only match if the entered text is a prefix of file name. +This behavior is like the standard emacs-completion. +Nil means to match if the entered text is an arbitrary substring. Value can be toggled within `ido' using `ido-toggle-prefix'." :type 'boolean :group 'ido) +(defcustom ido-enable-dot-prefix nil + "*Non-nil means to match leading dot as prefix. +I.e. hidden files and buffers will match only if you type a dot +as first char even if `ido-enable-prefix' is nil." + :type 'boolean + :group 'ido) + (defcustom ido-confirm-unique-completion nil "*Non-nil means that even a unique completion must be confirmed. This means that \\[ido-complete] must always be followed by \\[ido-exit-minibuffer] @@ -515,7 +526,7 @@ Note that the non-ido equivalent command is recorded." (defcustom ido-max-prospects 12 "*Non-zero means that the prospect list will be limited to than number of items. For a long list of prospects, building the full list for the minibuffer can take a -non-negletable amount of time; setting this variable reduces that time." +non-negligible amount of time; setting this variable reduces that time." :type 'integer :group 'ido) @@ -563,8 +574,12 @@ the `ido-work-directory-list' list." (defcustom ido-use-filename-at-point nil "*Non-nil means that ido shall look for a filename at point. +May use `ffap-guesser' to guess whether text at point is a filename. If found, use that as the starting point for filename selection." - :type 'boolean + :type '(choice + (const :tag "Disabled" nil) + (const :tag "Guess filename" guess) + (other :tag "Use literal filename" t)) :group 'ido) @@ -600,7 +615,7 @@ If zero, ftp directories are not cached." (defcustom ido-slow-ftp-hosts nil "*List of slow ftp hosts where ido prompting should not be used. If an ftp host is on this list, ido automatically switches to the non-ido -equivalent function, e.g. find-file rather than ido-find-file." +equivalent function, e.g. `find-file' rather than `ido-find-file'." :type '(repeat string) :group 'ido) @@ -660,17 +675,30 @@ See also `ido-dir-file-cache' and `ido-save-directory-list-file'." :type 'integer :group 'ido) +(defcustom ido-max-directory-size 30000 + "*Maximum size (in bytes) for directories to use ido completion. +If you enter a directory with a size larger than this size, ido will +not provide the normal completion. To show the completions, use C-a." + :type '(choice (const :tag "No limit" nil) + (integer :tag "Size in bytes" 30000)) + :group 'ido) + (defcustom ido-rotate-file-list-default nil "*Non-nil means that `ido' will always rotate file list to get default in front." :type 'boolean :group 'ido) -(defcustom ido-enter-single-matching-directory 'slash - "*Automatically enter sub-directory if it is the only matching item, if non-nil. -If value is 'slash, only enter if typing final slash, else do it always." +(defcustom ido-enter-matching-directory 'only + "*Additional methods to enter sub-directory of first/only matching item. +If value is 'first, enter first matching sub-directory when typing a slash. +If value is 'only, typing a slash only enters the sub-directory if it is +the only matching item. +If value is t, automatically enter a sub-directory when it is the only +matching item, even without typing a slash." :type '(choice (const :tag "Never" nil) - (const :tag "When typing /" slash) - (other :tag "Always" t)) + (const :tag "Slash enters first directory" first) + (const :tag "Slash enters first and only directory" only) + (other :tag "Always enter unique directory" t)) :group 'ido) (defcustom ido-create-new-buffer 'prompt @@ -682,8 +710,11 @@ ask user whether to create buffer, or 'never to never create new buffer." (const never)) :group 'ido) -(defcustom ido-define-mode-map-hook nil - "*Hook to define keys in `ido-mode-map' for extra keybindings." +(defcustom ido-setup-hook nil + "*Hook run after the ido variables and keymap have been setup. +The dynamic variable `ido-cur-item' contains the current type of item that +is read by ido, possible values are file, dir, buffer, and list. +Additional keys can be defined in `ido-mode-map'." :type 'hook :group 'ido) @@ -693,17 +724,18 @@ Obsolete. Set 3rd element of `ido-decorations' instead." :type '(choice string (const nil)) :group 'ido) -(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]") +(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]") "*List of strings used by ido to display the alternatives in the minibuffer. -There are 9 elements in this list: +There are 10 elements in this list: 1st and 2nd elements are used as brackets around the prospect list, 3rd element is the separator between prospects (ignored if ido-separator is set), 4th element is the string inserted at the end of a truncated list of prospects, 5th and 6th elements are used as brackets around the common match string which can be completed using TAB, -7th element is the string displayed when there are a no matches, and -8th element is displayed if there is a single match (and faces are not used). -9th element is displayed when the current directory is non-readable." +7th element is the string displayed when there are no matches, and +8th element is displayed if there is a single match (and faces are not used), +9th element is displayed when the current directory is non-readable, +10th element is displayed when directory exceeds `ido-max-directory-size'." :type '(repeat string) :group 'ido) @@ -713,23 +745,29 @@ subdirs in the alternatives." :type 'boolean :group 'ido) -(defface ido-first-match-face '((t (:bold t))) +(defface ido-first-match '((t (:bold t))) "*Font used by ido for highlighting first match." :group 'ido) -(defface ido-only-match-face '((((class color)) +(defface ido-only-match '((((class color)) (:foreground "ForestGreen")) (t (:italic t))) "*Font used by ido for highlighting only match." :group 'ido) -(defface ido-subdir-face '((((class color)) +(defface ido-subdir '((((min-colors 88) (class color)) + (:foreground "red1")) + (((class color)) (:foreground "red")) (t (:underline t))) "*Font used by ido for highlighting subdirs in the alternatives." :group 'ido) -(defface ido-indicator-face '((((class color)) +(defface ido-indicator '((((min-colors 88) (class color)) + (:foreground "yellow1" + :background "red1" + :width condensed)) + (((class color)) (:foreground "yellow" :background "red" :width condensed)) @@ -737,6 +775,12 @@ subdirs in the alternatives." "*Font used by ido for highlighting its indicators." :group 'ido) +(defface ido-incomplete-regexp + '((t + (:inherit font-lock-warning-face))) + "Ido face for indicating incomplete regexps." + :group 'ido) + (defcustom ido-make-file-list-hook nil "*List of functions to run when the list of matching files is created. Each function on the list may modify the dynamically bound variable @@ -831,17 +875,23 @@ Must be set before enabling ido mode." (defcustom ido-read-file-name-as-directory-commands '() "List of commands which uses read-file-name to read a directory name. When `ido-everywhere' is non-nil, the commands in this list will read -the directory using ido-read-directory-name." +the directory using `ido-read-directory-name'." :type '(repeat symbol) :group 'ido) (defcustom ido-read-file-name-non-ido '() "List of commands which shall not read file names the ido way. When `ido-everywhere' is non-nil, the commands in this list will read -the file name using normal read-file-name style." +the file name using normal `read-file-name' style." :type '(repeat symbol) :group 'ido) +(defcustom ido-before-fallback-functions '() + "List of functions to call before calling a fallback command. +The fallback command is passed as an argument to the functions." + :type 'hook + :group 'ido) + ;;; Internal Variables ;; Persistent variables @@ -862,7 +912,7 @@ See `ido-enable-last-directory-history' for details.") (defvar ido-work-directory-list nil "List of actual working directory names. The current directory is inserted at the front of this list whenever a -file is opened with ido-find-file and family.") +file is opened with `ido-find-file' and family.") (defvar ido-work-file-list nil "List of actual work file names. @@ -876,7 +926,7 @@ Each element in the list is of the form (DIR (MTIME) FILE...).") (defvar ido-ignore-item-temp-list nil "List of items to ignore in current ido invocation. -Intended to be let-bound by functions which calls ido repeatedly. +Intended to be let-bound by functions which call ido repeatedly. Should never be set permanently.") ;; Temporary storage @@ -901,6 +951,9 @@ Copied from `icomplete-eoinput'.") (defvar ido-text-init nil "The initial string for the users string it is typed in.") +(defvar ido-input-stack nil + "Stores the users strings when user hits M-b/M-f.") + (defvar ido-matches nil "List of files currently matching `ido-text'.") @@ -913,7 +966,7 @@ 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.") + "Current directory for `ido-find-file'.") (defvar ido-auto-merge-timer nil "Delay timer for auto merge.") @@ -923,11 +976,13 @@ selected.") Is set by ido functions to the current minibuffer-depth, so that it doesn't interfere with other minibuffer usage.") +(defvar ido-incomplete-regexp nil + "Non-nil if an incomplete regexp is entered.") ;;; Variables with dynamic bindings. ;;; Declared here to keep the byte compiler quiet. -;; Stores the current ido item type ('file, 'dir or 'buffer). +;; Stores the current ido item type ('file, 'dir, 'buffer, or 'list). (defvar ido-cur-item) ;; Stores the current list of items that will be searched through. @@ -936,6 +991,9 @@ it doesn't interfere with other minibuffer usage.") ;; at the end of the list. Created by `ido-make-item-list'. (defvar ido-cur-list) +;; Stores the choice list for ido-completing-read +(defvar ido-choice-list) + ;; Stores the list of items which are ignored when building ;; `ido-cur-list'. It is in no specific order. (defvar ido-ignored-list) @@ -943,6 +1001,9 @@ it doesn't interfere with other minibuffer usage.") ;; Remember if current directory is non-readable (so we cannot do completion). (defvar ido-directory-nonreadable) +;; Remember if current directory is 'huge' (so we don't want to do completion). +(defvar ido-directory-too-big) + ;; Keep current item list if non-nil. (defvar ido-keep-item-list) @@ -986,6 +1047,8 @@ it doesn't interfere with other minibuffer usage.") ;; Stores temporary state of literal find file. (defvar ido-find-literal) +;; Set to 'ignore to inhibit switching between find-file/switch-buffer. +(defvar ido-context-switch-command) ;;; FUNCTIONS @@ -1071,6 +1134,8 @@ it doesn't interfere with other minibuffer usage.") (defun ido-may-cache-directory (&optional dir) (setq dir (or dir ido-current-directory)) (cond + ((ido-directory-too-big-p dir) + nil) ((and (ido-is-root-directory dir) (or ido-enable-tramp-completion (memq system-type '(windows-nt ms-dos)))) @@ -1274,7 +1339,8 @@ This function also adds a hook to the minibuffer." (add-hook 'kill-emacs-hook 'ido-kill-emacs-hook) - (unless ido-minor-mode-map-entry + (if ido-minor-mode-map-entry + (setcdr ido-minor-mode-map-entry (make-sparse-keymap)) (setq ido-minor-mode-map-entry (cons 'ido-mode (make-sparse-keymap))) (add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry)) @@ -1301,17 +1367,25 @@ This function also adds a hook to the minibuffer." (define-key map [remap display-buffer] 'ido-display-buffer))))) (defun ido-everywhere (arg) - "Enable ido everywhere file and directory names are read." + "Toggle using ido speed-ups everywhere file and directory names are read. +With ARG, turn ido speed-up on if arg is positive, off otherwise." (interactive "P") (setq ido-everywhere (if arg (> (prefix-numeric-value arg) 0) (not ido-everywhere))) - (setq read-file-name-function - (and ido-everywhere (memq ido-mode '(both file)) - 'ido-read-file-name)) - (setq read-buffer-function - (and ido-everywhere (memq ido-mode '(both buffer)) - 'ido-read-buffer))) + (when (get 'ido-everywhere 'file) + (setq read-file-name-function (car (get 'ido-everywhere 'file))) + (put 'ido-everywhere 'file nil)) + (when (get 'ido-everywhere 'buffer) + (setq read-buffer-function (car (get 'ido-everywhere 'buffer))) + (put 'ido-everywhere 'buffer nil)) + (when ido-everywhere + (when (memq ido-mode '(both file)) + (put 'ido-everywhere 'file (cons read-file-name-function nil)) + (setq read-file-name-function 'ido-read-file-name)) + (when (memq ido-mode '(both buffer)) + (put 'ido-everywhere 'buffer (cons read-buffer-function nil)) + (setq read-buffer-function 'ido-read-buffer)))) ;;; IDO KEYMAP @@ -1333,16 +1407,21 @@ This function also adds a hook to the minibuffer." (define-key map "\C-s" 'ido-next-match) (define-key map "\C-t" 'ido-toggle-regexp) (define-key map "\C-z" 'ido-undo-merge-work-directory) - (define-key map [(control ? )] 'ido-restrict-to-matches) + (define-key map [(control ?\s)] 'ido-restrict-to-matches) (define-key map [(control ?@)] 'ido-restrict-to-matches) (define-key map [right] 'ido-next-match) (define-key map [left] 'ido-prev-match) (define-key map "?" 'ido-completion-help) + ;; Magic commands. + (define-key map "\C-b" 'ido-magic-backward-char) + (define-key map "\C-f" 'ido-magic-forward-char) + (define-key map "\C-d" 'ido-magic-delete-char) + (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 "\C-x\C-b" (or ido-context-switch-command 'ido-enter-switch-buffer)) + (define-key map "\C-x\C-f" 'ido-fallback-command) + (define-key map "\C-x\C-d" (or (and ido-context-switch-command 'ignore) 'ido-enter-dired)) (define-key map [down] 'ido-next-match-dir) (define-key map [up] 'ido-prev-match-dir) (define-key map [(meta up)] 'ido-prev-work-directory) @@ -1352,13 +1431,14 @@ This function also adds a hook to the minibuffer." (define-key map [(meta backspace)] 'ido-delete-backward-word-updir) (define-key map [(control backspace)] 'ido-up-directory) (define-key map "\C-l" 'ido-reread-directory) - (define-key map [(meta ?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 ?d)] 'ido-wide-find-dir-or-delete-dir) + (define-key map [(meta ?b)] 'ido-push-dir) + (define-key map [(meta ?f)] 'ido-wide-find-file-or-pop-dir) (define-key map [(meta ?k)] 'ido-forget-work-directory) (define-key map [(meta ?m)] 'ido-make-directory) (define-key map [(meta ?n)] 'ido-next-work-directory) (define-key map [(meta ?o)] 'ido-prev-work-file) + (define-key map [(meta control ?o)] 'ido-next-work-file) (define-key map [(meta ?p)] 'ido-prev-work-directory) (define-key map [(meta ?s)] 'ido-merge-work-directories) ) @@ -1372,8 +1452,8 @@ This function also adds a hook to the minibuffer." ) (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-x\C-f" (or ido-context-switch-command 'ido-enter-find-file)) + (define-key map "\C-x\C-b" 'ido-fallback-command) (define-key map "\C-k" 'ido-kill-buffer-at-head) ) @@ -1384,8 +1464,7 @@ This function also adds a hook to the minibuffer." (define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir) (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir))) - (setq ido-mode-map map) - (run-hooks 'ido-define-mode-map-hook))) + (setq ido-mode-map map))) (defun ido-final-slash (dir &optional fix-it) ;; return DIR if DIR has final slash. @@ -1414,6 +1493,16 @@ This function also adds a hook to the minibuffer." (file-directory-p dir) (not (file-readable-p dir))))) +(defun ido-directory-too-big-p (dir) + ;; Return t if dir is a directory, but too big to show + ;; Do not check for non-readable directories via tramp, as this causes a premature + ;; connect on incomplete tramp paths (after entring just method:). + (let ((ido-enable-tramp-completion nil)) + (and (numberp ido-max-directory-size) + (ido-final-slash dir) + (file-directory-p dir) + (> (nth 7 (file-attributes dir)) ido-max-directory-size)))) + (defun ido-set-current-directory (dir &optional subdir no-merge) ;; Set ido's current directory to DIR or DIR/SUBDIR (setq dir (ido-final-slash dir t)) @@ -1428,6 +1517,8 @@ This function also adds a hook to the minibuffer." (if (get-buffer ido-completion-buffer) (kill-buffer ido-completion-buffer)) (setq ido-directory-nonreadable (ido-nonreadable-directory-p dir)) + (setq ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p dir))) t)) (defun ido-set-current-home (&optional dir) @@ -1542,6 +1633,10 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-define-mode-map) (setq ido-text-init initial) + (setq ido-input-stack nil) + + (run-hooks 'ido-setup-hook) + (while (not done) (ido-trace "\n_LOOP_" ido-text-init) (setq ido-exit nil) @@ -1572,6 +1667,7 @@ If INITIAL is non-nil, it specifies the initial input string." (l (ido-make-merged-file-list ido-text-init (eq ido-use-merged-list 'auto) (eq ido-try-merged-list 'wide)))) + (ido-trace "merged" l) (cond ((not l) (if (eq ido-try-merged-list 'wide) @@ -1591,6 +1687,9 @@ If INITIAL is non-nil, it specifies the initial input string." ido-use-merged-list nil))) ((eq l t) (setq ido-use-merged-list nil)) + ((eq l 'input-pending-p) + (setq ido-try-merged-list t + ido-use-merged-list nil)) (t (setq ido-pre-merge-state (list ido-text-init ido-current-directory olist oign omat)) @@ -1612,13 +1711,20 @@ If INITIAL is non-nil, it specifies the initial input string." ido-rescan nil)) ((eq ido-cur-item 'file) (setq ido-ignored-list nil - ido-cur-list (ido-make-file-list ido-default-item))) + ido-cur-list (and (not ido-directory-nonreadable) + (not ido-directory-too-big) + (ido-make-file-list ido-default-item)))) ((eq ido-cur-item 'dir) (setq ido-ignored-list nil - ido-cur-list (ido-make-dir-list ido-default-item))) + ido-cur-list (and (not ido-directory-nonreadable) + (not ido-directory-too-big) + (ido-make-dir-list ido-default-item)))) ((eq ido-cur-item 'buffer) (setq ido-ignored-list nil ido-cur-list (ido-make-buffer-list ido-default-item))) + ((eq ido-cur-item 'list) + (setq ido-ignored-list nil + ido-cur-list (ido-make-choice-list ido-default-item))) (t nil)) (setq ido-rotate-temp nil) @@ -1676,9 +1782,11 @@ If INITIAL is non-nil, it specifies the initial input string." (setq ido-text-init "") (while new (setq new (if edit - (read-file-name (concat prompt "[EDIT] ") - (expand-file-name d) - (concat d f) nil f) + (condition-case nil + (read-file-name (concat prompt "[EDIT] ") + (expand-file-name d) + (concat d f) nil f) + (quit (concat d f))) f) d (or (file-name-directory new) "/") f (file-name-nondirectory new) @@ -1697,16 +1805,20 @@ If INITIAL is non-nil, it specifies the initial input string." (setq ido-text-init f new nil)))))) (t - (setq ido-text-init (read-string (concat prompt "[EDIT] ") ido-final-text)))) + (setq ido-text-init + (condition-case nil + (read-string (concat prompt "[EDIT] ") ido-final-text) + (quit ido-final-text))))) + nil) ((eq ido-exit 'keep) (setq ido-keep-item-list t)) - ((memq ido-exit '(dired fallback findfile findbuffer)) + ((memq ido-exit '(dired fallback find-file switch-to-buffer insert-buffer insert-file)) (setq done t)) - ((eq ido-exit 'updir) + ((memq ido-exit '(updir push)) ;; cannot go up if already at the root-dir (Unix) or at the ;; root-dir of a certain drive (Windows or MS-DOS). (if (ido-is-tramp-root) @@ -1715,11 +1827,36 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-set-current-directory (match-string 1 ido-current-directory)) (setq ido-set-default-item t)) (unless (ido-is-root-directory) + (when (eq ido-exit 'push) + (setq ido-input-stack (cons (cons ido-cur-item ido-text) ido-input-stack)) + (setq ido-cur-item 'dir) + (setq ido-text-init (file-name-nondirectory (substring ido-current-directory 0 -1))) + (ido-trace "push" ido-input-stack)) (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))) (setq ido-set-default-item t)))) + ((eq ido-exit 'pop) + (ido-trace "pop" ido-input-stack) + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt)))) + + ((eq ido-exit 'pop-all) + (ido-trace "pop-all" ido-input-stack) + (while ido-input-stack + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt))))) + ;; Handling the require-match must be done in a better way. - ((and require-match (not (ido-existing-item-p))) + ((and require-match + (not (if ido-directory-too-big + (file-exists-p (concat ido-current-directory ido-final-text)) + (ido-existing-item-p)))) (error "must specify valid item")) (t @@ -1731,7 +1868,7 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-name (car ido-matches)))) (cond - ((eq item 'buffer) + ((memq item '(buffer list)) (setq done t)) ((string-equal "./" ido-selected) @@ -1769,7 +1906,14 @@ If INITIAL is non-nil, it specifies the initial input string." (setq ido-last-directory-list (cons (cons ido-current-directory ido-selected) ido-last-directory-list))))) (ido-set-current-directory ido-current-directory ido-selected) - (setq ido-set-default-item t)) + (if ido-input-stack + (while ido-input-stack + (let ((elt (car ido-input-stack))) + (if (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory ido-current-directory (cdr elt)) + (setq ido-text-init (cdr elt))) + (setq ido-cur-item (car elt)))) + (setq ido-set-default-item t))) (t (setq done t)))))) @@ -1783,21 +1927,33 @@ If INITIAL is non-nil, it specifies the initial input string." (exit-minibuffer)) ;;; MAIN FUNCTIONS -(defun ido-buffer-internal (method &optional fallback prompt default initial) +(defun ido-buffer-internal (method &optional fallback prompt default initial switch-cmd) ;; Internal function for ido-switch-buffer and friends (if (not ido-mode) - (call-interactively (or fallback 'switch-to-buffer)) - (let ((buf (ido-read-buffer (or prompt "Buffer: ") default nil initial))) + (progn + (run-hook-with-args 'ido-before-fallback-functions + (or fallback 'switch-to-buffer)) + (call-interactively (or fallback 'switch-to-buffer))) + (let* ((ido-context-switch-command switch-cmd) + (ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (buf (ido-read-internal 'buffer (or prompt "Buffer: ") 'ido-buffer-history default nil initial))) ;; Choose the buffer name: either the text typed in, or the head ;; of the list of matches (cond - ((eq ido-exit 'findfile) + ((eq ido-exit 'find-file) (ido-file-internal ido-default-file-method nil nil nil nil ido-text)) + ((eq ido-exit 'insert-file) + (ido-file-internal 'insert 'insert-file nil "Insert file: " nil ido-text 'ido-enter-insert-buffer)) + ((eq ido-exit 'fallback) (let ((read-buffer-function nil)) + (run-hook-with-args 'ido-before-fallback-functions + (or fallback 'switch-to-buffer)) (call-interactively (or fallback 'switch-to-buffer)))) ;; Check buf is non-nil. @@ -1809,7 +1965,9 @@ If INITIAL is non-nil, it specifies the initial input string." (if (eq method 'insert) (progn (ido-record-command 'insert-buffer buf) - (insert-buffer buf)) + (with-no-warnings + ;; we really want to run insert-buffer here + (insert-buffer buf))) (ido-visit-buffer buf method t))) ;; buffer doesn't exist @@ -1827,18 +1985,6 @@ If INITIAL is non-nil, it specifies the initial input string." (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-directory-nonreadable 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)) @@ -1880,39 +2026,48 @@ If INITIAL is non-nil, it specifies the initial input string." ;; Add final slash to result in case it was missing from DEFAULT-DIRECTORY. (ido-final-slash (expand-file-name (or dir default-directory)) t)) -(defun ido-file-internal (method &optional fallback default prompt item initial) +(defun ido-file-internal (method &optional fallback default prompt item initial switch-cmd) ;; Internal function for ido-find-file and friends (unless item (setq item 'file)) - (let* ((ido-current-directory (ido-expand-directory default)) - (ido-directory-nonreadable (ido-nonreadable-directory-p ido-current-directory)) - filename) - - (cond - ((or (not ido-mode) (ido-is-slow-ftp-host)) - (setq filename t - ido-exit 'fallback)) - - ((and (eq item 'file) + (let ((ido-current-directory (ido-expand-directory default)) + (ido-context-switch-command switch-cmd) + ido-directory-nonreadable ido-directory-too-big + (minibuffer-completing-file-name t) + filename) + + (if (or (not ido-mode) (ido-is-slow-ftp-host)) + (setq filename t + ido-exit 'fallback) + (setq ido-directory-nonreadable + (ido-nonreadable-directory-p ido-current-directory) + ido-directory-too-big + (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory)))) + + (when (and (eq item 'file) (or ido-use-url-at-point ido-use-filename-at-point)) (let (fn d) (require 'ffap) ;; Duplicate code from ffap-guesser as we want different behaviour for files and URLs. (cond - ((and ido-use-url-at-point - ffap-url-regexp - (ffap-fixup-url (or (ffap-url-at-point) - (ffap-gopher-at-point)))) + ((with-no-warnings + (and ido-use-url-at-point + ffap-url-regexp + (ffap-fixup-url (or (ffap-url-at-point) + (ffap-gopher-at-point))))) (setq ido-exit 'ffap filename t)) ((and ido-use-filename-at-point - (setq fn (ffap-string-at-point)) + (setq fn (if (eq ido-use-filename-at-point 'guess) + (with-no-warnings (ffap-guesser)) + (ffap-string-at-point))) (not (string-match "^http:/" fn)) (setq d (file-name-directory fn)) (file-directory-p d)) (setq ido-current-directory d) - (setq initial (file-name-nondirectory fn))))))) + (setq initial (file-name-nondirectory fn)))))) (let (ido-saved-vc-hb (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) @@ -1935,11 +2090,16 @@ If INITIAL is non-nil, it specifies the initial input string." ;; we don't want to change directory of current buffer. (let ((default-directory ido-current-directory) (read-file-name-function nil)) + (run-hook-with-args 'ido-before-fallback-functions + (or fallback 'find-file)) (call-interactively (or fallback 'find-file)))) - ((eq ido-exit 'findbuffer) + ((eq ido-exit 'switch-to-buffer) (ido-buffer-internal ido-default-buffer-method nil nil nil ido-text)) + ((eq ido-exit 'insert-buffer) + (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil ido-text 'ido-enter-insert-file)) + ((eq ido-exit 'dired) (dired (concat ido-current-directory (or ido-text "")))) @@ -1969,7 +2129,8 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-record-work-directory) (funcall method ido-current-directory) (if (eq method 'dired) - (dired-goto-file (expand-file-name file)))) + (with-no-warnings + (dired-goto-file (expand-file-name file))))) ((string-match "[[*?]" filename) (setq dirname (concat ido-current-directory filename)) (ido-record-command method dirname) @@ -1997,6 +2158,7 @@ If INITIAL is non-nil, it specifies the initial input string." (setq filename (concat ido-current-directory filename)) (ido-record-command fallback filename) (ido-record-work-directory) + (run-hook-with-args 'ido-before-fallback-functions fallback) (funcall fallback filename)) ((eq method 'insert) @@ -2041,6 +2203,9 @@ If INITIAL is non-nil, it specifies the initial input string." (interactive) (let (res) (cond + (ido-incomplete-regexp + ;; Do nothing + ) ((and (memq ido-cur-item '(file dir)) (string-match "[$]" ido-text)) (let ((evar (substitute-in-file-name (concat ido-current-directory ido-text)))) @@ -2056,6 +2221,12 @@ If INITIAL is non-nil, it specifies the initial input string." (setq ido-exit 'refresh) (exit-minibuffer)))) + (ido-directory-too-big + (setq ido-directory-too-big nil) + (setq ido-text-init ido-text) + (setq ido-exit 'refresh) + (exit-minibuffer)) + ((not ido-matches) (when ido-completion-buffer (call-interactively (setq this-command ido-cannot-complete-command)))) @@ -2133,6 +2304,62 @@ If no merge has yet taken place, toggle automatic merging option." ((not ido-use-merged-list) (ido-merge-work-directories)))) +;;; Magic C-f + +(defun ido-magic-forward-char () + "Move forward in user input or perform magic action. +If no user input is present, or at end of input, perform magic actions: +C-x C-b ... C-f switch to ido-find-file. +C-x C-f ... C-f fallback to non-ido find-file. +C-x C-d ... C-f fallback to non-ido brief dired. +C-x d ... C-f fallback to non-ido dired." + (interactive) + (cond + ((not (eobp)) + (forward-char 1)) + ((memq ido-cur-item '(file dir)) + (ido-fallback-command)) + (ido-context-switch-command + (call-interactively ido-context-switch-command)) + ((eq ido-cur-item 'buffer) + (ido-enter-find-file)))) + +;;; Magic C-b + +(defun ido-magic-backward-char () + "Move backward in user input or perform magic action. +If no user input is present, or at start of input, perform magic actions: +C-x C-f C-b switch to ido-switch-buffer. +C-x C-d C-b switch to ido-switch-buffer. +C-x d C-b switch to ido-switch-buffer. +C-x C-b C-b fallback to non-ido switch-to-buffer." + (interactive) + (cond + ((> (point) (minibuffer-prompt-end)) + (forward-char -1)) + ((eq ido-cur-item 'buffer) + (ido-fallback-command)) + (ido-context-switch-command + (call-interactively ido-context-switch-command)) + (t + (ido-enter-switch-buffer)))) + +;;; Magic C-d + +(defun ido-magic-delete-char () + "Delete following char in user input or perform magic action. +If at end of user input, perform magic actions: +C-x C-f ... C-d enter dired on current directory." + (interactive) + (cond + ((not (eobp)) + (delete-char 1)) + (ido-context-switch-command + nil) + ((memq ido-cur-item '(file dir)) + (ido-enter-dired)))) + + ;;; TOGGLE FUNCTIONS (defun ido-toggle-case () @@ -2159,7 +2386,9 @@ If no merge has yet taken place, toggle automatic merging option." (defun ido-toggle-ignore () "Toggle ignoring files specified with `ido-ignore-files'." (interactive) - (setq ido-process-ignore-lists (not ido-process-ignore-lists)) + (if ido-directory-too-big + (setq ido-directory-too-big nil) + (setq ido-process-ignore-lists (not ido-process-ignore-lists))) (setq ido-text-init ido-text) (setq ido-exit 'refresh) (exit-minibuffer)) @@ -2201,9 +2430,10 @@ timestamp has not changed (e.g. with ftp or on Windows)." (defun ido-exit-minibuffer () "Exit minibuffer, but make sure we have a match if one is needed." (interactive) - (if (or (not ido-require-match) - (ido-existing-item-p)) - (throw 'exit nil))) + (if (and (or (not ido-require-match) + (ido-existing-item-p)) + (not ido-incomplete-regexp)) + (exit-minibuffer))) (defun ido-select-text () "Select the buffer or file named by the prompt. @@ -2215,19 +2445,22 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (defun ido-fallback-command () "Fallback to non-ido version of current command." (interactive) + (let ((i (length ido-text))) + (while (> i 0) + (push (aref ido-text (setq i (1- i))) unread-command-events))) (setq ido-exit 'fallback) (exit-minibuffer)) (defun ido-enter-find-file () - "Drop into find-file from buffer switching." + "Drop into `find-file' from buffer switching." (interactive) - (setq ido-exit 'findfile) + (setq ido-exit 'find-file) (exit-minibuffer)) (defun ido-enter-switch-buffer () - "Drop into ido-switch-buffer from file switching." + "Drop into `ido-switch-buffer' from file switching." (interactive) - (setq ido-exit 'findbuffer) + (setq ido-exit 'switch-to-buffer) (exit-minibuffer)) (defun ido-enter-dired () @@ -2236,6 +2469,18 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (setq ido-exit 'dired) (exit-minibuffer)) +(defun ido-enter-insert-buffer () + "Drop into insert buffer from insert file." + (interactive) + (setq ido-exit 'insert-buffer) + (exit-minibuffer)) + +(defun ido-enter-insert-file () + "Drop into insert file from insert buffer." + (interactive) + (setq ido-exit 'insert-file) + (exit-minibuffer)) + (defun ido-up-directory (&optional clear) "Go up one directory level." @@ -2289,10 +2534,11 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (not (equal dir ido-current-directory)) (file-directory-p dir) (or (not must-match) - (ido-set-matches1 + ;; TODO. check for nonreadable and too-big. + (ido-set-matches-1 (if (eq ido-cur-item 'file) - (ido-make-file-list1 dir) - (ido-make-dir-list1 dir))))) + (ido-make-file-list-1 dir) + (ido-make-dir-list-1 dir))))) (setq j n) (setq dir nil))) (if dir @@ -2336,7 +2582,9 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (unless file (let ((enable-recursive-minibuffers t)) (setq file - (read-string (concat "Wide find file: " ido-current-directory) ido-text)))) + (condition-case nil + (read-string (concat "Wide find file: " ido-current-directory) ido-text) + (quit ""))))) (when (> (length file) 0) (setq ido-use-merged-list t ido-try-merged-list 'wide) (setq ido-exit 'refresh) @@ -2350,7 +2598,9 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (unless dir (let ((enable-recursive-minibuffers t)) (setq dir - (read-string (concat "Wide find directory: " ido-current-directory) ido-text)))) + (condition-case nil + (read-string (concat "Wide find directory: " ido-current-directory) ido-text) + (quit ""))))) (when (> (length dir) 0) (setq ido-use-merged-list t ido-try-merged-list 'wide) (setq ido-exit 'refresh) @@ -2358,6 +2608,34 @@ If no buffer or file exactly matching the prompt exists, maybe create a new one. (setq ido-rotate-temp t) (exit-minibuffer))) +(defun ido-wide-find-dir-or-delete-dir (&optional dir) + "Prompt for DIR to search for using find, starting from current directory. +If input stack is non-empty, delete current directory component." + (interactive) + (if ido-input-stack + (ido-delete-backward-word-updir 1) + (ido-wide-find-dir))) + +(defun ido-push-dir () + "Move to previous directory in file name, push current input on stack." + (interactive) + (setq ido-exit 'push) + (exit-minibuffer)) + +(defun ido-pop-dir (arg) + "Pop directory from input stack back to input. +With \\[universal-argument], pop all element." + (interactive "P") + (when ido-input-stack + (setq ido-exit (if arg 'pop-all 'pop)) + (exit-minibuffer))) + +(defun ido-wide-find-file-or-pop-dir (arg) + (interactive "P") + (if ido-input-stack + (ido-pop-dir arg) + (ido-wide-find-file))) + (defun ido-make-directory (&optional dir) "Prompt for DIR to create in current directory." (interactive) @@ -2546,21 +2824,83 @@ for first matching file." (defun ido-all-completions () ;; Return unsorted list of all competions. - (let ((ido-process-ignore-lists nil)) + (let ((ido-process-ignore-lists nil) + (ido-directory-too-big nil)) (cond ((eq ido-cur-item 'file) - (ido-make-file-list1 ido-current-directory)) + (ido-make-file-list-1 ido-current-directory)) ((eq ido-cur-item 'dir) - (ido-make-dir-list1 ido-current-directory)) + (ido-make-dir-list-1 ido-current-directory)) ((eq ido-cur-item 'buffer) - (ido-make-buffer-list1)) + (ido-make-buffer-list-1)) + ((eq ido-cur-item 'list) + ido-choice-list) (t nil)))) -(defun ido-sort-list (items) - ;; Simple list of file or buffer names - (sort items (lambda (a b) (string-lessp (ido-no-final-slash a) - (ido-no-final-slash b))))) +;; File list sorting + +(defun ido-file-lessp (a b) + ;; Simple compare two file names. + (string-lessp (ido-no-final-slash a) (ido-no-final-slash b))) + + +(defun ido-file-extension-lessp (a b) + ;; Compare file names according to ido-file-extensions-order list. + (let ((n (compare-strings a 0 nil b 0 nil nil)) + lessp p) + (if (eq n t) + nil + (if (< n 0) + (setq n (1- (- n)) + p a a b b p + lessp t) + (setq n (1- n))) + (cond + ((= n 0) + lessp) + ((= (aref a n) ?.) + (ido-file-extension-aux a b n lessp)) + (t + (while (and (> n 2) (/= (aref a n) ?.)) + (setq n (1- n))) + (if (> n 1) + (ido-file-extension-aux a b n lessp) + lessp)))))) + +(defun ido-file-extension-aux (a b n lessp) + (let ((oa (ido-file-extension-order a n)) + (ob (ido-file-extension-order b n))) + (cond + ((= oa ob) + lessp) + ((and oa ob) + (if lessp + (> oa ob) + (< oa ob))) + (oa + (not lessp)) + (ob + lessp) + (t + lessp)))) + +(defun ido-file-extension-order (s n) + (let ((l ido-file-extensions-order) + (i 0) o do) + (while l + (cond + ((eq (car l) t) + (setq do i + l (cdr l))) + ((eq (compare-strings s n nil (car l) 0 nil nil) t) + (setq o i + l nil)) + (t + (setq l (cdr l)))) + (setq i (1+ i))) + (or o do))) + (defun ido-sort-merged-list (items promote) ;; Input is list of ("file" . "dir") cons cells. @@ -2610,9 +2950,9 @@ for first matching file." (setq items (cdr items))) res)) -(defun ido-make-merged-file-list (text auto wide) + +(defun ido-make-merged-file-list-1 (text auto wide) (let (res) - (message "Searching for `%s'...." text) (if (and (ido-final-slash text) ido-dir-file-cache) (if wide (setq res (ido-wide-find-dirs-or-files @@ -2663,18 +3003,33 @@ for first matching file." (or ido-merge-ftp-work-directories (not (ido-is-ftp-directory dir))) (file-directory-p dir) + ;; TODO. check for nonreadable and too-big. (setq fl (if (eq ido-cur-item 'file) - (ido-make-file-list1 dir t) - (ido-make-dir-list1 dir t)))) + (ido-make-file-list-1 dir t) + (ido-make-dir-list-1 dir t)))) (if must-match - (setq fl (ido-set-matches1 fl))) + (setq fl (ido-set-matches-1 fl))) (if fl (setq res (nconc fl res)))) (if (and auto (input-pending-p)) (setq dirs nil res t)))))) - (if (and res (not (eq res t))) - (setq res (ido-sort-merged-list res auto))) + res)) + +(defun ido-make-merged-file-list (text auto wide) + (let (res) + (message "Searching for `%s'...." text) + (condition-case nil + (if (eq t (setq res + (while-no-input + (ido-make-merged-file-list-1 text auto wide)))) + (setq res 'input-pending-p)) + (quit + (setq res t + ido-try-merged-list nil + ido-use-merged-list nil))) + (when (and res (listp res)) + (setq res (ido-sort-merged-list res auto))) (when (and (or ido-rotate-temp ido-rotate-file-list-default) (listp res) (> (length text) 0)) @@ -2685,7 +3040,7 @@ for first matching file." (message nil) res)) -(defun ido-make-buffer-list1 (&optional frame visible) +(defun ido-make-buffer-list-1 (&optional frame visible) ;; Return list of non-ignored buffer names (delq nil (mapcar @@ -2698,12 +3053,12 @@ for first matching file." (defun ido-make-buffer-list (default) ;; Return the current list of buffers. ;; Currently visible buffers are put at the end of the list. - ;; The hook `ido-make-buflist-hook' is run after the list has been + ;; The hook `ido-make-buffer-list-hook' is run after the list has been ;; created to allow the user to further modify the order of the buffer names ;; in this list. If DEFAULT is non-nil, and corresponds to an existing buffer, ;; it is put to the start of the list. (let* ((ido-current-buffers (ido-get-buffers-in-frames 'current)) - (ido-temp-list (ido-make-buffer-list1 (selected-frame) ido-current-buffers))) + (ido-temp-list (ido-make-buffer-list-1 (selected-frame) ido-current-buffers))) (if ido-temp-list (nconc ido-temp-list ido-current-buffers) (setq ido-temp-list ido-current-buffers)) @@ -2716,6 +3071,20 @@ for first matching file." (run-hooks 'ido-make-buffer-list-hook) ido-temp-list)) +(defun ido-make-choice-list (default) + ;; Return the current list of choices. + ;; If DEFAULT is non-nil, and corresponds to an element of choices, + ;; it is put to the start of the list. + (let ((ido-temp-list ido-choice-list)) + (if default + (progn + (setq ido-temp-list + (delete default ido-temp-list)) + (setq ido-temp-list + (cons default ido-temp-list)))) + ; (run-hooks 'ido-make-choice-list-hook) + ido-temp-list)) + (defun ido-to-end (items) ;; Move the elements from ITEMS to the end of `ido-temp-list' (mapcar @@ -2726,9 +3095,11 @@ for first matching file." (nconc ido-temp-list items) (setq ido-temp-list items))) -(defun ido-file-name-all-completions1 (dir) +(defun ido-file-name-all-completions-1 (dir) (cond ((ido-nonreadable-directory-p dir) '()) + ;; do not check (ido-directory-too-big-p dir) here. + ;; Caller must have done that if necessary. ((and ido-enable-tramp-completion (string-match "\\`/\\([^/:]+:\\([^/:@]+@\\)?\\)\\'" dir)) @@ -2781,13 +3152,13 @@ for first matching file." (if (and ftp (file-readable-p dir)) (setq mtime (cons 'ftp (ido-time-stamp)))) (if mtime - (setq cached (cons dir (cons mtime (ido-file-name-all-completions1 dir))) + (setq cached (cons dir (cons mtime (ido-file-name-all-completions-1 dir))) ido-dir-file-cache (cons cached ido-dir-file-cache))) (if (> (length ido-dir-file-cache) ido-max-dir-file-cache) (setcdr (nthcdr (1- ido-max-dir-file-cache) ido-dir-file-cache) nil))) (and cached (cdr (cdr cached)))) - (ido-file-name-all-completions1 dir))) + (ido-file-name-all-completions-1 dir))) (defun ido-remove-cached-dir (dir) ;; Remove dir from ido-dir-file-cache @@ -2798,7 +3169,7 @@ for first matching file." (setq ido-dir-file-cache (delq cached ido-dir-file-cache)))))) -(defun ido-make-file-list1 (dir &optional merged) +(defun ido-make-file-list-1 (dir &optional merged) ;; Return list of non-ignored files in DIR ;; If MERGED is non-nil, each file is cons'ed with DIR (and (or (ido-is-tramp-root dir) (file-directory-p dir)) @@ -2815,8 +3186,11 @@ for first matching file." ;; 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 ((ido-temp-list (ido-make-file-list-1 ido-current-directory))) + (setq ido-temp-list (sort ido-temp-list + (if ido-file-extensions-order + #'ido-file-extension-lessp + #'ido-file-lessp))) (let ((default-directory ido-current-directory)) (ido-to-end ;; move ftp hosts and visited files to end (delq nil (mapcar @@ -2848,7 +3222,7 @@ for first matching file." (run-hooks 'ido-make-file-list-hook) ido-temp-list)) -(defun ido-make-dir-list1 (dir &optional merged) +(defun ido-make-dir-list-1 (dir &optional merged) ;; Return list of non-ignored subdirs in DIR ;; If MERGED is non-nil, each subdir is cons'ed with DIR (and (or (ido-is-tramp-root dir) (file-directory-p dir)) @@ -2864,8 +3238,8 @@ for first matching file." ;; The hook `ido-make-dir-list-hook' is run after the list has been ;; created to allow the user to further modify the order of the ;; directory names in this list. - (let ((ido-temp-list (ido-make-dir-list1 ido-current-directory))) - (setq ido-temp-list (ido-sort-list ido-temp-list)) + (let ((ido-temp-list (ido-make-dir-list-1 ido-current-directory))) + (setq ido-temp-list (sort ido-temp-list #'ido-file-lessp)) (ido-to-end ;; move . files to end (delq nil (mapcar (lambda (x) (if (string-equal (substring x 0 1) ".") x)) @@ -2885,7 +3259,8 @@ for first matching file." (setq ido-temp-list (cons default ido-temp-list)))) (setq ido-temp-list (delete "." ido-temp-list)) - (setq ido-temp-list (cons "." ido-temp-list)) + (unless ido-input-stack + (setq ido-temp-list (cons "." ido-temp-list))) (run-hooks 'ido-make-dir-list-hook) ido-temp-list)) @@ -2917,7 +3292,7 @@ for first matching file." ;;; FIND MATCHING ITEMS -(defun ido-set-matches1 (items &optional do-full) +(defun ido-set-matches-1 (items &optional do-full) ;; Return list of matches in items (let* ((case-fold-search ido-case-fold) (slash (and (not ido-enable-prefix) (ido-final-slash ido-text))) @@ -2928,21 +3303,38 @@ for first matching file." (concat "\\`" re "\\'"))) (prefix-re (and full-re (not ido-enable-prefix) (concat "\\`" rexq))) + (non-prefix-dot (or (not ido-enable-dot-prefix) + (not ido-process-ignore-lists) + ido-enable-prefix + (= (length ido-text) 0))) + full-matches prefix-matches matches) - (mapcar - (lambda (item) - (let ((name (ido-name item))) - (if (string-match re name) - (cond - ((and full-re (string-match full-re name)) - (setq full-matches (cons item full-matches))) - ((and prefix-re (string-match prefix-re name)) - (setq prefix-matches (cons item prefix-matches))) - (t (setq matches (cons item matches)))))) - t) - items) + (setq ido-incomplete-regexp nil) + (condition-case error + (mapcar + (lambda (item) + (let ((name (ido-name item))) + (if (and (or non-prefix-dot + (if (= (aref ido-text 0) ?.) + (= (aref name 0) ?.) + (/= (aref name 0) ?.))) + (string-match re name)) + (cond + ((and full-re (string-match full-re name)) + (setq full-matches (cons item full-matches))) + ((and prefix-re (string-match prefix-re name)) + (setq prefix-matches (cons item prefix-matches))) + (t (setq matches (cons item matches)))))) + t) + items) + (invalid-regexp + (setq ido-incomplete-regexp t + ;; Consider the invalid regexp message internally as a + ;; special-case single match, and handle appropriately + ;; elsewhere. + matches (cdr error)))) (if prefix-matches (setq matches (nconc prefix-matches matches))) (if full-matches @@ -2966,7 +3358,7 @@ for first matching file." (defun ido-set-matches () ;; Set `ido-matches' to the list of items matching prompt (when ido-rescan - (setq ido-matches (ido-set-matches1 (reverse ido-cur-list) (not ido-rotate)) + (setq ido-matches (ido-set-matches-1 (reverse ido-cur-list) (not ido-rotate)) ido-rotate nil))) (defun ido-ignore-item-p (name re-list &optional ignore-ext) @@ -2974,38 +3366,37 @@ for first matching file." (or (member name ido-ignore-item-temp-list) (and ido-process-ignore-lists re-list - (let ((data (match-data)) - (ext-list (and ignore-ext ido-ignore-extensions + (save-match-data + (let ((ext-list (and ignore-ext ido-ignore-extensions completion-ignored-extensions)) - ignorep nextstr - (flen (length name)) slen) - (while ext-list - (setq nextstr (car ext-list)) - (if (cond - ((stringp nextstr) - (and (>= flen (setq slen (length nextstr))) - (string-equal (substring name (- flen slen)) nextstr))) - ((fboundp nextstr) (funcall nextstr name)) - (t nil)) - (setq ignorep t - ext-list nil - re-list nil) - (setq ext-list (cdr ext-list)))) - (while re-list - (setq nextstr (car re-list)) - (if (cond - ((stringp nextstr) (string-match nextstr name)) - ((fboundp nextstr) (funcall nextstr name)) - (t nil)) - (setq ignorep t - re-list nil) - (setq re-list (cdr re-list)))) - ;; return the result - (if ignorep - (setq ido-ignored-list (cons name ido-ignored-list))) - (set-match-data data) - ignorep)))) - + (case-fold-search ido-case-fold) + ignorep nextstr + (flen (length name)) slen) + (while ext-list + (setq nextstr (car ext-list)) + (if (cond + ((stringp nextstr) + (and (>= flen (setq slen (length nextstr))) + (string-equal (substring name (- flen slen)) nextstr))) + ((fboundp nextstr) (funcall nextstr name)) + (t nil)) + (setq ignorep t + ext-list nil + re-list nil) + (setq ext-list (cdr ext-list)))) + (while re-list + (setq nextstr (car re-list)) + (if (cond + ((stringp nextstr) (string-match nextstr name)) + ((fboundp nextstr) (funcall nextstr name)) + (t nil)) + (setq ignorep t + re-list nil) + (setq re-list (cdr re-list)))) + ;; return the result + (if ignorep + (setq ido-ignored-list (cons name ido-ignored-list))) + ignorep))))) ;; Private variable used by `ido-word-matching-substring'. (defvar ido-change-word-sub) @@ -3078,7 +3469,8 @@ for first matching file." (if (pos-visible-in-window-p (point-max) win) (if (or ido-completion-buffer-all-completions (boundp 'ido-completion-buffer-full)) (set-window-start win (point-min)) - (set (make-local-variable 'ido-completion-buffer-full) t) + (with-no-warnings + (set (make-local-variable 'ido-completion-buffer-full) t)) (setq full-list t display-it t)) (scroll-other-window)) @@ -3086,14 +3478,15 @@ for first matching file." (setq display-it t)) (if display-it (with-output-to-temp-buffer ido-completion-buffer - (let ((completion-list (ido-sort-list + (let ((completion-list (sort (cond (ido-use-merged-list (ido-flatten-merged-list (or ido-matches ido-cur-list))) ((or full-list ido-completion-buffer-all-completions) (ido-all-completions)) (t - (copy-sequence (or ido-matches ido-cur-list))))))) + (copy-sequence (or ido-matches ido-cur-list)))) + #'ido-file-lessp))) (if (featurep 'xemacs) ;; XEmacs extents are put on by default, doesn't seem to be ;; any way of switching them off. @@ -3147,7 +3540,7 @@ for first matching file." ;;; VISIT CHOSEN BUFFER (defun ido-visit-buffer (buffer method &optional record) "Visit file named FILE according to METHOD. -Record command in command-history if optional RECORD is non-nil." +Record command in `command-history' if optional RECORD is non-nil." (let (win newframe) (cond @@ -3220,9 +3613,9 @@ 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-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: \\ RET Select the buffer at the front of the list of matches. If the list is empty, possibly prompt to create new buffer. @@ -3262,7 +3655,7 @@ For details of keybindings, do `\\[describe-function] ido'." The buffer name is selected interactively by typing a substring. For details of keybindings, do `\\[describe-function] ido'." (interactive) - (ido-buffer-internal 'display 'display-buffer)) + (ido-buffer-internal 'display 'display-buffer nil nil nil 'ignore)) ;;;###autoload (defun ido-kill-buffer () @@ -3270,7 +3663,7 @@ For details of keybindings, do `\\[describe-function] ido'." The buffer name is selected interactively by typing a substring. For details of keybindings, do `\\[describe-function] ido'." (interactive) - (ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer)))) + (ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer)) nil 'ignore)) ;;;###autoload (defun ido-insert-buffer () @@ -3278,7 +3671,7 @@ For details of keybindings, do `\\[describe-function] ido'." The buffer name is selected interactively by typing a substring. For details of keybindings, do `\\[describe-function] ido'." (interactive) - (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: ")) + (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil nil 'ido-enter-insert-file)) ;;;###autoload (defun ido-switch-buffer-other-frame () @@ -3296,7 +3689,7 @@ For details of keybindings, do `\\[describe-function] ido'." (interactive "DDir: ") (if (not (equal (substring dir -1) "/")) (setq dir (concat dir "/"))) - (ido-file-internal ido-default-file-method nil dir)) + (ido-file-internal ido-default-file-method nil dir nil nil nil 'ignore)) ;;;###autoload (defun ido-find-file () @@ -3305,11 +3698,11 @@ 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, +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: \\ RET Select the file at the front of the list of matches. If the @@ -3389,7 +3782,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." The file name is selected interactively by typing a substring. For details of keybindings, do `\\[describe-function] ido-find-file'." (interactive) - (ido-file-internal 'display)) + (ido-file-internal 'display nil nil nil nil nil 'ignore)) ;;;###autoload (defun ido-find-file-other-frame () @@ -3411,7 +3804,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (ido-report-no-match nil) (ido-confirm-unique-completion t) (ido-auto-merge-work-directories-length -1)) - (ido-file-internal 'write 'write-file nil "Write file: "))) + (ido-file-internal 'write 'write-file nil "Write file: " nil nil 'ignore))) ;;;###autoload (defun ido-insert-file () @@ -3419,7 +3812,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." The file name is selected interactively by typing a substring. For details of keybindings, do `\\[describe-function] ido-find-file'." (interactive) - (ido-file-internal 'insert 'insert-file nil "Insert file: ")) + (ido-file-internal 'insert 'insert-file nil "Insert file: " nil nil 'ido-enter-insert-buffer)) ;;;###autoload (defun ido-dired () @@ -3500,7 +3893,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." ;; Handle explicit directory changes (cond - ((eq ido-cur-item 'buffer) + ((memq ido-cur-item '(buffer list)) ) ((= (length contents) 0) @@ -3556,7 +3949,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (expand-file-name "/" ido-current-directory) "/")) (setq refresh t)) - ((and ido-directory-nonreadable + ((and (or ido-directory-nonreadable ido-directory-too-big) (file-directory-p (concat ido-current-directory (file-name-directory contents)))) (ido-set-current-directory (concat ido-current-directory (file-name-directory contents))) @@ -3604,12 +3997,13 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (ido-set-matches) (ido-trace "new " ido-matches) - (when (and ido-enter-single-matching-directory + (when (and ido-enter-matching-directory ido-matches - (null (cdr ido-matches)) + (or (eq ido-enter-matching-directory 'first) + (null (cdr ido-matches))) (ido-final-slash (car ido-matches)) (or try-single-dir-match - (eq ido-enter-single-matching-directory t))) + (eq ido-enter-matching-directory t))) (ido-trace "single match" (car ido-matches)) (ido-set-current-directory (concat ido-current-directory (car ido-matches))) @@ -3618,6 +4012,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (when (and (not ido-matches) (not ido-directory-nonreadable) + (not ido-directory-too-big) ;; ido-rescan ? ido-process-ignore-lists ido-ignored-list) @@ -3641,7 +4036,8 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (not (ido-is-root-directory)) (> (length contents) 1) (not (string-match "[$]" contents)) - (not ido-directory-nonreadable)) + (not ido-directory-nonreadable) + (not ido-directory-too-big)) (ido-trace "merge?") (if ido-use-merged-list (ido-undo-merge-work-directory contents nil) @@ -3688,7 +4084,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." first) (if (and ind ido-use-faces) - (put-text-property 0 1 'face 'ido-indicator-face ind)) + (put-text-property 0 1 'face 'ido-indicator ind)) (if (and ido-use-faces comps) (let* ((fn (ido-name (car comps))) @@ -3696,8 +4092,10 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (setq first (format "%s" fn)) (put-text-property 0 ln 'face (if (= (length comps) 1) - 'ido-only-match-face - 'ido-first-match-face) + (if ido-incomplete-regexp + 'ido-incomplete-regexp + 'ido-only-match) + 'ido-first-match) first) (if ind (setq first (concat first ind))) (setq comps (cons first (cdr comps))))) @@ -3706,17 +4104,27 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (cond (ido-directory-nonreadable (or (nth 8 ido-decorations) " [Not readable]")) + (ido-directory-too-big + (or (nth 9 ido-decorations) " [Too big]")) (ido-report-no-match (nth 6 ido-decorations)) ;; [No match] (t ""))) - + (ido-incomplete-regexp + (concat " " (car comps))) ((null (cdr comps)) ;one match - (concat (if (> (length (ido-name (car comps))) (length name)) - ;; when there is one match, show the matching file name in full - (concat (nth 4 ido-decorations) ;; [ ... ] - (ido-name (car comps)) - (nth 5 ido-decorations)) - "") + (concat (if (if (not ido-enable-regexp) + (= (length (ido-name (car comps))) (length name)) + ;; We can't rely on the length of the input + ;; for regexps, so explicitly check for a + ;; complete match + (string-match name (ido-name (car comps))) + (string-equal (match-string 0 (ido-name (car comps))) + (ido-name (car comps)))) + "" + ;; when there is one match, show the matching file name in full + (concat (nth 4 ido-decorations) ;; [ ... ] + (ido-name (car comps)) + (nth 5 ido-decorations))) (if (not ido-use-faces) (nth 7 ido-decorations)))) ;; [Matched] (t ;multiple matches (let* ((items (if (> ido-max-prospects 0) (1+ ido-max-prospects) 999)) @@ -3738,7 +4146,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (if (and ido-use-faces (not (string= str first)) (ido-final-slash str)) - (put-text-property 0 (length str) 'face 'ido-subdir-face str)) + (put-text-property 0 (length str) 'face 'ido-subdir str)) str))))) comps)))))) @@ -3810,43 +4218,88 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." ;;; Helper functions for other programs (put 'dired-do-rename 'ido 'ignore) +(put 'ibuffer-find-file 'ido 'find-file) +(put 'dired-other-window 'ido 'dir) + +;;;###autoload +(defun ido-read-buffer (prompt &optional default require-match) + "Ido replacement for the built-in `read-buffer'. +Return the name of a buffer selected. +PROMPT is the prompt to give to the user. DEFAULT if given is the default +buffer to be selected, which will go to the front of the list. +If REQUIRE-MATCH is non-nil, an existing buffer must be selected." + (let* ((ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (ido-context-switch-command 'ignore) + (buf (ido-read-internal 'buffer prompt 'ido-buffer-history default require-match))) + (if (eq ido-exit 'fallback) + (let ((read-buffer-function nil)) + (run-hook-with-args 'ido-before-fallback-functions 'read-buffer) + (read-buffer prompt default require-match)) + buf))) ;;;###autoload (defun ido-read-file-name (prompt &optional dir default-filename mustmatch initial predicate) - "Read file name, prompting with PROMPT and completing in directory DIR. + "Ido replacement for the built-in `read-file-name'. +Read file name, prompting with PROMPT and completing in directory DIR. See `read-file-name' for additional parameters." - (cond - ((or (eq predicate 'file-directory-p) - (eq (get this-command 'ido) 'dir) - (memq this-command ido-read-file-name-as-directory-commands)) - (ido-read-directory-name prompt dir default-filename mustmatch initial)) - ((and (not (eq (get this-command 'ido) 'ignore)) - (not (memq this-command ido-read-file-name-non-ido)) - (or (null predicate) (eq predicate 'file-exists-p))) - (let* (filename - ido-saved-vc-hb - (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) - (ido-current-directory (ido-expand-directory dir)) - (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) - (ido-work-directory-index -1) - (ido-work-file-index -1) - (ido-find-literal nil)) - (setq filename - (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial)) - (if filename - (concat ido-current-directory filename)))) - (t - (let ((read-file-name-function nil)) - (read-file-name prompt dir default-filename mustmatch initial predicate))))) + (let (filename) + (cond + ((or (eq predicate 'file-directory-p) + (eq (get this-command 'ido) 'dir) + (memq this-command ido-read-file-name-as-directory-commands)) + (setq filename + (ido-read-directory-name prompt dir default-filename mustmatch initial)) + (if (eq ido-exit 'fallback) + (setq filename 'fallback))) + ((and (not (eq (get this-command 'ido) 'ignore)) + (not (memq this-command ido-read-file-name-non-ido)) + (or (null predicate) (eq predicate 'file-exists-p))) + (let* (ido-saved-vc-hb + (ido-context-switch-command + (if (eq (get this-command 'ido) 'find-file) nil 'ignore)) + (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) + (minibuffer-completing-file-name t) + (ido-current-directory (ido-expand-directory dir)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory))) + (ido-work-directory-index -1) + (ido-work-file-index -1) + (ido-find-literal nil)) + (setq ido-exit nil) + (setq filename + (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial)) + (cond + ((eq ido-exit 'fallback) + (setq filename 'fallback)) + ((eq ido-exit 'dired) + (setq filename ido-current-directory)) + (filename + (setq filename + (concat ido-current-directory filename)))))) + (t + (setq filename 'fallback))) + (if (eq filename 'fallback) + (let ((read-file-name-function nil)) + (run-hook-with-args 'ido-before-fallback-functions 'read-file-name) + (read-file-name prompt dir default-filename mustmatch initial predicate)) + filename))) ;;;###autoload (defun ido-read-directory-name (prompt &optional dir default-dirname mustmatch initial) - "Read directory name, prompting with PROMPT and completing in directory DIR. -See `read-file-name' for additional parameters." + "Ido replacement for the built-in `read-directory-name'. +Read directory name, prompting with PROMPT and completing in directory DIR. +See `read-directory-name' for additional parameters." (let* (filename + (minibuffer-completing-file-name t) + (ido-context-switch-command 'ignore) ido-saved-vc-hb (ido-current-directory (ido-expand-directory dir)) (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory))) (ido-work-directory-index -1) (ido-work-file-index -1)) (setq filename @@ -3856,5 +4309,29 @@ See `read-file-name' for additional parameters." ido-current-directory (concat ido-current-directory filename))))) +;;;###autoload +(defun ido-completing-read (prompt choices &optional predicate require-match initial-input hist def) + "Ido replacement for the built-in `completing-read'. +Read a string in the minibuffer with ido-style completion. +PROMPT is a string to prompt with; normally it ends in a colon and a space. +CHOICES is a list of strings which are the possible completions. +PREDICATE is currently ignored; it is included to be compatible + with `completing-read'. +If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless + the input is (or completes to) an element of CHOICES or is null. + If the input is null, `ido-completing-read' returns DEF, or an empty + string if DEF is nil, regardless of the value of REQUIRE-MATCH. +If INITIAL-INPUT is non-nil, insert it in the minibuffer initially, + with point positioned at the end. +HIST, if non-nil, specifies a history list. +DEF, if non-nil, is the default value." + (let ((ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (ido-context-switch-command 'ignore) + (ido-choice-list choices)) + (ido-read-internal 'list prompt hist def require-match initial-input))) + + ;;; arch-tag: b63a3500-1735-41bd-8a01-05373f0864da ;;; ido.el ends here