diff options
Diffstat (limited to 'lisp/minibuffer.el')
-rw-r--r-- | lisp/minibuffer.el | 211 |
1 files changed, 116 insertions, 95 deletions
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 2724b5a3e6d..36b8d808417 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1,4 +1,4 @@ -;;; minibuffer.el --- Minibuffer completion functions -*- lexical-binding: t -*- +;;; minibuffer.el --- Minibuffer and completion functions -*- lexical-binding: t -*- ;; Copyright (C) 2008-2022 Free Software Foundation, Inc. @@ -900,7 +900,7 @@ If the value is `lazy', the *Completions* buffer is only displayed after the second failed attempt to complete." :type '(choice (const nil) (const t) (const lazy))) -(defconst completion-styles-alist +(defvar completion-styles-alist '((emacs21 completion-emacs21-try-completion completion-emacs21-all-completions "Simple prefix-based completion. @@ -1004,7 +1004,9 @@ an association list that can specify properties such as: - `styles': the list of `completion-styles' to use for that category. - `cycle': the `completion-cycle-threshold' to use for that category. Categories are symbols such as `buffer' and `file', used when -completing buffer and file names, respectively.") +completing buffer and file names, respectively. + +Also see `completion-category-overrides'.") (defcustom completion-category-overrides nil "List of category-specific user overrides for completion styles. @@ -1014,7 +1016,9 @@ an association list that can specify properties such as: - `cycle': the `completion-cycle-threshold' to use for that category. Categories are symbols such as `buffer' and `file', used when completing buffer and file names, respectively. -This overrides the defaults specified in `completion-category-defaults'." + +If a property in a category is specified by this variable, it +overrides the default specified in `completion-category-defaults'." :version "25.1" :type `(alist :key-type (choice :tag "Category" (const buffer) @@ -1076,9 +1080,10 @@ This overrides the defaults specified in `completion-category-defaults'." (result-and-style (completion--some (lambda (style) - (let ((probe (funcall (nth n (assq style - completion-styles-alist)) - string table pred point))) + (let ((probe (funcall + (or (nth n (assq style completion-styles-alist)) + (error "Invalid completion style %s" style)) + string table pred point))) (and probe (cons probe style)))) (completion--styles md))) (adjust-fn (get (cdr result-and-style) 'completion--adjust-metadata))) @@ -1168,6 +1173,18 @@ completion candidates than this number." :version "24.1" :type completion--cycling-threshold-type) +(defcustom completions-sort 'alphabetical + "Sort candidates in the *Completions* buffer. + +The value can be nil to disable sorting, `alphabetical' for +alphabetical sorting or a custom sorting function. The sorting +function takes and returns a list of completion candidate +strings." + :type '(choice (const :tag "No sorting" nil) + (const :tag "Alphabetical sorting" alphabetical) + (function :tag "Custom function")) + :version "29.1") + (defcustom completions-group nil "Enable grouping of completion candidates in the *Completions* buffer. See also `completions-group-format' and `completions-group-sort'." @@ -1379,14 +1396,18 @@ scroll the window of possible completions." ;; and this command is repeated, scroll that window. ((and (window-live-p minibuffer-scroll-window) (eq t (frame-visible-p (window-frame minibuffer-scroll-window)))) - (let ((window minibuffer-scroll-window)) + (let ((window minibuffer-scroll-window) + (reverse (equal (this-command-keys) [backtab]))) (with-current-buffer (window-buffer window) - (if (pos-visible-in-window-p (point-max) window) - ;; If end is in view, scroll up to the beginning. - (set-window-start window (point-min) nil) + (if (pos-visible-in-window-p (if reverse (point-min) (point-max)) window) + ;; If end or beginning is in view, scroll up to the + ;; beginning or end respectively. + (if reverse + (set-window-point window (point-max)) + (set-window-start window (point-min) nil)) ;; Else scroll down one screen. (with-selected-window window - (scroll-up))) + (if reverse (scroll-down) (scroll-up)))) nil))) ;; If we're cycling, keep on cycling. ((and completion-cycling completion-all-sorted-completions) @@ -2259,7 +2280,10 @@ variables.") ;; same, but not always. (setq completions (if sort-fun (funcall sort-fun completions) - (sort completions 'string-lessp))) + (pcase completions-sort + ('nil completions) + ('alphabetical (sort completions #'string-lessp)) + (_ (funcall completions-sort completions))))) ;; After sorting, group the candidates using the ;; `group-function'. @@ -2444,14 +2468,12 @@ Also respects the obsolete wrapper hook `completion-in-region-functions'. (completion-in-region-mode 1)) (completion--in-region-1 start end)))) -(defvar completion-in-region-mode-map - (let ((map (make-sparse-keymap))) - ;; FIXME: Only works if completion-in-region-mode was activated via - ;; completion-at-point called directly. - (define-key map "\M-?" 'completion-help-at-point) - (define-key map "\t" 'completion-at-point) - map) - "Keymap activated during `completion-in-region'.") +(defvar-keymap completion-in-region-mode-map + :doc "Keymap activated during `completion-in-region'." + ;; FIXME: Only works if completion-in-region-mode was activated via + ;; completion-at-point called directly. + "M-?" #'completion-help-at-point + "TAB" #'completion-at-point) ;; It is difficult to know when to exit completion-in-region-mode (i.e. hide ;; the *Completions*). Here's how previous packages did it: @@ -2647,48 +2669,41 @@ The completion method is determined by `completion-at-point-functions'." (define-key map "\n" 'exit-minibuffer) (define-key map "\r" 'exit-minibuffer)) -(defvar minibuffer-local-completion-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map minibuffer-local-map) - (define-key map "\t" 'minibuffer-complete) - ;; M-TAB is already abused for many other purposes, so we should find - ;; another binding for it. - ;; (define-key map "\e\t" 'minibuffer-force-complete) - (define-key map " " 'minibuffer-complete-word) - (define-key map "?" 'minibuffer-completion-help) - (define-key map [prior] 'switch-to-completions) - (define-key map "\M-v" 'switch-to-completions) - (define-key map "\M-g\M-c" 'switch-to-completions) - map) - "Local keymap for minibuffer input with completion.") - -(defvar minibuffer-local-must-match-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map minibuffer-local-completion-map) - (define-key map "\r" 'minibuffer-complete-and-exit) - (define-key map "\n" 'minibuffer-complete-and-exit) - map) - "Local keymap for minibuffer input with completion, for exact match.") - -(defvar minibuffer-local-filename-completion-map - (let ((map (make-sparse-keymap))) - (define-key map " " nil) - map) - "Local keymap for minibuffer input with completion for filenames. +(defvar-keymap minibuffer-local-completion-map + :doc "Local keymap for minibuffer input with completion." + :parent minibuffer-local-map + "TAB" #'minibuffer-complete + "<backtab>" #'minibuffer-complete + ;; M-TAB is already abused for many other purposes, so we should find + ;; another binding for it. + ;; "M-TAB" #'minibuffer-force-complete + "SPC" #'minibuffer-complete-word + "?" #'minibuffer-completion-help + "<prior>" #'switch-to-completions + "M-v" #'switch-to-completions + "M-g M-c" #'switch-to-completions) + +(defvar-keymap minibuffer-local-must-match-map + :doc "Local keymap for minibuffer input with completion, for exact match." + :parent minibuffer-local-completion-map + "RET" #'minibuffer-complete-and-exit + "C-j" #'minibuffer-complete-and-exit) + +(defvar-keymap minibuffer-local-filename-completion-map + :doc "Local keymap for minibuffer input with completion for filenames. Gets combined either with `minibuffer-local-completion-map' or -with `minibuffer-local-must-match-map'.") +with `minibuffer-local-must-match-map'." + "SPC" nil) (defvar minibuffer-local-filename-must-match-map (make-sparse-keymap)) (make-obsolete-variable 'minibuffer-local-filename-must-match-map nil "24.1") -(defvar minibuffer-local-ns-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map minibuffer-local-map) - (define-key map " " #'exit-minibuffer) - (define-key map "\t" #'exit-minibuffer) - (define-key map "?" #'self-insert-and-exit) - map) - "Local keymap for the minibuffer when spaces are not allowed.") +(defvar-keymap minibuffer-local-ns-map + :doc "Local keymap for the minibuffer when spaces are not allowed." + :parent minibuffer-local-map + "SPC" #'exit-minibuffer + "TAB" #'exit-minibuffer + "?" #'self-insert-and-exit) (defun read-no-blanks-input (prompt &optional initial inherit-input-method) "Read a string from the terminal, not allowing blanks. @@ -2709,24 +2724,23 @@ If `inhibit-interaction' is non-nil, this function will signal an ;;; Major modes for the minibuffer -(defvar minibuffer-inactive-mode-map - (let ((map (make-keymap))) - (suppress-keymap map) - (define-key map "e" 'find-file-other-frame) - (define-key map "f" 'find-file-other-frame) - (define-key map "b" 'switch-to-buffer-other-frame) - (define-key map "i" 'info) - (define-key map "m" 'mail) - (define-key map "n" 'make-frame) - (define-key map [mouse-1] 'view-echo-area-messages) - ;; So the global down-mouse-1 binding doesn't clutter the execution of the - ;; above mouse-1 binding. - (define-key map [down-mouse-1] #'ignore) - map) - "Keymap for use in the minibuffer when it is not active. +(defvar-keymap minibuffer-inactive-mode-map + :doc "Keymap for use in the minibuffer when it is not active. The non-mouse bindings in this keymap can only be used in minibuffer-only frames, since the minibuffer can normally not be selected when it is -not active.") +not active." + :full t + :suppress t + "e" #'find-file-other-frame + "f" #'find-file-other-frame + "b" #'switch-to-buffer-other-frame + "i" #'info + "m" #'mail + "n" #'make-frame + "<mouse-1>" #'view-echo-area-messages + ;; So the global down-mouse-1 binding doesn't clutter the execution of the + ;; above mouse-1 binding. + "<down-mouse-1>" #'ignore) (define-derived-mode minibuffer-inactive-mode nil "InactiveMinibuffer" :abbrev-table nil ;abbrev.el is not loaded yet during dump. @@ -2735,7 +2749,7 @@ not active.") This is only used when the minibuffer area has no active minibuffer. Note that the minibuffer may change to this mode more often than -you might expect. For instance, typing `M-x' may change the +you might expect. For instance, typing \\`M-x' may change the buffer to this mode, then to a different mode, and then back again to this mode upon exit. Code running from `minibuffer-inactive-mode-hook' has to be prepared to run @@ -2918,26 +2932,30 @@ same as `substitute-in-file-name'." (let* ((ustr (substitute-in-file-name qstr)) (uprefix (substring ustr 0 upos)) qprefix) - ;; Main assumption: nothing after qpos should affect the text before upos, - ;; so we can work our way backward from the end of qstr, one character - ;; at a time. - ;; Second assumptions: If qpos is far from the end this can be a bit slow, - ;; so we speed it up by doing a first loop that skips a word at a time. - ;; This word-sized loop is careful not to cut in the middle of env-vars. - (while (let ((boundary (string-match "\\(\\$+{?\\)?\\w+\\W*\\'" qstr))) - (and boundary - (progn - (setq qprefix (substring qstr 0 boundary)) + (if (eq upos (length ustr)) + ;; Easy and common case. This not only speed things up in a very + ;; common case but it also avoids problems in some cases (bug#53053). + (cons (length qstr) #'minibuffer-maybe-quote-filename) + ;; Main assumption: nothing after qpos should affect the text before upos, + ;; so we can work our way backward from the end of qstr, one character + ;; at a time. + ;; Second assumptions: If qpos is far from the end this can be a bit slow, + ;; so we speed it up by doing a first loop that skips a word at a time. + ;; This word-sized loop is careful not to cut in the middle of env-vars. + (while (let ((boundary (string-match "\\(\\$+{?\\)?\\w+\\W*\\'" qstr))) + (and boundary + (progn + (setq qprefix (substring qstr 0 boundary)) + (string-prefix-p uprefix + (substitute-in-file-name qprefix))))) + (setq qstr qprefix)) + (let ((qpos (length qstr))) + (while (and (> qpos 0) (string-prefix-p uprefix - (substitute-in-file-name qprefix))))) - (setq qstr qprefix)) - (let ((qpos (length qstr))) - (while (and (> qpos 0) - (string-prefix-p uprefix - (substitute-in-file-name - (substring qstr 0 (1- qpos))))) - (setq qpos (1- qpos))) - (cons qpos #'minibuffer-maybe-quote-filename)))) + (substitute-in-file-name + (substring qstr 0 (1- qpos))))) + (setq qpos (1- qpos))) + (cons qpos #'minibuffer-maybe-quote-filename))))) (defalias 'completion--file-name-table (completion-table-with-quoting #'completion-file-name-table @@ -3052,7 +3070,10 @@ Fourth arg MUSTMATCH can take the following values: - anything else behaves like t except that typing RET does not exit if it does non-null completion. -Fifth arg INITIAL specifies text to start with. +Fifth arg INITIAL specifies text to start with. It will be +interpreted as the trailing part of DEFAULT-FILENAME, so using a +full file name for INITIAL will usually lead to surprising +results. Sixth arg PREDICATE, if non-nil, should be a function of one argument; then a file name is considered an acceptable completion |