;;; ido.el --- interactively do things with buffers and files.
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-;; 2004, 2005, 2006 Free Software Foundation, Inc.
+;; 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Author: Kim F. Storm <storm@cua.dk>
;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
(defvar ido-incomplete-regexp nil
"Non-nil if an incomplete regexp is entered.")
+(defvar ido-initial-position nil
+ "Non-nil means to explicitly cursor on entry to minibuffer.
+Value is an integer which is number of chars to right of prompt.")
+
;;; Variables with dynamic bindings.
;;; Declared here to keep the byte compiler quiet.
;; Stores the current ido item type ('file, 'dir, 'buffer, or 'list).
(defvar ido-cur-item)
+;;; Stores the current default item
+(defvar ido-default-item)
+
;; Stores the current list of items that will be searched through.
;; The list is ordered, so that the most interesting item comes first,
;; although by default, the files visible in the current frame are put
(defun ido-active (&optional merge)
(if merge
ido-use-merged-list
- (and (boundp 'ido-completing-read) (= ido-use-mycompletion-depth (minibuffer-depth)))))
+ (and (boundp 'ido-completing-read)
+ (or (featurep 'xemacs)
+ (= ido-use-mycompletion-depth (minibuffer-depth))))))
(defvar ido-trace-enable nil)
(pop-to-buffer b t t)
(setq truncate-lines t)))))
+(defun ido-local-file-exists-p (file)
+ "Tell if FILE exists locally."
+ (let (file-name-handler-alist)
+ (file-exists-p file)))
+
(defun ido-unc-hosts (&optional query)
"Return list of UNC host names."
(let ((hosts
(define-key map [(meta down)] 'ido-next-work-directory)
(define-key map [backspace] 'ido-delete-backward-updir)
(define-key map "\d" 'ido-delete-backward-updir)
- (define-key map [(meta backspace)] 'ido-delete-backward-word-updir)
+ (define-key map [remap backward-kill-word] 'ido-delete-backward-word-updir) ; M-DEL
+
(define-key map [(control backspace)] 'ido-up-directory)
(define-key map "\C-l" 'ido-reread-directory)
(define-key map [(meta ?d)] 'ido-wide-find-dir-or-delete-dir)
(if (member ido-default-item ido-ignore-item-temp-list)
(setq ido-default-item nil))
(ido-trace "new default" ido-default-item)
+ (if ido-default-item
+ (setq ido-initial-position 0))
(setq ido-set-default-item nil))
(if ido-process-ignore-lists-inhibit
(ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))))
(setq ido-set-default-item t))
- ((and (string-match (if ido-enable-tramp-completion "..[:@]\\'" "..:\\'") ido-selected)
- (ido-is-root-directory)) ;; Ange-ftp or Tramp
+ ((and (string-match (if ido-enable-tramp-completion ".[:@]\\'" ".:\\'") ido-selected)
+ (ido-is-root-directory) ;; Ange-ftp or Tramp
+ (not (ido-local-file-exists-p ido-selected)))
(ido-set-current-directory ido-current-directory ido-selected)
(ido-trace "tramp prefix" ido-selected)
(if (ido-is-slow-ftp-host)
((or (string-match "[/\\][^/\\]" ido-selected)
(and (memq system-type '(windows-nt ms-dos))
- (string-match "\\`.:" ido-selected)))
+ (string-match "\\`[a-zA-Z]:" ido-selected)))
(ido-set-current-directory (file-name-directory ido-selected))
(setq ido-set-default-item t))
ido-selected))
(defun ido-edit-input ()
- "Edit absolute file name entered so far with ido; terminate by RET."
+ "Edit absolute file name entered so far with ido; terminate by RET.
+If cursor is not at the end of the user input, move to end of input."
(interactive)
- (setq ido-text-init (if ido-matches (ido-name (car ido-matches)) ido-text))
- (setq ido-exit 'edit)
- (exit-minibuffer))
+ (if (not (eobp))
+ (end-of-line)
+ (setq ido-text-init (if ido-matches (ido-name (car ido-matches)) ido-text))
+ (setq ido-exit 'edit)
+ (exit-minibuffer)))
;;; MAIN FUNCTIONS
(defun ido-buffer-internal (method &optional fallback prompt default initial switch-cmd)
(let ((minibuffer-completing-file-name t))
(setq filename (ido-read-internal item
(or prompt "Find file: ")
- 'ido-file-history nil nil initial))))
+ 'ido-file-history
+ (and (eq method 'alt-file) buffer-file-name)
+ nil initial))))
;; Choose the file name: either the text typed in, or the head
;; of the list of matches
(defun ido-set-common-completion ()
;; Find common completion of `ido-text' in `ido-matches'
;; The result is stored in `ido-common-match-string'
- (let* (val)
- (setq ido-common-match-string nil)
+ (let (val)
+ (setq ido-common-match-string nil)
(if (and ido-matches
(not ido-enable-regexp) ;; testing
(stringp ido-text)
((and (= 1 (length ido-matches))
(not (and ido-enable-tramp-completion
(string-equal ido-current-directory "/")
- (string-match "..[@:]\\'" (ido-name (car ido-matches))))))
+ (string-match ".[@:]\\'" (ido-name (car ido-matches)))))
+ (not (ido-local-file-exists-p (ido-name (car ido-matches)))))
;; only one choice, so select it.
(if (not ido-confirm-unique-completion)
(exit-minibuffer)
(cond
((> (point) (minibuffer-prompt-end))
(forward-char -1))
+ ((eq last-command this-command)
+ (when (and (memq ido-cur-item '(file dir))
+ (not (bobp)))
+ (ido-push-dir))) ; else do nothing
((eq ido-cur-item 'buffer)
(ido-fallback-command))
(ido-context-switch-command
(defun ido-toggle-ignore ()
"Toggle ignoring files specified with `ido-ignore-files'."
(interactive)
- (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))
+ (if (and (not (eobp)) (> (point) (minibuffer-prompt-end)))
+ (goto-char (minibuffer-prompt-end))
+ (if ido-directory-too-big
+ (progn
+ (message "Reading directory...")
+ (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)))
(defun ido-toggle-vc ()
"Disable version control for this file."
(let ((word (save-excursion
(set-buffer ido-entry-buffer)
(let ((p (point)) start-line end-line start-name name)
- (beginning-of-line)
- (setq start-line (point))
- (end-of-line)
- (setq end-line (point))
- (goto-char p)
- (if (re-search-backward "[^-_a-zA-Z0-9:./\\~@]" start-line 1)
- (forward-char 1))
- (setq start-name (point))
- (re-search-forward "[-_a-zA-Z0-9:./\\~@]*" end-line 1)
- (if (= start-name (point))
- nil
- (buffer-substring-no-properties start-name (point)))))))
+ (if (and mark-active (/= p (mark)))
+ (setq start-name (mark))
+ (beginning-of-line)
+ (setq start-line (point))
+ (end-of-line)
+ (setq end-line (point))
+ (goto-char p)
+ (if (re-search-backward "[^-_a-zA-Z0-9:./\\~@]" start-line 1)
+ (forward-char 1))
+ (setq start-name (point))
+ (re-search-forward "[-_a-zA-Z0-9:./\\~@]*" end-line 1)
+ (if (= start-name (point))
+ (setq start-name nil)))
+ (and start-name
+ (buffer-substring-no-properties start-name (point)))))))
(if (cond
((not word) nil)
((string-match "\\`[~/]" word)
(let ((default-directory ido-current-directory))
(ido-to-end ;; move ftp hosts and visited files to end
(delq nil (mapcar
- (lambda (x) (if (or (string-match "..:\\'" x)
+ (lambda (x) (if (or (and (string-match ".:\\'" x)
+ (not (ido-local-file-exists-p x)))
(and (not (ido-final-slash x))
- (get-file-buffer x))) x))
+ (let (file-name-handler-alist)
+ (get-file-buffer x)))) x))
ido-temp-list)))))
(ido-to-end ;; move . files to end
(delq nil (mapcar
(/= (aref name 0) ?.)))
(string-match re name))
(cond
+ ((and (eq ido-cur-item 'buffer)
+ (or (not (stringp ido-default-item))
+ (not (string= name ido-default-item)))
+ (string= name (buffer-name ido-entry-buffer)))
+ (setq matches (cons item matches)))
((and full-re (string-match full-re name))
(setq full-matches (cons item full-matches)))
((and suffix-re (string-match suffix-re name))
(set-buffer temp-buf)
(setq win (get-buffer-window temp-buf))
(if (pos-visible-in-window-p (point-max) win)
- (if (or ido-completion-buffer-all-completions (boundp 'ido-completion-buffer-full))
+ (if (or ido-completion-buffer-all-completions
+ (boundp 'ido-completion-buffer-full))
(set-window-start win (point-min))
(with-no-warnings
(set (make-local-variable 'ido-completion-buffer-full) t))
(with-output-to-temp-buffer ido-completion-buffer
(let ((completion-list (sort
(cond
+ (ido-directory-too-big
+ (message "Reading directory...")
+ (setq ido-directory-too-big nil
+ ido-ignored-list nil
+ ido-cur-list (ido-all-completions)
+ ido-rescan t)
+ (ido-set-matches)
+ (or ido-matches ido-cur-list))
(ido-use-merged-list
(ido-flatten-merged-list (or ido-matches ido-cur-list)))
((or full-list ido-completion-buffer-all-completions)
;;; KILL CURRENT BUFFER
(defun ido-kill-buffer-at-head ()
- "Kill the buffer at the head of `ido-matches'."
+ "Kill the buffer at the head of `ido-matches'.
+If cursor is not at the end of the user input, delete to end of input."
(interactive)
- (let ((enable-recursive-minibuffers t)
- (buf (ido-name (car ido-matches))))
- (when buf
- (kill-buffer buf)
- ;; Check if buffer still exists.
- (if (get-buffer buf)
- ;; buffer couldn't be killed.
- (setq ido-rescan t)
- ;; else buffer was killed so remove name from list.
- (setq ido-cur-list (delq buf ido-cur-list))))))
+ (if (not (eobp))
+ (kill-line)
+ (let ((enable-recursive-minibuffers t)
+ (buf (ido-name (car ido-matches))))
+ (when buf
+ (kill-buffer buf)
+ ;; Check if buffer still exists.
+ (if (get-buffer buf)
+ ;; buffer couldn't be killed.
+ (setq ido-rescan t)
+ ;; else buffer was killed so remove name from list.
+ (setq ido-cur-list (delq buf ido-cur-list)))))))
;;; DELETE CURRENT FILE
(defun ido-delete-file-at-head ()
- "Delete the file at the head of `ido-matches'."
+ "Delete the file at the head of `ido-matches'.
+If cursor is not at the end of the user input, delete to end of input."
(interactive)
- (let ((enable-recursive-minibuffers t)
- (file (ido-name (car ido-matches))))
- (if file
- (setq file (concat ido-current-directory file)))
- (when (and file
- (file-exists-p file)
- (not (file-directory-p file))
- (file-writable-p ido-current-directory)
- (yes-or-no-p (concat "Delete " file "? ")))
- (delete-file file)
- ;; Check if file still exists.
- (if (file-exists-p file)
- ;; file could not be deleted
- (setq ido-rescan t)
- ;; else file was killed so remove name from list.
- (setq ido-cur-list (delq (car ido-matches) ido-cur-list))))))
+ (if (not (eobp))
+ (kill-line)
+ (let ((enable-recursive-minibuffers t)
+ (file (ido-name (car ido-matches))))
+ (if file
+ (setq file (concat ido-current-directory file)))
+ (when (and file
+ (file-exists-p file)
+ (not (file-directory-p file))
+ (file-writable-p ido-current-directory)
+ (yes-or-no-p (concat "Delete " file "? ")))
+ (delete-file file)
+ ;; Check if file still exists.
+ (if (file-exists-p file)
+ ;; file could not be deleted
+ (setq ido-rescan t)
+ ;; else file was killed so remove name from list.
+ (setq ido-cur-list (delq (car ido-matches) ido-cur-list)))))))
;;; VISIT CHOSEN BUFFER
(defun ido-switch-buffer-other-window ()
"Switch to another buffer and show it in another window.
The buffer name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido'."
+For details of keybindings, see `ido-switch-buffer'."
(interactive)
(ido-buffer-internal 'other-window 'switch-to-buffer-other-window))
(defun ido-display-buffer ()
"Display a buffer in another window but don't select it.
The buffer name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido'."
+For details of keybindings, see `ido-switch-buffer'."
(interactive)
(ido-buffer-internal 'display 'display-buffer nil nil nil 'ignore))
(defun ido-kill-buffer ()
"Kill a buffer.
The buffer name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido'."
+For details of keybindings, see `ido-switch-buffer'."
(interactive)
(ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer)) nil 'ignore))
(defun ido-insert-buffer ()
"Insert contents of a buffer in current buffer after point.
The buffer name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido'."
+For details of keybindings, see `ido-switch-buffer'."
(interactive)
(ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil nil 'ido-enter-insert-file))
(defun ido-switch-buffer-other-frame ()
"Switch to another buffer and show it in another frame.
The buffer name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido'."
+For details of keybindings, see `ido-switch-buffer'."
(interactive)
(if ido-mode
(ido-buffer-internal 'other-frame)
(defun ido-find-file-other-window ()
"Switch to another file and show it in another window.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'other-window 'find-file-other-window))
(defun ido-find-alternate-file ()
"Switch to another file and show it in another window.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'alt-file 'find-alternate-file nil "Find alternate file: "))
(defun ido-find-file-read-only ()
"Edit file read-only with name obtained via minibuffer.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'read-only 'find-file-read-only nil "Find file read-only: "))
(defun ido-find-file-read-only-other-window ()
"Edit file read-only in other window with name obtained via minibuffer.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'read-only 'find-file-read-only-other-window nil "Find file read-only other window: "))
(defun ido-find-file-read-only-other-frame ()
"Edit file read-only in other frame with name obtained via minibuffer.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'read-only 'find-file-read-only-other-frame nil "Find file read-only other frame: "))
(defun ido-display-file ()
"Display a file in another window but don't select it.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'display nil nil nil nil nil 'ignore))
(defun ido-find-file-other-frame ()
"Switch to another file and show it in another frame.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'other-frame 'find-file-other-frame))
(defun ido-write-file ()
"Write current buffer to a file.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(let ((ido-process-ignore-lists t)
(ido-work-directory-match-only nil)
(defun ido-insert-file ()
"Insert contents of file in current buffer.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(ido-file-internal 'insert 'insert-file nil "Insert file: " nil nil 'ido-enter-insert-buffer))
(defun ido-dired ()
"Call `dired' the ido way.
The directory is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(let ((ido-report-no-match nil)
(ido-auto-merge-work-directories-length -1))
(defun ido-list-directory ()
"Call `list-directory' the ido way.
The directory is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+For details of keybindings, see `ido-find-file'."
(interactive)
(let ((ido-report-no-match nil)
(ido-auto-merge-work-directories-length -1))
(ido-trace "\n*merge timeout*" buffer)
(setq ido-auto-merge-timer nil)
(when (and (buffer-live-p buffer)
- (= ido-use-mycompletion-depth (minibuffer-depth))
+ (ido-active)
(boundp 'ido-eoinput) ido-eoinput)
(let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) ido-eoinput)))
(ido-trace "request merge")
;; 1. It prints a default file name when there is no text yet entered.
;; 2. It calls my completion routine rather than the standard completion.
- (when (= ido-use-mycompletion-depth (minibuffer-depth))
+ (when (ido-active)
(let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) (point-max)))
(buffer-undo-list t)
try-single-dir-match
(setq refresh t))
))
- ((and (string-match (if ido-enable-tramp-completion "..[:@]\\'" "..:\\'") contents)
- (ido-is-root-directory)) ;; Ange-ftp or tramp
+ ((and (string-match (if ido-enable-tramp-completion ".[:@]\\'" ".:\\'") contents)
+ (ido-is-root-directory) ;; Ange-ftp or tramp
+ (not (ido-local-file-exists-p contents)))
(ido-set-current-directory ido-current-directory contents)
(when (ido-is-slow-ftp-host)
(setq ido-exit 'fallback)
(defun ido-minibuffer-setup ()
"Minibuffer setup hook for `ido'."
;; Copied from `icomplete-minibuffer-setup-hook'.
- (when (and (boundp 'ido-completing-read)
- (or (featurep 'xemacs)
- (= ido-use-mycompletion-depth (minibuffer-depth))))
+ (when (ido-active)
(add-hook 'pre-command-hook 'ido-tidy nil t)
(add-hook 'post-command-hook 'ido-exhibit nil t)
(setq cua-inhibit-cua-keys t)
(when (featurep 'xemacs)
(ido-exhibit)
(goto-char (point-min)))
- (run-hooks 'ido-minibuffer-setup-hook)))
+ (run-hooks 'ido-minibuffer-setup-hook)
+ (when ido-initial-position
+ (goto-char (+ (minibuffer-prompt-end) ido-initial-position))
+ (setq ido-initial-position nil))))
(defun ido-tidy ()
"Pre command hook for `ido'."
(cancel-timer ido-auto-merge-timer)
(setq ido-auto-merge-timer nil))
- (if (and (boundp 'ido-use-mycompletion-depth)
- (= ido-use-mycompletion-depth (minibuffer-depth)))
+ (if (ido-active)
(if (and (boundp 'ido-eoinput)
ido-eoinput)