;;; ido.el --- interactively do things with buffers and files.
-;; Copyright (C) 1996-2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+;; 2004, 2005 Free Software Foundation, Inc.
;; Author: Kim F. Storm <storm@cua.dk>
;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
;; 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
;; 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.
;; 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
;; -----------------
;;
;; 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
;; ------------
;; 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).
;;;###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...)
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)
"*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
-of for files with an unlisted file extension."
+for files with an unlisted file extension."
:type '(repeat (choice string
(const :tag "Default order" t)))
:group 'ido)
`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)
(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)
(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)
(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)
(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)
: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
:group 'ido)
(defcustom ido-setup-hook nil
- "*Hook run after the ido variables and keymap has been setup.
+ "*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'."
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)
: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 '((((min-colors 88) (class color))
+(defface ido-subdir '((((min-colors 88) (class color))
(:foreground "red1"))
(((class color))
(:foreground "red"))
"*Font used by ido for highlighting subdirs in the alternatives."
:group 'ido)
-(defface ido-indicator-face '((((min-colors 88) (class color))
+(defface ido-indicator '((((min-colors 88) (class color))
(:foreground "yellow1"
:background "red1"
:width condensed))
"*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
(defcustom ido-read-file-name-as-directory-commands '()
"List of commands which uses read-file-name to read a directory name.
When `ido-everywhere' is non-nil, the commands in this list will read
-the directory using ido-read-directory-name."
+the directory using `ido-read-directory-name'."
:type '(repeat symbol)
:group 'ido)
(defcustom ido-read-file-name-non-ido '()
"List of commands which shall not read file names the ido way.
When `ido-everywhere' is non-nil, the commands in this list will read
-the file name using normal read-file-name style."
+the file name using normal `read-file-name' style."
:type '(repeat symbol)
:group 'ido)
+(defcustom ido-before-fallback-functions '()
+ "List of functions to call before calling a fallback command.
+The fallback command is passed as an argument to the functions."
+ :type 'hook
+ :group 'ido)
+
;;; Internal Variables
;; Persistent variables
(defvar ido-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.
(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
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.")
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.
(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))
(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)
(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" (or ido-context-switch-command 'ido-enter-switch-buffer))
- (define-key map "\C-d" (or (and ido-context-switch-command 'ignore) '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)
(define-key map [(meta backspace)] 'ido-delete-backward-word-updir)
(define-key map [(control backspace)] 'ido-up-directory)
(define-key map "\C-l" 'ido-reread-directory)
- (define-key map [(meta ?d)] 'ido-wide-find-dir)
+ (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 ?O)] 'ido-next-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)
)
)
(when (eq ido-cur-item 'buffer)
- (define-key map "\C-f" (or ido-context-switch-command 'ido-enter-find-file))
- (define-key map "\C-b" 'ido-fallback-command)
+ (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)
)
(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)
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))
(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))
+ (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)
((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.
(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
(setq item 'file))
(let ((ido-current-directory (ido-expand-directory default))
(ido-context-switch-command switch-cmd)
- ido-directory-nonreadable ido-directory-too-big
+ ido-directory-nonreadable ido-directory-too-big
+ (minibuffer-completing-file-name t)
filename)
(if (or (not ido-mode) (ido-is-slow-ftp-host))
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))
;; 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 'switch-to-buffer)
(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)
(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))))
((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 ()
(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))
+ (if (and (or (not ido-require-match)
+ (ido-existing-item-p))
+ (not ido-incomplete-regexp))
(exit-minibuffer)))
(defun ido-select-text ()
(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 '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 'switch-to-buffer)
(exit-minibuffer))
(file-directory-p dir)
(or (not must-match)
;; TODO. check for nonreadable and too-big.
- (ido-set-matches1
+ (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
(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)
(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))))
(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)
- (condition-case nil
- (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)))
+ (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 (and dir (stringp dir)
- (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))))
- (if must-match
- (setq fl (ido-set-matches1 fl)))
- (if fl
- (setq res (nconc fl res))))
+ (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))))))
- (quit (setq res t)))
- (if (and res (not (eq res t)))
- (setq res (ido-sort-merged-list res auto)))
+ (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)
+ ;; TODO. check for nonreadable and too-big.
+ (setq fl (if (eq ido-cur-item 'file)
+ (ido-make-file-list-1 dir t)
+ (ido-make-dir-list-1 dir t))))
+ (if must-match
+ (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))))))
+ 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))
(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
(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))
(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.
(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
(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))
;; 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)))
+ (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
(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))
;; 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)))
+ (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
;;; 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)))
full-matches
prefix-matches
matches)
- (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)
+ (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
(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)
(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)
;;; 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
As you type in a string, all of the buffers matching the string are
displayed if substring-matching is used \(default). Look at
-`ido-enable-prefix' and `ido-toggle-prefix'. When you have found the
-buffer you want, it can then be selected. As you type, most keys have their
-normal keybindings, except for the following: \\<ido-mode-map>
+`ido-enable-prefix' and `ido-toggle-prefix'. When you have found the
+buffer you want, it can then be selected. As you type, most keys have
+their normal keybindings, except for the following: \\<ido-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.
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: \\<ido-mode-map>
RET Select the file at the front of the list of matches. If the
(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)))
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)))
(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)))))
(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))
(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))))))
;;; 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)
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 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)
(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)))
(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)))
+ (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 'ignore)
+ (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)
(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))))))
(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)))
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))