;;; 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>
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;(setq ido-ignore-files '("^ " "\\.c$" "\\.h$"))
(defcustom ido-default-file-method 'raise-frame
- "*How to visit a new file when using `ido-find-file'.
+ "*How to visit a new file when using `ido-find-file'.
Possible values:
`selected-window' Show new file in selected window
`other-window' Show new file in another window (same frame)
:group 'ido)
(defcustom ido-default-buffer-method 'raise-frame
- "*How to switch to new buffer when using `ido-switch-buffer'.
+ "*How to switch to new buffer when using `ido-switch-buffer'.
See `ido-default-file-method' for details."
:type '(choice (const :tag "Show in selected window" selected-window)
(const :tag "Show in other window" other-window)
(defcustom ido-minibuffer-setup-hook nil
"*Ido-specific customization of minibuffer setup.
-This hook is run during minibuffer setup iff `ido' will be active.
+This hook is run during minibuffer setup if `ido' is active.
It is intended for use in customizing ido for interoperation
with other packages. For instance:
(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.
(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)
(unwind-protect
(with-current-buffer buf
(erase-buffer)
+ (insert ";;; -*- coding: utf-8 -*-\n")
+ (setq buffer-file-coding-system 'utf-8)
(ido-pp 'ido-last-directory-list)
(ido-pp 'ido-work-directory-list)
(ido-pp 'ido-work-file-list)
(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 [remap delete-backward-char] 'ido-delete-backward-updir) ; BS
(define-key map [remap backward-kill-word] 'ido-delete-backward-word-updir) ; M-DEL
(define-key map [(control backspace)] 'ido-up-directory)
(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
(if (and ido-matches (eq ido-try-merged-list 'auto))
(setq ido-try-merged-list t))
(let
- ((minibuffer-local-completion-map ido-completion-map)
- (minibuffer-local-filename-completion-map ido-completion-map)
+ ((minibuffer-local-completion-map
+ (if (memq ido-cur-item '(file dir))
+ minibuffer-local-completion-map
+ ido-completion-map))
+ (minibuffer-local-filename-completion-map
+ (if (memq ido-cur-item '(file dir))
+ ido-completion-map
+ minibuffer-local-filename-completion-map))
(max-mini-window-height (or ido-max-window-height
(and (boundp 'max-mini-window-height) max-mini-window-height)))
(ido-completing-read t)
ido-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)
((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))))
+ (setq this-command (or fallback 'switch-to-buffer))
+ (run-hook-with-args 'ido-before-fallback-functions this-command)
+ (call-interactively this-command)))
;; Check buf is non-nil.
((not buf) nil)
;; View buffer if it exists
((get-buffer buf)
+ (add-to-history 'buffer-name-history buf)
(if (eq method 'insert)
(progn
(ido-record-command 'insert-buffer buf)
;; create a new buffer
(t
+ (add-to-history 'buffer-name-history buf)
(setq buf (get-buffer-create buf))
(if (fboundp 'set-buffer-major-mode)
(set-buffer-major-mode buf))
filename t))
((and ido-use-filename-at-point
- (setq fn (if (eq ido-use-filename-at-point 'guess)
- (with-no-warnings (ffap-guesser))
- (ffap-string-at-point)))
+ (setq fn (with-no-warnings
+ (if (eq ido-use-filename-at-point 'guess)
+ (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))))
+ (setq this-command (or fallback 'find-file))
+ (run-hook-with-args 'ido-before-fallback-functions this-command)
+ (call-interactively this-command)))
((eq ido-exit 'switch-to-buffer)
(ido-buffer-internal ido-default-buffer-method nil nil nil ido-text))
((eq method 'write)
(ido-record-work-file filename)
(setq default-directory ido-current-directory)
- (ido-record-command 'write-file (concat ido-current-directory filename))
+ (setq filename (concat ido-current-directory filename))
+ (ido-record-command 'write-file filename)
+ (add-to-history 'file-name-history filename)
(ido-record-work-directory)
- (write-file (concat ido-current-directory filename)))
+ (write-file filename))
((eq method 'read-only)
(ido-record-work-file filename)
(ido-record-command
(if ido-find-literal 'insert-file-literally 'insert-file)
filename)
+ (add-to-history 'file-name-history filename)
(ido-record-work-directory)
(insert-file-1 filename
(if ido-find-literal
(ido-record-work-file filename)
(setq filename (concat ido-current-directory filename))
(ido-record-command 'find-file filename)
+ (add-to-history 'file-name-history filename)
(ido-record-work-directory)
(ido-visit-buffer (find-file-noselect filename nil ido-find-literal) method))))))
(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)
(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
- (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))
+ (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."
(defun ido-to-end (items)
;; Move the elements from ITEMS to the end of `ido-temp-list'
- (mapcar
+ (mapc
(lambda (elem)
(setq ido-temp-list (delq elem ido-temp-list)))
items)
(nconc ido-temp-list items)
(setq ido-temp-list items)))
+(declare-function tramp-tramp-file-p "net/tramp" (name))
+
(defun ido-file-name-all-completions-1 (dir)
(cond
((ido-nonreadable-directory-p dir) '())
;; Caller must have done that if necessary.
((and ido-enable-tramp-completion
- (or (fboundp 'tramp-completion-mode)
+ (or (fboundp 'tramp-completion-mode-p)
(require 'tramp nil t))
(string-match "\\`/[^/]+[:@]\\'" dir))
;; Strip method:user@host: part of tramp completions.
;; Tramp completions do not include leading slash.
- (let ((len (1- (length dir)))
- (compl
- (or (file-name-all-completions "" dir)
- ;; work around bug in ange-ftp.
- ;; /ftp:user@host: => nil
- ;; /ftp:user@host:./ => ok
- (and
- (not (string= "/ftp:" dir))
- (tramp-tramp-file-p dir)
- (fboundp 'tramp-ftp-file-name-p)
- (funcall 'tramp-ftp-file-name-p dir)
- (string-match ":\\'" dir)
- (file-name-all-completions "" (concat dir "./"))))))
+ (let* ((len (1- (length dir)))
+ (tramp-completion-mode t)
+ (compl
+ (or (file-name-all-completions "" dir)
+ ;; work around bug in ange-ftp.
+ ;; /ftp:user@host: => nil
+ ;; /ftp:user@host:./ => ok
+ (and
+ (not (string= "/ftp:" dir))
+ (tramp-tramp-file-p dir)
+ (fboundp 'tramp-ftp-file-name-p)
+ (funcall 'tramp-ftp-file-name-p dir)
+ (string-match ":\\'" dir)
+ (file-name-all-completions "" (concat dir "./"))))))
(if (and compl
(> (length (car compl)) len)
(string= (substring (car compl) 0 len) (substring dir 1)))
full-matches suffix-matches prefix-matches matches)
(setq ido-incomplete-regexp nil)
(condition-case error
- (mapcar
+ (mapc
(lambda (item)
(let ((name (ido-name item)))
(if (and (or non-prefix-dot
(setq re (mapconcat #'regexp-quote (split-string ido-text "") ".*"))
(if ido-enable-prefix
(setq re (concat "\\`" re)))
- (mapcar
+ (mapc
(lambda (item)
(let ((name (ido-name item)))
(if (string-match re name)
;;; 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))
+ (delete-region (point) (line-end-position))
+ (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))
+ (delete-region (point) (line-end-position))
+ (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-in-dir (dir)
"Switch to another file starting from DIR."
(interactive "DDir: ")
- (if (not (equal (substring dir -1) "/"))
- (setq dir (concat dir "/")))
+ (setq dir (file-name-as-directory dir))
(ido-file-internal ido-default-file-method nil dir nil nil nil 'ignore))
;;;###autoload
(defun ido-find-file-other-window ()
"Switch to another file and show it in another window.
The file name is selected interactively by typing a substring.
-For details of keybindings, do `\\[describe-function] ido-find-file'."
+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
(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)