summaryrefslogtreecommitdiff
path: root/lisp/minibuffer.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/minibuffer.el')
-rw-r--r--lisp/minibuffer.el165
1 files changed, 130 insertions, 35 deletions
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index fa2dcb4f698..0a844c538b4 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -150,8 +150,29 @@ The metadata of a completion table should be constant between two boundaries."
minibuffer-completion-table
minibuffer-completion-predicate))
+(defun completion--metadata-get-1 (metadata prop)
+ (or (alist-get prop metadata)
+ (plist-get completion-extra-properties
+ ;; Cache the keyword
+ (or (get prop 'completion-extra-properties--keyword)
+ (put prop 'completion-extra-properties--keyword
+ (intern (concat ":" (symbol-name prop))))))))
+
(defun completion-metadata-get (metadata prop)
- (cdr (assq prop metadata)))
+ "Get property PROP from completion METADATA.
+If the metadata specifies a completion category, the variables
+`completion-category-overrides' and
+`completion-category-defaults' take precedence for
+category-specific overrides. If the completion metadata does not
+specify the property, the `completion-extra-properties' plist is
+consulted. Note that the keys of the
+`completion-extra-properties' plist are keyword symbols, not
+plain symbols."
+ (if-let (((not (eq prop 'category)))
+ (cat (completion--metadata-get-1 metadata 'category))
+ (over (completion--category-override cat prop)))
+ (cdr over)
+ (completion--metadata-get-1 metadata prop)))
(defun complete-with-action (action collection string predicate)
"Perform completion according to ACTION.
@@ -300,7 +321,7 @@ the form (concat S2 S)."
;; Predicates are called differently depending on the nature of
;; the completion table :-(
(cond
- ((vectorp table) ;Obarray.
+ ((obarrayp table)
(lambda (sym) (funcall pred (concat prefix (symbol-name sym)))))
((hash-table-p table)
(lambda (s _v) (funcall pred (concat prefix s))))
@@ -1135,23 +1156,42 @@ styles for specific categories, such as files, buffers, etc."
(project-file (styles . (substring)))
(xref-location (styles . (substring)))
(info-menu (styles . (basic substring)))
- (symbol-help (styles . (basic shorthand substring))))
+ (symbol-help (styles . (basic shorthand substring)))
+ (calendar-month (display-sort-function . identity)))
"Default settings for specific completion categories.
+
Each entry has the shape (CATEGORY . ALIST) where ALIST is
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.
+- `cycle-sort-function': function to sort entries when cycling.
+- `display-sort-function': function to sort entries in *Completions*.
+- `group-function': function for grouping the completion candidates.
+- `annotation-function': function to add annotations in *Completions*.
+- `affixation-function': function to prepend/append a prefix/suffix.
+
Categories are symbols such as `buffer' and `file', used when
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.
+ "List of category-specific user overrides for completion metadata.
+
Each override has the shape (CATEGORY . ALIST) where ALIST is
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.
+- `cycle-sort-function': function to sort entries when cycling.
+- `display-sort-function': nil means to use either the sorting
+function from metadata, or if that is nil, fall back to `completions-sort';
+`identity' disables sorting and keeps the original order; and other
+possible values are the same as in `completions-sort'.
+- `group-function': function for grouping the completion candidates.
+- `annotation-function': function to add annotations in *Completions*.
+- `affixation-function': function to prepend/append a prefix/suffix.
+See more description of metadata in `completion-metadata'.
+
Categories are symbols such as `buffer' and `file', used when
completing buffer and file names, respectively.
@@ -1171,7 +1211,33 @@ overrides the default specified in `completion-category-defaults'."
,completion--styles-type)
(cons :tag "Completion Cycling"
(const :tag "Select one value from the menu." cycle)
- ,completion--cycling-threshold-type))))
+ ,completion--cycling-threshold-type)
+ (cons :tag "Cycle Sorting"
+ (const :tag "Select one value from the menu."
+ cycle-sort-function)
+ (choice (function :tag "Custom function")))
+ (cons :tag "Completion Sorting"
+ (const :tag "Select one value from the menu."
+ display-sort-function)
+ (choice (const :tag "Use default" nil)
+ (const :tag "No sorting" identity)
+ (const :tag "Alphabetical sorting"
+ minibuffer-sort-alphabetically)
+ (const :tag "Historical sorting"
+ minibuffer-sort-by-history)
+ (function :tag "Custom function")))
+ (cons :tag "Completion Groups"
+ (const :tag "Select one value from the menu."
+ group-function)
+ (choice (function :tag "Custom function")))
+ (cons :tag "Completion Annotation"
+ (const :tag "Select one value from the menu."
+ annotation-function)
+ (choice (function :tag "Custom function")))
+ (cons :tag "Completion Affixation"
+ (const :tag "Select one value from the menu."
+ affixation-function)
+ (choice (function :tag "Custom function"))))))
(defun completion--category-override (category tag)
(or (assq tag (cdr (assq category completion-category-overrides)))
@@ -1904,10 +1970,13 @@ appear to be a match."
;; Allow user to specify null string
((= beg end) (funcall exit-function))
;; The CONFIRM argument is a predicate.
- ((and (functionp minibuffer-completion-confirm)
- (funcall minibuffer-completion-confirm
- (buffer-substring beg end)))
- (funcall exit-function))
+ ((functionp minibuffer-completion-confirm)
+ (if (funcall minibuffer-completion-confirm
+ (buffer-substring beg end))
+ (funcall exit-function)
+ (unless completion-fail-discreetly
+ (ding)
+ (completion--message "No match"))))
;; See if we have a completion from the table.
((test-completion (buffer-substring beg end)
minibuffer-completion-table
@@ -2379,6 +2448,9 @@ candidates."
"Property list of extra properties of the current completion job.
These include:
+`:category': the kind of objects returned by `all-completions'.
+ Used by `completion-category-overrides'.
+
`:annotation-function': Function to annotate the completions buffer.
The function must accept one argument, a completion string,
and return either nil or a string which is to be displayed
@@ -2394,6 +2466,15 @@ These include:
`:annotation-function' when both are provided, so only this
function is used.
+`:group-function': Function for grouping the completion candidates.
+
+`:display-sort-function': Function to sort entries in *Completions*.
+
+`:cycle-sort-function': Function to sort entries when cycling.
+
+See more information about these functions above
+in `completion-metadata'.
+
`:exit-function': Function to run after completion is performed.
The function must accept two arguments, STRING and STATUS.
@@ -2516,12 +2597,8 @@ The candidate will still be chosen by `choose-completion' unless
base-size md
minibuffer-completion-table
minibuffer-completion-predicate))
- (ann-fun (or (completion-metadata-get all-md 'annotation-function)
- (plist-get completion-extra-properties
- :annotation-function)))
- (aff-fun (or (completion-metadata-get all-md 'affixation-function)
- (plist-get completion-extra-properties
- :affixation-function)))
+ (ann-fun (completion-metadata-get all-md 'annotation-function))
+ (aff-fun (completion-metadata-get all-md 'affixation-function))
(sort-fun (completion-metadata-get all-md 'display-sort-function))
(group-fun (completion-metadata-get all-md 'group-function))
(mainbuf (current-buffer))
@@ -3075,30 +3152,41 @@ the mode hook of this mode."
(setq-local minibuffer-completion-auto-choose nil)))
(defcustom minibuffer-visible-completions nil
- "When non-nil, visible completions can be navigated from the minibuffer.
-This means that when the *Completions* buffer is visible in a window,
-then you can use the arrow keys in the minibuffer to move the cursor
-in the *Completions* buffer. Then you can type `RET',
-and the candidate highlighted in the *Completions* buffer
-will be accepted.
-But when the *Completions* buffer is not displayed on the screen,
-then the arrow keys move point in the minibuffer as usual, and
-`RET' accepts the input typed in the minibuffer."
+ "Whether candidates shown in *Completions* can be navigated from minibuffer.
+When non-nil, if the *Completions* buffer is displayed in a window,
+you can use the arrow keys in the minibuffer to move the cursor in
+the window showing the *Completions* buffer. Typing `RET' selects
+the highlighted completion candidate.
+If the *Completions* buffer is not displayed on the screen, or this
+variable is nil, the arrow keys move point in the minibuffer as usual,
+and `RET' accepts the input typed into the minibuffer."
:type 'boolean
:version "30.1")
+(defvar minibuffer-visible-completions--always-bind nil
+ "If non-nil, force the `minibuffer-visible-completions' bindings on.")
+
+(defun minibuffer-visible-completions--filter (cmd)
+ "Return CMD if `minibuffer-visible-completions' bindings should be active."
+ (if minibuffer-visible-completions--always-bind
+ cmd
+ (when-let ((window (get-buffer-window "*Completions*" 0)))
+ (when (and (eq (buffer-local-value 'completion-reference-buffer
+ (window-buffer window))
+ (window-buffer (active-minibuffer-window)))
+ (if (eq cmd #'minibuffer-choose-completion-or-exit)
+ (with-current-buffer (window-buffer window)
+ (get-text-property (point) 'completion--string))
+ t))
+ cmd))))
+
(defun minibuffer-visible-completions-bind (binding)
"Use BINDING when completions are visible.
Return an item that is enabled only when a window
displaying the *Completions* buffer exists."
`(menu-item
"" ,binding
- :filter ,(lambda (cmd)
- (when-let ((window (get-buffer-window "*Completions*" 0)))
- (when (eq (buffer-local-value 'completion-reference-buffer
- (window-buffer window))
- (window-buffer (active-minibuffer-window)))
- cmd)))))
+ :filter ,#'minibuffer-visible-completions--filter))
(defvar-keymap minibuffer-visible-completions-map
:doc "Local keymap for minibuffer input with visible completions."
@@ -3409,9 +3497,10 @@ Fourth arg MUSTMATCH can take the following values:
input, but she needs to confirm her choice if she called
`minibuffer-complete' right before `minibuffer-complete-and-exit'
and the input is not an existing file.
-- a function, which will be called with the input as the
- argument. If the function returns a non-nil value, the
- minibuffer is exited with that argument as the value.
+- a function, which will be called with a single argument, the
+ input unquoted by `substitute-in-file-name', which see. If the
+ function returns a non-nil value, the minibuffer is exited with
+ that argument as the value.
- anything else behaves like t except that typing RET does not exit if it
does non-null completion.
@@ -3500,7 +3589,13 @@ See `read-file-name' for the meaning of the arguments."
(let ((ignore-case read-file-name-completion-ignore-case)
(minibuffer-completing-file-name t)
(pred (or predicate 'file-exists-p))
- (add-to-history nil))
+ (add-to-history nil)
+ (require-match (if (functionp mustmatch)
+ (lambda (input)
+ (funcall mustmatch
+ ;; User-supplied MUSTMATCH expects an unquoted filename
+ (substitute-in-file-name input)))
+ mustmatch)))
(let* ((val
(if (or (not (next-read-file-uses-dialog-p))
@@ -3536,7 +3631,7 @@ See `read-file-name' for the meaning of the arguments."
(read-file-name--defaults dir initial))))
(set-syntax-table minibuffer-local-filename-syntax))
(completing-read prompt 'read-file-name-internal
- pred mustmatch insdef
+ pred require-match insdef
'file-name-history default-filename)))
;; If DEFAULT-FILENAME not supplied and DIR contains
;; a file name, split it.