X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/616e8e5f5e21ba5024a38621f42f8d3467a24785..09fd8197ffbbd7e7fe6339f86a3477531d20ab27:/lisp/ido.el diff --git a/lisp/ido.el b/lisp/ido.el index 012be3da37..1c2617b814 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, 2005 Free Software Foundation, Inc. +;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +;; 2004, 2005, 2006 Free Software Foundation, Inc. ;; Author: Kim F. Storm ;; Based on: iswitchb by Stephen Eglen @@ -20,47 +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. - -;;; Acknowledgements - -;; Infinite amounts of gratitude goes to Stephen Eglen -;; who wrote iswitch-buffer mode - from which I ripped off 99% of the code -;; for ido-switch-buffer and found the inspiration for ido-find-file. -;; The ido package would never have existed without his work. - -;; Also thanks to Klaus Berndl, Rohit Namjoshi, Robert Fenk, Alex -;; Schroeder, Bill Benedetto, Stephen Eglen, and many others for bug -;; fixes and improvements. - -;;; History - -;; Since I discovered Stephen Eglen's excellent iswitchb package, I just -;; couldn't live without it, but once being addicted to switching buffers -;; with a minimum of keystrokes, I soon found that opening files in the -;; old-fashioned way was just too slow - so I decided to write a package -;; which could open files with the same speed and ease as iswitchb could -;; switch buffers. - -;; I originally wrote a separate ifindf.el package based on a copy of -;; iswitchb.el, which did for opening files what iswitchb did for -;; switching buffers. Along the way, I corrected a few errors in -;; ifindf which could have found its way back into iswitchb, but since -;; most of the functionality of the two package was practically -;; identical, I decided that the proper thing to do was to merge my -;; ifindf package back into iswitchb. -;; -;; This is basically what ido (interactively do) is all about; but I -;; found it ackward to merge my changes into the "iswitchb-" namespace, -;; so I invented a common "ido-" namespace for the merged packages. -;; -;; This version is based on ido.el version 1.57 released on -;; gnu.emacs.sources adapted for emacs 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 -;; an idea of Yuji Minejima and his mcomplete-package. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -93,23 +55,23 @@ ;; most recent, when I use ido-switch-buffer, I first of all get ;; presented with the list of all the buffers ;; -;; Buffer: {123456,123} +;; Buffer: {123456 | 123} ;; ;; If I then press 2: -;; Buffer: 2[3]{123456,123} +;; Buffer: 2[3]{123456 | 123} ;; ;; The list in {...} are the matching buffers, most recent first ;; (buffers visible in the current frame are put at the end of the ;; list by default). At any time I can select the item at the head of -;; the list by pressing RET. I can also bring the put the first -;; element at the end of the list by pressing C-s or [right], or put -;; the last element at the head of the list by pressing C-r or [left]. +;; the 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. ;; So, I press TAB: -;; Buffer: 23{123456,123} +;; Buffer: 23{123456 | 123} ;; ;; At this point, I still have two matching buffers. ;; If I want the first buffer in the list, I simply press RET. If I @@ -117,13 +79,16 @@ ;; top of the list and then RET to select it. ;; ;; However, if I type 4, I only have one match left: -;; Buffer: 234[123456] [Matched] +;; Buffer: 234[123456] +;; +;; Since there is only one matching buffer left, it is given in [] and +;; it is shown in the `ido-only-match' face (ForestGreen). I can now +;; press TAB or RET to go to that buffer. ;; -;; Since there is only one matching buffer left, it is given in [] and we -;; see the text [Matched] afterwards. I can now press TAB or RET to go -;; to that buffer. +;; If I want to create a new buffer named "234", I press C-j instead of +;; TAB or RET. ;; -;; If however, I now type "a": +;; If instead, I type "a": ;; Buffer: 234a [No match] ;; There are no matching buffers. If I press RET or TAB, I can be ;; prompted to create a new buffer called "234a". @@ -210,8 +175,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 +200,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 @@ -256,7 +216,7 @@ ;; ;;(defun ido-my-keys () ;; "Add my keybindings for ido." -;; (define-key ido-mode-map " " 'ido-next-match) +;; (define-key ido-completion-map " " 'ido-next-match) ;; ) ;; Seeing all the matching buffers or files @@ -322,11 +282,52 @@ ;; can be used by other packages to read a buffer name, a file name, ;; or a directory name in the `ido' way. +;;; Acknowledgements + +;; Infinite amounts of gratitude goes to Stephen Eglen +;; who wrote iswitch-buffer mode - from which I ripped off 99% of the code +;; for ido-switch-buffer and found the inspiration for ido-find-file. +;; The ido package would never have existed without his work. + +;; Also thanks to Klaus Berndl, Rohit Namjoshi, Robert Fenk, Alex +;; Schroeder, Bill Benedetto, Stephen Eglen, and many others for bug +;; fixes and improvements. + +;;; History + +;; Since I discovered Stephen Eglen's excellent iswitchb package, I just +;; couldn't live without it, but once being addicted to switching buffers +;; with a minimum of keystrokes, I soon found that opening files in the +;; old-fashioned way was just too slow - so I decided to write a package +;; which could open files with the same speed and ease as iswitchb could +;; switch buffers. + +;; I originally wrote a separate ifindf.el package based on a copy of +;; iswitchb.el, which did for opening files what iswitchb did for +;; switching buffers. Along the way, I corrected a few errors in +;; ifindf which could have found its way back into iswitchb, but since +;; most of the functionality of the two package was practically +;; identical, I decided that the proper thing to do was to merge my +;; ifindf package back into iswitchb. +;; +;; This is basically what ido (interactively do) is all about; but I +;; found it ackward to merge my changes into the "iswitchb-" namespace, +;; so I invented a common "ido-" namespace for the merged packages. +;; +;; This version is based on ido.el version 1.57 released on +;; gnu.emacs.sources adapted for emacs 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 +;; an idea of Yuji Minejima and his mcomplete-package. + ;;; Code: (provide 'ido) +(defvar cua-inhibit-cua-keys) + ;;; User Variables ;; ;; These are some things you might want to change. @@ -356,10 +357,13 @@ Setting this variable directly does not take effect; use either \\[customize] or the function `ido-mode'." :set #'(lambda (symbol value) (ido-mode value)) - :initialize 'custom-initialize-default + :initialize 'custom-initialize-set :require 'ido :link '(emacs-commentary-link "ido.el") - :set-after '(ido-save-directory-list-file) + :set-after '(ido-save-directory-list-file + ;; This will clear ido-unc-hosts-cache, so set it + ;; before loading history file. + ido-unc-hosts) :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 +375,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) @@ -578,8 +582,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) @@ -608,6 +616,7 @@ A tramp file name uses the following syntax: /method:user@host:filename." (defcustom ido-cache-ftp-work-directory-time 1.0 "*Maximum time to cache contents of an ftp directory (in hours). +Use C-l in prompt to refresh list. If zero, ftp directories are not cached." :type 'number :group 'ido) @@ -624,10 +633,44 @@ equivalent function, e.g. `find-file' rather than `ido-find-file'." :type '(repeat regexp) :group 'ido) +(defvar ido-unc-hosts-cache t + "Cached value from `ido-unc-hosts' function.") + +(defcustom ido-unc-hosts nil + "*List of known UNC host names to complete after initial //. +If value is a function, that function is called to search network for +hosts on first use of UNC path." + :type '(choice (repeat :tag "List of UNC host names" string) + (function-item :tag "Use `NET VIEW'" + :value ido-unc-hosts-net-view) + (function :tag "Your own function")) + :set #'(lambda (symbol value) + (set symbol value) + (setq ido-unc-hosts-cache t)) + :group 'ido) + +(defcustom ido-downcase-unc-hosts t + "*Non-nil if UNC host names should be downcased." + :type 'boolean + :group 'ido) + +(defcustom ido-ignore-unc-host-regexps nil + "*List of regexps matching UNC hosts to ignore. +Case is ignored if `ido-downcase-unc-hosts' is set." + :type '(repeat regexp) + :group 'ido) + +(defcustom ido-cache-unc-host-shares-time 8.0 + "*Maximum time to cache shares of an UNC host (in hours). +Use C-l in prompt to refresh list. +If zero, UNC host shares are not cached." + :type 'number + :group 'ido) + (defcustom ido-max-work-file-list 10 "*Maximum number of names of recently opened files to record. This is the list the file names (sans directory) which have most recently -been opened. See `ido-work-file-list' and `ido-save-directory-list-file'." +been opened. See `ido-work-file-list' and `ido-save-directory-list-file'." :type 'integer :group 'ido) @@ -688,12 +731,17 @@ not provide the normal completion. To show the completions, use C-a." :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 @@ -709,7 +757,7 @@ ask user whether to create buffer, or 'never to never create new buffer." "*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'." +Additional keys can be defined in `ido-completion-map'." :type 'hook :group 'ido) @@ -770,6 +818,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 @@ -862,7 +916,7 @@ Must be set before enabling ido mode." :group 'ido) (defcustom ido-read-file-name-as-directory-commands '() - "List of commands which uses read-file-name to read a directory name. + "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'." :type '(repeat symbol) @@ -875,12 +929,30 @@ 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-mode-map nil - "Keymap for `ido-find-file' and `ido-switch-buffer'.") +(defvar ido-completion-map nil + "Currently active keymap for ido commands.") + +(defvar ido-common-completion-map nil + "Keymap for all ido commands.") + +(defvar ido-file-completion-map nil + "Keymap for ido file commands.") + +(defvar ido-file-dir-completion-map nil + "Keymap for ido file and directory commands.") + +(defvar ido-buffer-completion-map nil + "Keymap for ido buffer commands.") (defvar ido-file-history nil "History of files selected using `ido-find-file'.") @@ -941,7 +1013,7 @@ Copied from `icomplete-eoinput'.") "List of files currently matching `ido-text'.") (defvar ido-report-no-match t - "Report [No Match] when no completions matches ido-text.") + "Report [No Match] when no completions matches `ido-text'.") (defvar ido-exit nil "Flag to monitor how `ido-find-file' exits. @@ -959,6 +1031,8 @@ 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. @@ -1062,10 +1136,67 @@ it doesn't interfere with other minibuffer usage.") (pop-to-buffer b t t) (setq truncate-lines t))))) +(defun ido-unc-hosts (&optional query) + "Return list of UNC host names." + (let ((hosts + (cond + ((listp ido-unc-hosts) + ido-unc-hosts) ;; static list or nil + ((listp ido-unc-hosts-cache) + ido-unc-hosts-cache) ;; result of net search + ((and query (fboundp ido-unc-hosts)) + (message (propertize "Searching for UNC hosts..." 'face 'highlight)) + (setq ido-unc-hosts-cache (funcall ido-unc-hosts)) + (message nil) + ido-unc-hosts-cache) + (query + (setq ido-unc-hosts-cache nil)) + (t (fboundp ido-unc-hosts))))) + (when query + (let ((case-fold-search ido-downcase-unc-hosts) + res host re-list re) + (while hosts + (setq host (car hosts) + hosts (cdr hosts) + re-list (and ido-process-ignore-lists + ido-ignore-unc-host-regexps)) + (while re-list + (setq re (car re-list) + re-list (cdr re-list)) + (if (string-match re host) + (setq re-list nil + host nil))) + (when host + (when ido-downcase-unc-hosts + (setq host (downcase host))) + (setq res (cons host res)))) + (setq hosts (sort res #'string<)))) + hosts)) + +(defun ido-unc-hosts-net-view () + "Query network for list of UNC host names using `NET VIEW'." + (let (hosts) + (with-temp-buffer + (shell-command "net view" t) + (goto-char (point-min)) + (while (re-search-forward "^\\\\\\\\\\([[:graph:]]+\\)" nil t) + (setq hosts (cons (match-string 1) hosts)))) + hosts)) + (defun ido-is-tramp-root (&optional dir) - (setq dir (or dir ido-current-directory)) (and ido-enable-tramp-completion - (string-match "\\`/[^/][^/]+:\\([^/:@]+@\\)?\\'" dir))) + (string-match "\\`/[^/]+[@:]\\'" + (or dir ido-current-directory)))) + +(defun ido-is-unc-root (&optional dir) + (and (ido-unc-hosts) + (string-equal "//" + (or dir ido-current-directory)))) + +(defun ido-is-unc-host (&optional dir) + (and (ido-unc-hosts) + (string-match "\\`//[^/]+/\\'" + (or dir ido-current-directory)))) (defun ido-is-root-directory (&optional dir) (setq dir (or dir ido-current-directory)) @@ -1112,6 +1243,12 @@ it doesn't interfere with other minibuffer usage.") (or (not time) (< (- (ido-time-stamp) time) ido-cache-ftp-work-directory-time)))) +(defun ido-cache-unc-valid (&optional time) + (and (numberp ido-cache-unc-host-shares-time) + (> ido-cache-unc-host-shares-time 0) + (or (not time) + (< (- (ido-time-stamp) time) ido-cache-unc-host-shares-time)))) + (defun ido-may-cache-directory (&optional dir) (setq dir (or dir ido-current-directory)) (cond @@ -1121,10 +1258,11 @@ it doesn't interfere with other minibuffer usage.") (or ido-enable-tramp-completion (memq system-type '(windows-nt ms-dos)))) nil) - ((not (ido-is-ftp-directory dir)) - t) - ((ido-cache-ftp-valid) - t))) + ((ido-is-unc-host dir) + (ido-cache-unc-valid)) + ((ido-is-ftp-directory dir) + (ido-cache-ftp-valid)) + (t t))) (defun ido-pp (list &optional sep) (let ((print-level nil) (eval-expression-print-level nil) @@ -1145,25 +1283,22 @@ it doesn't interfere with other minibuffer usage.") (defun ido-save-history () "Save ido history and cache information between sessions." (interactive) - (if (and ido-last-directory-list ido-save-directory-list-file) - (save-excursion - (save-window-excursion - (if (find-buffer-visiting ido-save-directory-list-file) - (kill-buffer (find-buffer-visiting ido-save-directory-list-file))) - (if (file-exists-p ido-save-directory-list-file) - (delete-file ido-save-directory-list-file)) - (set-buffer (let ((enable-local-variables nil)) - (find-file-noselect ido-save-directory-list-file t))) - (goto-char (point-min)) - (delete-region (point-min) (point-max)) - (ido-pp 'ido-last-directory-list) - (ido-pp 'ido-work-directory-list) - (ido-pp 'ido-work-file-list) - (ido-pp 'ido-dir-file-cache "\n\n ") - (insert "\n") - (let ((version-control 'never)) + (when (and ido-last-directory-list ido-save-directory-list-file) + (let ((buf (get-buffer-create " *ido session*")) + (version-control 'never)) + (unwind-protect + (with-current-buffer buf + (erase-buffer) + (ido-pp 'ido-last-directory-list) + (ido-pp 'ido-work-directory-list) + (ido-pp 'ido-work-file-list) + (ido-pp 'ido-dir-file-cache "\n\n ") + (if (listp ido-unc-hosts-cache) + (ido-pp 'ido-unc-hosts-cache) + (insert "\n;; ----- ido-unc-hosts-cache -----\nt\n")) + (insert "\n") (write-file ido-save-directory-list-file nil)) - (kill-buffer (current-buffer)))))) + (kill-buffer buf))))) (defun ido-load-history (&optional arg) "Load ido history and cache information from previous session. @@ -1173,18 +1308,19 @@ With prefix argument, reload history unconditionally." (let ((file (expand-file-name ido-save-directory-list-file)) buf) (when (file-readable-p file) - (save-excursion - (save-window-excursion - (setq buf (set-buffer (let ((enable-local-variables nil)) - (find-file-noselect file)))) - (goto-char (point-min)) - (condition-case nil - (setq ido-last-directory-list (read (current-buffer)) - ido-work-directory-list (read (current-buffer)) - ido-work-file-list (read (current-buffer)) - ido-dir-file-cache (read (current-buffer))) - (error nil)))) - (kill-buffer buf)))) + (setq buf (get-buffer-create " *ido session*")) + (unwind-protect + (with-current-buffer buf + (erase-buffer) + (insert-file-contents file) + (condition-case nil + (setq ido-last-directory-list (read (current-buffer)) + ido-work-directory-list (read (current-buffer)) + ido-work-file-list (read (current-buffer)) + ido-dir-file-cache (read (current-buffer)) + ido-unc-hosts-cache (read (current-buffer))) + (error nil))) + (kill-buffer buf))))) (ido-wash-history)) (defun ido-wash-history () @@ -1232,15 +1368,21 @@ Removes badly formatted data and ignored directories." (and (stringp dir) (consp time) - (if (integerp (car time)) - (and (/= (car time) 0) - (integerp (car (cdr time))) - (/= (car (cdr time)) 0) - (ido-may-cache-directory dir)) - (and (eq (car time) 'ftp) - (numberp (cdr time)) + (cond + ((integerp (car time)) + (and (/= (car time) 0) + (integerp (car (cdr time))) + (/= (car (cdr time)) 0) + (ido-may-cache-directory dir))) + ((eq (car time) 'ftp) + (and (numberp (cdr time)) (ido-is-ftp-directory dir) (ido-cache-ftp-valid (cdr time)))) + ((eq (car time) 'unc) + (and (numberp (cdr time)) + (ido-is-unc-host dir) + (ido-cache-unc-valid (cdr time)))) + (t nil)) (let ((s files) (ok t)) (while s (if (stringp (car s)) @@ -1280,8 +1422,7 @@ Removes badly formatted data and ignored directories." (while e (setq d (car e) e (cdr e)) (if (not (consp d)) - (set-text-properties 0 (length d) nil d)))))) -) + (set-text-properties 0 (length d) nil d))))))) (defun ido-kill-emacs-hook () @@ -1312,6 +1453,8 @@ This function also adds a hook to the minibuffer." (t nil))) (ido-everywhere (if ido-everywhere 1 -1)) + (when ido-mode + (ido-init-completion-maps)) (when ido-mode (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup) @@ -1320,11 +1463,7 @@ This function also adds a hook to the minibuffer." (add-hook 'kill-emacs-hook 'ido-kill-emacs-hook) - (unless ido-minor-mode-map-entry - (setq ido-minor-mode-map-entry (cons 'ido-mode (make-sparse-keymap))) - (add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry)) - - (let ((map (cdr ido-minor-mode-map-entry))) + (let ((map (make-sparse-keymap))) (when (memq ido-mode '(file both)) (define-key map [remap find-file] 'ido-find-file) (define-key map [remap find-file-read-only] 'ido-find-file-read-only) @@ -1344,10 +1483,17 @@ This function also adds a hook to the minibuffer." (define-key map [remap switch-to-buffer-other-frame] 'ido-switch-buffer-other-frame) (define-key map [remap insert-buffer] 'ido-insert-buffer) (define-key map [remap kill-buffer] 'ido-kill-buffer) - (define-key map [remap display-buffer] 'ido-display-buffer))))) + (define-key map [remap display-buffer] 'ido-display-buffer)) + + (if ido-minor-mode-map-entry + (setcdr ido-minor-mode-map-entry map) + (setq ido-minor-mode-map-entry (cons 'ido-mode map)) + (add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry))))) + (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) @@ -1368,12 +1514,11 @@ This function also adds a hook to the minibuffer." ;;; IDO KEYMAP -(defun ido-define-mode-map () - "Set up the keymap for `ido'." - (let (map) - ;; generated every time so that it can inherit new functions. +(defun ido-init-completion-maps () + "Set up the completion keymaps used by `ido'." - (setq map (copy-keymap minibuffer-local-map)) + ;; Common map + (let ((map (make-sparse-keymap))) (define-key map "\C-a" 'ido-toggle-ignore) (define-key map "\C-c" 'ido-toggle-case) (define-key map "\C-e" 'ido-edit-input) @@ -1386,64 +1531,97 @@ 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) + (set-keymap-parent map minibuffer-local-map) + (setq ido-common-completion-map map)) + + ;; File and directory map + (let ((map (make-sparse-keymap))) + (define-key map "\C-x\C-b" 'ido-enter-switch-buffer) + (define-key map "\C-x\C-f" 'ido-fallback-command) + (define-key map "\C-x\C-d" '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 down)] 'ido-next-work-directory) + (define-key map [backspace] 'ido-delete-backward-updir) + (define-key map "\d" 'ido-delete-backward-updir) + (define-key map [(meta backspace)] 'ido-delete-backward-word-updir) + (define-key map [(control backspace)] 'ido-up-directory) + (define-key map "\C-l" 'ido-reread-directory) + (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) + (set-keymap-parent map ido-common-completion-map) + (setq ido-file-dir-completion-map map)) + + ;; File only map + (let ((map (make-sparse-keymap))) + (define-key map "\C-k" 'ido-delete-file-at-head) + (define-key map "\C-o" 'ido-copy-current-word) + (define-key map "\C-w" 'ido-copy-current-file-name) + (define-key map [(meta ?l)] 'ido-toggle-literal) + (define-key map "\C-v" 'ido-toggle-vc) + (set-keymap-parent map ido-file-dir-completion-map) + (setq ido-file-completion-map map)) + + ;; Buffer map + (let ((map (make-sparse-keymap))) + (define-key map "\C-x\C-f" 'ido-enter-find-file) + (define-key map "\C-x\C-b" 'ido-fallback-command) + (define-key map "\C-k" 'ido-kill-buffer-at-head) + (set-keymap-parent map ido-common-completion-map) + (setq ido-buffer-completion-map map))) + + +(defun ido-setup-completion-map () + "Set up the keymap for `ido'." - (when (memq ido-cur-item '(file dir)) - (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 down)] 'ido-next-work-directory) - (define-key map [backspace] 'ido-delete-backward-updir) - (define-key map "\d" 'ido-delete-backward-updir) - (define-key map [(meta backspace)] 'ido-delete-backward-word-updir) - (define-key map [(control backspace)] 'ido-up-directory) - (define-key map "\C-l" 'ido-reread-directory) - (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 ?p)] 'ido-prev-work-directory) - (define-key map [(meta ?s)] 'ido-merge-work-directories) - ) - - (when (eq ido-cur-item 'file) - (define-key map "\C-k" 'ido-delete-file-at-head) - (define-key map "\C-o" 'ido-copy-current-word) - (define-key map "\C-w" 'ido-copy-current-file-name) - (define-key map [(meta ?l)] 'ido-toggle-literal) - (define-key map "\C-v" 'ido-toggle-vc) - ) + ;; generated every time so that it can inherit new functions. + (let ((map (make-sparse-keymap)) + (viper-p (if (boundp 'viper-mode) viper-mode))) - (when (eq ido-cur-item 'buffer) - (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) - ) + (when viper-p + (define-key map [remap viper-intercept-ESC-key] 'ignore)) - (when (if (boundp 'viper-mode) viper-mode) - (define-key map [remap viper-intercept-ESC-key] 'ignore) - (when (memq ido-cur-item '(file dir)) + (cond + ((memq ido-cur-item '(file dir)) + (when ido-context-switch-command + (define-key map "\C-x\C-b" ido-context-switch-command) + (define-key map "\C-x\C-d" 'ignore)) + (when viper-p (define-key map [remap viper-backward-char] 'ido-delete-backward-updir) (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))) + (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir)) + (set-keymap-parent map + (if (eq ido-cur-item 'file) + ido-file-completion-map + ido-file-dir-completion-map))) - (setq ido-mode-map map))) + ((eq ido-cur-item 'buffer) + (when ido-context-switch-command + (define-key map "\C-x\C-f" ido-context-switch-command)) + (set-keymap-parent map ido-buffer-completion-map)) + + (t + (set-keymap-parent map ido-common-completion-map))) + + (setq ido-completion-map map))) (defun ido-final-slash (dir &optional fix-it) ;; return DIR if DIR has final slash. @@ -1469,6 +1647,7 @@ This function also adds a hook to the minibuffer." ;; connect on incomplete tramp paths (after entring just method:). (let ((ido-enable-tramp-completion nil)) (and (ido-final-slash dir) + (not (ido-is-unc-host dir)) (file-directory-p dir) (not (file-readable-p dir))))) @@ -1479,18 +1658,34 @@ This function also adds a hook to the minibuffer." (let ((ido-enable-tramp-completion nil)) (and (numberp ido-max-directory-size) (ido-final-slash dir) + (not (ido-is-unc-host 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)) + (unless (and ido-enable-tramp-completion + (string-match "\\`/[^/]*@\\'" dir)) + (setq dir (ido-final-slash dir t))) (setq ido-use-merged-list nil ido-try-merged-list (not no-merge)) - (if subdir - (setq dir (ido-final-slash (concat dir subdir) t))) - (if (equal dir ido-current-directory) - nil + (when subdir + (setq dir (concat dir subdir)) + (unless (and ido-enable-tramp-completion + (string-match "\\`/[^/]*@\\'" dir)) + (setq dir (ido-final-slash dir t)))) + (if (get-buffer ido-completion-buffer) + (kill-buffer ido-completion-buffer)) + (cond + ((equal dir ido-current-directory) + nil) + ((ido-is-unc-root dir) + (ido-trace "unc" dir) + (setq ido-current-directory dir) + (setq ido-directory-nonreadable nil) + (setq ido-directory-too-big nil) + t) + (t (ido-trace "cd" dir) (setq ido-current-directory dir) (if (get-buffer ido-completion-buffer) @@ -1498,7 +1693,7 @@ This function also adds a hook to the minibuffer." (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)) + t))) (defun ido-set-current-home (&optional dir) ;; Set ido's current directory to user's home directory @@ -1580,10 +1775,10 @@ This function also adds a hook to the minibuffer." ;; the relevant function is called (find-file, write-file, etc). (defun ido-read-internal (item prompt history &optional default require-match initial) - "Perform the ido-read-buffer and ido-read-file-name functions. + "Perform the `ido-read-buffer' and `ido-read-file-name' functions. Return the name of a buffer or file selected. PROMPT is the prompt to give to the user. -DEFAULT if given is the default directory to start with. +DEFAULT if given is the default item to start with. If REQUIRE-MATCH is non-nil, an existing file must be selected. If INITIAL is non-nil, it specifies the initial input string." (let @@ -1610,7 +1805,7 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-enable-regexp ido-enable-regexp) ) - (ido-define-mode-map) + (ido-setup-completion-map) (setq ido-text-init initial) (setq ido-input-stack nil) @@ -1627,7 +1822,10 @@ If INITIAL is non-nil, it specifies the initial input string." (cond ((eq item 'buffer) (if (bufferp default) (buffer-name default) default)) - ((stringp default) default) + ((stringp default) + (if (memq item '(file dir)) + (file-name-nondirectory default) + default)) ((eq item 'file) (and ido-enable-last-directory-history (let ((d (assoc ido-current-directory ido-last-directory-list))) @@ -1715,7 +1913,8 @@ If INITIAL is non-nil, it specifies the initial input string." (if (and ido-matches (eq ido-try-merged-list 'auto)) (setq ido-try-merged-list t)) (let - ((minibuffer-local-completion-map ido-mode-map) + ((minibuffer-local-completion-map ido-completion-map) + (minibuffer-local-filename-completion-map ido-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) @@ -1868,6 +2067,7 @@ If INITIAL is non-nil, it specifies the initial input string." (setq ido-exit 'fallback done t) (setq ido-set-default-item t))) + ((or (string-match "[/\\][^/\\]" ido-selected) (and (memq system-type '(windows-nt ms-dos)) (string-match "\\`.:" ido-selected))) @@ -1901,7 +2101,7 @@ If INITIAL is non-nil, it specifies the initial input string." (defun ido-edit-input () "Edit absolute file name entered so far with ido; terminate by RET." (interactive) - (setq ido-text-init ido-text) + (setq ido-text-init (if ido-matches (car ido-matches) ido-text)) (setq ido-exit 'edit) (exit-minibuffer)) @@ -1909,7 +2109,10 @@ If INITIAL is non-nil, it specifies the initial input string." (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) @@ -1928,6 +2131,8 @@ If INITIAL is non-nil, it specifies the initial input string." ((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. @@ -1939,7 +2144,10 @@ 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)) + (push-mark + (save-excursion + (insert-buffer-substring (get-buffer buf)) + (point)))) (ido-visit-buffer buf method t))) ;; buffer doesn't exist @@ -2004,7 +2212,8 @@ If INITIAL is non-nil, it specifies the initial input string." (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)) @@ -2031,7 +2240,9 @@ If INITIAL is non-nil, it specifies the initial input string." 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)) @@ -2059,6 +2270,8 @@ 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 'switch-to-buffer) @@ -2103,7 +2316,7 @@ If INITIAL is non-nil, it specifies the initial input string." (ido-record-command method dirname) (ido-record-work-directory) (funcall method dirname)) - ((y-or-n-p (format "Directory %s does not exist. Create it " filename)) + ((y-or-n-p (format "Directory %s does not exist. Create it? " filename)) (ido-record-command method dirname) (ido-record-work-directory dirname) (make-directory-internal dirname) @@ -2125,6 +2338,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) @@ -2134,9 +2348,10 @@ If INITIAL is non-nil, it specifies the initial input string." (if ido-find-literal 'insert-file-literally 'insert-file) filename) (ido-record-work-directory) - (if ido-find-literal - (insert-file-contents-literally filename) - (insert-file-contents filename))) + (insert-file-1 filename + (if ido-find-literal + #'insert-file-contents-literally + #'insert-file-contents))) (filename (ido-record-work-file filename) @@ -2169,6 +2384,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)))) @@ -2384,7 +2602,9 @@ timestamp has not changed (e.g. with ftp or on Windows)." (interactive) (if (and ido-mode (eq ido-cur-item 'file)) (progn - (ido-remove-cached-dir ido-current-directory) + (if (ido-is-unc-root) + (setq ido-unc-hosts-cache t) + (ido-remove-cached-dir ido-current-directory)) (setq ido-text-init ido-text) (setq ido-rotate-temp t) (setq ido-exit 'refresh) @@ -2393,8 +2613,9 @@ 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)) + (if (and (or (not ido-require-match) + (ido-existing-item-p)) + (not ido-incomplete-regexp)) (exit-minibuffer))) (defun ido-select-text () @@ -2982,11 +3203,10 @@ for first matching file." (let (res) (message "Searching for `%s'...." text) (condition-case nil - (unless (catch 'input-pending-p - (let ((throw-on-input 'input-pending-p)) - (setq res (ido-make-merged-file-list-1 text auto wide)) - t)) - (setq res 'input-pending-p)) + (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 @@ -3063,27 +3283,29 @@ for first matching file." ((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)) - - ;; Trick tramp's file-name-all-completions handler to DTRT, as it - ;; has some pretty obscure requirements. This seems to work... - ;; /ftp: => (f-n-a-c "/ftp:" "") - ;; /ftp:kfs: => (f-n-a-c "" "/ftp:kfs:") - ;; /ftp:kfs@ => (f-n-a-c "ftp:kfs@" "/") - ;; /ftp:kfs@kfs: => (f-n-a-c "" "/ftp:kfs@kfs:") - ;; Currently no attempt is made to handle multi: stuff. - - (let* ((prefix (match-string 1 dir)) - (user-flag (match-beginning 2)) - (len (and prefix (length prefix))) - compl) - (if user-flag - (setq dir (substring dir 1))) - (require 'tramp nil t) - (ido-trace "tramp complete" dir) - (setq compl (file-name-all-completions dir (if user-flag "/" ""))) - (if (> len 0) + (or (fboundp 'tramp-completion-mode) + (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 "./")))))) + (if (and compl + (> (length (car compl)) len) + (string= (substring (car compl) 0 len) (substring dir 1))) (mapcar (lambda (c) (substring c len)) compl) compl))) (t @@ -3092,36 +3314,52 @@ for first matching file." (defun ido-file-name-all-completions (dir) ;; Return name of all files in DIR ;; Uses and updates ido-dir-file-cache - (if (and (numberp ido-max-dir-file-cache) (> ido-max-dir-file-cache 0) - (stringp dir) (> (length dir) 0) - (ido-may-cache-directory dir)) - (let* ((cached (assoc dir ido-dir-file-cache)) + (cond + ((ido-is-unc-root dir) + (mapcar + (lambda (host) + (if (string-match "/\\'" host) host (concat host "/"))) + (ido-unc-hosts t))) + ((and (numberp ido-max-dir-file-cache) (> ido-max-dir-file-cache 0) + (stringp dir) (> (length dir) 0) + (ido-may-cache-directory dir)) + (let* ((cached (assoc dir ido-dir-file-cache)) (ctime (nth 1 cached)) (ftp (ido-is-ftp-directory dir)) - (attr (if ftp nil (file-attributes dir))) + (unc (ido-is-unc-host dir)) + (attr (if (or ftp unc) nil (file-attributes dir))) (mtime (nth 5 attr)) valid) (when cached ; should we use the cached entry ? - (if ftp - (setq valid (and (eq (car ctime) 'ftp) - (ido-cache-ftp-valid (cdr ctime)))) + (cond + (ftp + (setq valid (and (eq (car ctime) 'ftp) + (ido-cache-ftp-valid (cdr ctime))))) + (unc + (setq valid (and (eq (car ctime) 'unc) + (ido-cache-unc-valid (cdr ctime))))) + (t (if attr (setq valid (and (= (car ctime) (car mtime)) - (= (car (cdr ctime)) (car (cdr mtime))))))) - (if (not valid) - (setq ido-dir-file-cache (delq cached ido-dir-file-cache) - cached nil))) + (= (car (cdr ctime)) (car (cdr mtime)))))))) + (unless valid + (setq ido-dir-file-cache (delq cached ido-dir-file-cache) + cached nil))) (unless cached - (if (and ftp (file-readable-p dir)) - (setq mtime (cons 'ftp (ido-time-stamp)))) + (cond + (unc + (setq mtime (cons 'unc (ido-time-stamp)))) + ((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-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-completions-1 dir))) + (cdr (cdr cached))))) + (t + (ido-file-name-all-completions-1 dir)))) (defun ido-remove-cached-dir (dir) ;; Remove dir from ido-dir-file-cache @@ -3135,7 +3373,8 @@ for first matching file." (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)) + (and (or (ido-is-tramp-root dir) (ido-is-unc-root dir) + (file-directory-p dir)) (delq nil (mapcar (lambda (name) @@ -3154,13 +3393,14 @@ for first matching file." (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 - (lambda (x) (if (or (string-match "..:\\'" x) - (and (not (ido-final-slash x)) - (get-file-buffer x))) x)) - ido-temp-list)))) + (unless (ido-is-tramp-root ido-current-directory) + (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) + (and (not (ido-final-slash x)) + (get-file-buffer x))) x)) + ido-temp-list))))) (ido-to-end ;; move . files to end (delq nil (mapcar (lambda (x) (if (string-equal (substring x 0 1) ".") x)) @@ -3274,22 +3514,30 @@ for first matching file." 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 @@ -3321,38 +3569,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) @@ -3483,7 +3730,7 @@ for first matching file." (file-exists-p file) (not (file-directory-p file)) (file-writable-p ido-current-directory) - (yes-or-no-p (concat "Delete " file " "))) + (yes-or-no-p (concat "Delete " file "? "))) (delete-file file) ;; Check if file still exists. (if (file-exists-p file) @@ -3568,10 +3815,10 @@ default is to show it in the same window, unless it is already visible in another frame. As you type in a string, all of the buffers matching the string are -displayed if substring-matching is used \(default). Look at +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: \\ +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. @@ -3591,7 +3838,7 @@ in a separate window. \\[ido-toggle-prefix] Toggle between substring and prefix matching. \\[ido-toggle-case] Toggle case-sensitive searching of buffer names. \\[ido-completion-help] Show list of matching buffers in separate window. -\\[ido-enter-find-file] Drop into ido-find-file. +\\[ido-enter-find-file] Drop into `ido-find-file'. \\[ido-kill-buffer-at-head] Kill buffer at head of buffer list. \\[ido-toggle-ignore] Toggle ignoring buffers listed in `ido-ignore-buffers'." (interactive) @@ -3659,7 +3906,7 @@ 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: \\ +except for the following: \\ RET Select the file at the front of the list of matches. If the list is empty, possibly prompt to create new file. @@ -3678,7 +3925,7 @@ in a separate window. \\[ido-merge-work-directories] search for file in the work directory history. \\[ido-forget-work-directory] removes current directory from the work directory history. \\[ido-prev-work-file] or \\[ido-next-work-file] cycle through the work file history. -\\[ido-wide-find-file] and \\[ido-wide-find-dir] prompts and uses find to locate files or directories. +\\[ido-wide-find-file-or-pop-dir] and \\[ido-wide-find-dir-or-delete-dir] prompts and uses find to locate files or directories. \\[ido-make-directory] prompts for a directory to create in current directory. \\[ido-fallback-command] Fallback to non-ido version of current command. \\[ido-toggle-regexp] Toggle regexp searching. @@ -3856,10 +4103,16 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." ) ((= (length contents) 1) - (when (and (ido-is-tramp-root) (string-equal contents "/")) + (cond + ((and (ido-is-tramp-root) (string-equal contents "/")) (ido-set-current-directory ido-current-directory contents) (setq refresh t)) - ) + ((and (ido-unc-hosts) (string-equal contents "/") + (let ((ido-enable-tramp-completion nil)) + (ido-is-root-directory))) + (ido-set-current-directory "//") + (setq refresh t)) + )) ((and (string-match (if ido-enable-tramp-completion "..[:@]\\'" "..:\\'") contents) (ido-is-root-directory)) ;; Ange-ftp or tramp @@ -3953,12 +4206,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))) @@ -4047,7 +4301,9 @@ 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 + (if ido-incomplete-regexp + 'ido-incomplete-regexp + 'ido-only-match) 'ido-first-match) first) (if ind (setq first (concat first ind))) @@ -4062,14 +4318,22 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (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)) @@ -4164,6 +4428,7 @@ For details of keybindings, do `\\[describe-function] ido-find-file'." (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) @@ -4179,6 +4444,7 @@ If REQUIRE-MATCH is non-nil, an existing buffer must be selected." (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))) @@ -4203,11 +4469,14 @@ See `read-file-name' for additional parameters." (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-show-dot-for-dired (and ido-show-dot-for-dired + (not default-filename))) (ido-work-file-index -1) (ido-find-literal nil)) (setq ido-exit nil) @@ -4225,6 +4494,7 @@ See `read-file-name' for additional parameters." (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))) @@ -4234,6 +4504,7 @@ See `read-file-name' for additional parameters." 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))