X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/732fd4c7e11debd61c97eaaba3038d61e6ec7024..455700d69a1a6861dc8c9b2ba19733429727d3c3:/lisp/ido.el diff --git a/lisp/ido.el b/lisp/ido.el index 782979ad44..0e74cbc7a2 100644 --- a/lisp/ido.el +++ b/lisp/ido.el @@ -1,6 +1,6 @@ ;;; ido.el --- interactively do things with buffers and files -;; Copyright (C) 1996-2015 Free Software Foundation, Inc. +;; Copyright (C) 1996-2016 Free Software Foundation, Inc. ;; Author: Kim F. Storm ;; Based on: iswitchb by Stephen Eglen @@ -208,13 +208,13 @@ ;; ;; 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 ;; ---------------------------------------- @@ -322,9 +322,10 @@ ;;; Code: (defvar recentf-list) +(require 'seq) + +;;;; Options -;;; User Variables -;; ;; These are some things you might want to change. (defun ido-fractionp (n) @@ -377,7 +378,7 @@ use either \\[customize] or the function `ido-mode'." '("\\` ") "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) @@ -386,7 +387,7 @@ example functions that filter buffer names." '("\\`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) @@ -741,8 +742,8 @@ not provide the normal completion. To show the completions, use \\[ido-toggle-i (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." @@ -754,8 +755,8 @@ 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)) @@ -940,7 +941,7 @@ 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: - (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 @@ -978,25 +979,90 @@ The fallback command is passed as an argument to the functions." :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'.") @@ -1027,7 +1093,10 @@ Each element in the list is of the form (DIR (MTIME) 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. @@ -1086,13 +1155,14 @@ Value is an integer which is number of chars to right of prompt.") 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. @@ -1306,8 +1376,7 @@ Only used if `ido-use-virtual-buffers' is non-nil.") (defun ido-time-stamp (&optional time) ;; Time is a floating point number (fractions of 1 hour) - (setq time (or time (current-time))) - (/ (+ (* (car time) 65536.0) (car (cdr time))) 3600.0)) + (/ (float-time time) 3600)) (defun ido-cache-ftp-valid (&optional time) (and (numberp ido-cache-ftp-work-directory-time) @@ -1503,7 +1572,6 @@ Removes badly formatted data and ignored directories." (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)) @@ -1523,10 +1591,10 @@ enable the mode if ARG is omitted or nil." (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) @@ -1537,8 +1605,8 @@ With ARG, turn Ido mode on if arg is positive, off otherwise. 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 @@ -1597,119 +1665,51 @@ This function also adds a hook to the minibuffer." ;;; 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) @@ -2275,7 +2275,8 @@ If cursor is not at the end of the user input, move to end of input." ((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 @@ -2285,7 +2286,8 @@ If cursor is not at the end of the user input, move to end of input." ((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 @@ -3181,11 +3183,19 @@ for first matching file." (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) @@ -3482,7 +3492,11 @@ This is to make them appear as if they were \"virtual buffers\"." (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 "") @@ -3543,7 +3557,9 @@ it is put to the start of the list." (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 @@ -3761,13 +3777,13 @@ frame, rather than all frames, regardless of value of `ido-all-frames'." (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))) @@ -4027,6 +4043,20 @@ If cursor is not at the end of the user input, delete to end of input." (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'. @@ -4763,7 +4793,7 @@ Modified from `icomplete-completions'." (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 @@ -4777,7 +4807,7 @@ If REQUIRE-MATCH is non-nil, an existing buffer must be selected." (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