;;; ido.el --- interactively do things with buffers and files
-;; Copyright (C) 1996-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1996-2016 Free Software Foundation, Inc.
;; Author: Kim F. Storm <storm@cua.dk>
;; Based on: iswitchb by Stephen Eglen <stephen@cns.ed.ac.uk>
;;
;; Customize the Ido group to change the Ido functionality.
;;
-;; To modify the keybindings, use the ido-setup-hook. For example:
-;;(add-hook 'ido-setup-hook 'ido-my-keys)
+;; To modify the keybindings, use `define-key' on
+;; `ido-common-completion-map' or one of the specialized keymaps:
+;; `ido-file-dir-completion-map', `ido-file-completion-map' or
+;; `ido-buffer-completion-map'.
;;
-;;(defun ido-my-keys ()
-;; "Add my keybindings for ido."
-;; (define-key ido-completion-map " " 'ido-next-match)
-;; )
+;; (with-eval-after-load 'ido
+;; (define-key ido-common-completion-map " " 'ido-next-match))
;; Seeing all the matching buffers or files
;; ----------------------------------------
;;; Code:
(defvar recentf-list)
+(require 'seq)
+
+;;;; Options
-;;; User Variables
-;;
;; These are some things you might want to change.
(defun ido-fractionp (n)
'("\\` ")
"List of regexps or functions matching buffer names to ignore.
For example, traditional behavior is not to list buffers whose names begin
-with a space, for which the regexp is `\\` '. See the source file for
+with a space, for which the regexp is `\\\\=` '. See the source file for
example functions that filter buffer names."
:type '(repeat (choice regexp function))
:group 'ido)
'("\\`CVS/" "\\`#" "\\`.#" "\\`\\.\\./" "\\`\\./")
"List of regexps or functions matching file names to ignore.
For example, traditional behavior is not to list files whose names begin
-with a #, for which the regexp is `\\`#'. See the source file for
+with a #, for which the regexp is `\\\\=`#'. See the source file for
example functions that filter filenames."
:type '(repeat (choice regexp function))
:group 'ido)
(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
+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."
(defcustom ido-create-new-buffer 'prompt
"Specify whether a new buffer is created if no buffer matches substring.
-Choices are 'always to create new buffers unconditionally, 'prompt to
-ask user whether to create buffer, or 'never to never create new buffer."
+Choices are `always' to create new buffers unconditionally, `prompt' to
+ask user whether to create buffer, or `never' to never create new buffer."
:type '(choice (const always)
(const prompt)
(const never))
It is intended for use in customizing Ido for interoperation
with other packages. For instance:
- (add-hook 'ido-minibuffer-setup-hook
+ (add-hook \\='ido-minibuffer-setup-hook
(lambda () (setq-local max-mini-window-height 3)))
will constrain Emacs to a maximum minibuffer height of 3 lines when
:type 'hook
:group 'ido)
-;;; Internal Variables
-
-;; Persistent variables
-
-(defvar ido-completion-map nil
- "Currently active keymap for Ido commands.")
+;;;; Keymaps
-(defvar ido-common-completion-map nil
+(defvar ido-common-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map minibuffer-local-map)
+ (define-key map "\C-a" 'ido-toggle-ignore)
+ (define-key map "\C-c" 'ido-toggle-case)
+ (define-key map "\C-e" 'ido-edit-input)
+ (define-key map "\t" 'ido-complete)
+ (define-key map " " 'ido-complete-space)
+ (define-key map "\C-j" 'ido-select-text)
+ (define-key map "\C-m" 'ido-exit-minibuffer)
+ (define-key map "\C-p" 'ido-toggle-prefix)
+ (define-key map "\C-r" 'ido-prev-match)
+ (define-key map "\C-s" 'ido-next-match)
+ (define-key map [?\C-.] 'ido-next-match)
+ (define-key map [?\C-,] 'ido-prev-match)
+ (define-key map "\C-t" 'ido-toggle-regexp)
+ (define-key map "\C-z" 'ido-undo-merge-work-directory)
+ (define-key map [(control ?\s)] 'ido-restrict-to-matches)
+ (define-key map [(meta ?\s)] 'ido-take-first-match)
+ (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)
+ (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)
+ map)
"Keymap for all Ido commands.")
-(defvar ido-file-completion-map nil
- "Keymap for Ido file commands.")
-
-(defvar ido-file-dir-completion-map nil
+(defvar ido-file-dir-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map ido-common-completion-map)
+ (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 [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)
+ (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 ?v)] 'ido-push-dir-first)
+ (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)
+ map)
"Keymap for Ido file and directory commands.")
-(defvar ido-buffer-completion-map nil
+(defvar ido-file-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map ido-file-dir-completion-map)
+ (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)
+ map)
+ "Keymap for Ido file commands.")
+
+(defvar ido-buffer-completion-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map ido-common-completion-map)
+ (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)
+ (define-key map [?\C-\S-b] 'ido-bury-buffer-at-head)
+ (define-key map "\C-o" 'ido-toggle-virtual-buffers)
+ map)
"Keymap for Ido buffer commands.")
+;;;; Persistent variables
+
(defvar ido-file-history nil
"History of files selected using `ido-find-file'.")
Intended to be let-bound by functions which call Ido repeatedly.
Should never be set permanently.")
-;; Temporary storage
+;;;; Temporary storage
+
+(defvar ido-completion-map nil
+ "Currently active keymap for Ido commands.")
(defvar ido-eoinput 1
"Point where minibuffer input ends and completion info begins.
This is a copy of `recentf-list', pared down and with faces applied.
Only used if `ido-use-virtual-buffers' is non-nil.")
-;;; Variables with dynamic bindings.
-;;; Declared here to keep the byte compiler quiet.
+;;;; Variables with dynamic bindings.
+
+;; These are 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
+;; Stores the current default item.
(defvar ido-default-item)
;; Stores the current list of items that will be searched through.
(ido-save-history))
(defun ido-common-initialization ()
- (ido-init-completion-maps)
(add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
(add-hook 'choose-completion-string-functions 'ido-choose-completion-string))
(when ido-everywhere
(when (memq ido-mode '(both file))
(put 'ido-everywhere 'file (cons read-file-name-function nil))
- (setq read-file-name-function 'ido-read-file-name))
+ (setq read-file-name-function #'ido-read-file-name))
(when (memq ido-mode '(both buffer))
(put 'ido-everywhere 'buffer (cons read-buffer-function nil))
- (setq read-buffer-function 'ido-read-buffer))))
+ (setq read-buffer-function #'ido-read-buffer))))
(defvar ido-minor-mode-map-entry nil)
Turning on Ido mode will remap (via a minor-mode keymap) the default
keybindings for the `find-file' and `switch-to-buffer' families of
commands to the Ido versions of these functions.
-However, if ARG arg equals 'files, remap only commands for files, or
-if it equals 'buffers, remap only commands for buffer switching.
+However, if ARG arg equals `files', remap only commands for files, or
+if it equals `buffers', remap only commands for buffer switching.
This function also adds a hook to the minibuffer."
(interactive "P")
(setq ido-mode
;;; IDO KEYMAP
-(defun ido-init-completion-maps ()
- "Set up the completion keymaps used by Ido."
-
- ;; 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)
- (define-key map "\t" 'ido-complete)
- (define-key map " " 'ido-complete-space)
- (define-key map "\C-j" 'ido-select-text)
- (define-key map "\C-m" 'ido-exit-minibuffer)
- (define-key map "\C-p" 'ido-toggle-prefix)
- (define-key map "\C-r" 'ido-prev-match)
- (define-key map "\C-s" 'ido-next-match)
- (define-key map [?\C-.] 'ido-next-match)
- (define-key map [?\C-,] 'ido-prev-match)
- (define-key map "\C-t" 'ido-toggle-regexp)
- (define-key map "\C-z" 'ido-undo-merge-work-directory)
- (define-key map [(control ?\s)] 'ido-restrict-to-matches)
- (define-key map [(meta ?\s)] 'ido-take-first-match)
- (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 [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)
- (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 ?v)] 'ido-push-dir-first)
- (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)
- (set-keymap-parent map ido-file-dir-completion-map)
- (setq ido-file-completion-map map))
+(defalias 'ido-init-completion-maps 'ignore "")
+(make-obsolete 'ido-init-completion-maps "it does nothing." "25.1")
- ;; 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)
- (define-key map "\C-o" 'ido-toggle-virtual-buffers)
- (set-keymap-parent map ido-common-completion-map)
- (setq ido-buffer-completion-map map)))
+(defun ido-setup-completion-map ()
+ "Set up the completion keymap used by Ido.
+Create a keymap, bind `ido-completion-map' to it, and depending
+on what is being completed (`ido-cur-item') set its parent keymap
+to one of:
-(defun ido-setup-completion-map ()
- "Set up the keymap for Ido."
+ `ido-common-completion-map'
+ `ido-file-dir-completion-map'
+ `ido-file-completion-map'
+ `ido-buffer-completion-map'
+If option `ido-context-switch-command' is non-nil or `viper-mode'
+is enabled then some keybindings are changed in the keymap."
;; generated every time so that it can inherit new functions.
(let ((map (make-sparse-keymap))
(viper-p (if (boundp 'viper-mode) viper-mode)))
-
(when viper-p
(define-key map [remap viper-intercept-ESC-key] 'ignore))
-
- (cond
- ((memq ido-cur-item '(file dir))
+ (pcase ido-cur-item
+ ((or `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-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))
(set-keymap-parent map
(if (eq ido-cur-item 'file)
ido-file-completion-map
ido-file-dir-completion-map)))
-
- ((eq ido-cur-item 'buffer)
+ (`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)
((and (eq ido-create-new-buffer 'prompt)
(null require-match)
- (not (y-or-n-p (format "No buffer matching `%s', create one? " buf))))
+ (not (y-or-n-p (format-message
+ "No buffer matching `%s', create one? " buf))))
nil)
;; buffer doesn't exist
((and (eq ido-create-new-buffer 'prompt)
(null require-match)
- (not (y-or-n-p (format "No buffer matching `%s', create one? " buf))))
+ (not (y-or-n-p (format-message
+ "No buffer matching `%s', create one? " buf))))
nil)
;; create a new buffer
(if (> i 0)
(setq ido-cur-list (ido-chop ido-cur-list (nth i ido-matches)))))))
-(defun ido-restrict-to-matches ()
- "Set current item list to the currently matched items."
- (interactive)
+(defun ido-restrict-to-matches (&optional removep)
+ "Set current item list to the currently matched items.
+
+When argument REMOVEP is non-nil, the currently matched items are
+instead removed from the current item list."
+ (interactive "P")
(when ido-matches
- (setq ido-cur-list ido-matches
+ (setq ido-cur-list (if removep
+ ;; An important feature is to preserve the
+ ;; order of the elements.
+ (seq-difference ido-cur-list ido-matches)
+ ido-matches)
+ ido-matches ido-cur-list
ido-text-init ""
ido-rescan nil
ido-exit 'keep)
(unless recentf-mode (recentf-mode 1))
(setq ido-virtual-buffers nil)
(let (name)
- (dolist (head recentf-list)
+ (dolist (head (append
+ recentf-list
+ (and (fboundp 'bookmark-get-filename)
+ (delq nil (mapcar #'bookmark-get-filename
+ (bound-and-true-p bookmark-alist))))))
(setq name (file-name-nondirectory head))
;; In case HEAD is a directory with trailing /. See bug#14552.
(when (equal name "")
(let* ((len (1- (length dir)))
(non-essential t)
(compl
- (or (file-name-all-completions "" dir)
+ (or ;; We do not want to be disturbed by "File does not
+ ;; exist" errors.
+ (ignore-errors (file-name-all-completions "" dir))
;; work around bug in ange-ftp.
;; /ftp:user@host: => nil
;; /ftp:user@host:./ => ok
(not (and (eq ido-cur-item 'buffer)
ido-buffer-disable-smart-matches))
(not ido-enable-regexp)
- (not (string-match "\$\\'" rex0))
+ (not (string-match "$\\'" rex0))
(concat "\\`" rex0 (if slash "/" "") "\\'")))
(suffix-re (and do-full slash
(not (and (eq ido-cur-item 'buffer)
ido-buffer-disable-smart-matches))
(not ido-enable-regexp)
- (not (string-match "\$\\'" rex0))
+ (not (string-match "$\\'" rex0))
(concat rex0 "/\\'")))
(prefix-re (and full-re (not ido-enable-prefix)
(concat "\\`" rexq)))
(setq ido-cur-list (delete buf ido-cur-list))
(setq ido-rescan t))))))
+;;; BURY CURRENT BUFFER
+(defun ido-bury-buffer-at-head ()
+ "Bury the buffer at the head of `ido-matches'."
+ (interactive)
+ (let ((enable-recursive-minibuffers t)
+ (buf (ido-name (car ido-matches)))
+ (nextbuf (cadr ido-matches)))
+ (when (get-buffer buf)
+ (bury-buffer buf)
+ (setq ido-default-item nextbuf
+ ido-text-init ido-text
+ ido-exit 'refresh)
+ (exit-minibuffer))))
+
;;; DELETE CURRENT FILE
(defun ido-delete-file-at-head ()
"Delete the file at the head of `ido-matches'.
(put 'dired-do-rename 'ido 'ignore)
;;;###autoload
-(defun ido-read-buffer (prompt &optional default require-match)
+(defun ido-read-buffer (prompt &optional default require-match predicate)
"Ido replacement for the built-in `read-buffer'.
Return the name of a buffer selected.
PROMPT is the prompt to give to the user. DEFAULT if given is the default
(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))
+ (read-buffer prompt default require-match predicate))
buf)))
;;;###autoload