From: Eshel Yaron Date: Thu, 21 Dec 2023 19:43:59 +0000 (+0100) Subject: Support narrowing (restricting) minibuffer completions X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ab27da21e6ac5602dc10ea039c0c7e82c746f743;p=emacs.git Support narrowing (restricting) minibuffer completions Add new minibuffer commands for restricting the list of possible completion candidates. * lisp/minibuffer.el (completion-fail-discreetly): Fix docstring typo. (minibuffer-narrow-completions-function): New variable. (completion--fail, minibuffer-narrow-completions-p) (minibuffer-narrow-completions-by-regexp) (minibuffer--completion-predicate-description) (minibuffer--add-completions-predicate): New functions. (minibuffer-narrow-completions-to-current) (minibuffer-narrow-completions) (minibuffer-widen-completions): New commands. (minibuffer-narrow-completions-map): New prefix keymap. Bind new commands to 'n', 'm' and 'w', respectively. (minibuffer-local-completion-map): Bind new prefix keymap to 'C-x n'. (completions-header-format, completion--do-completion) (display-completion-list, minibuffer-completion-help): Update. * lisp/simple.el (completions-narrow-mode): New minor mode. (completion-setup-function): Enable it in *Completions* buffer when there are completions restrictions in place. * lisp/menu-bar.el (minibuffer-local-completion-map): Add completions narrowing commands to "Minibuf" menu. * lisp/help-fns.el (help--symbol-completion-table): Provide bespoke 'narrow-completions-function' that keeps only symbols with a given symbol property. * doc/emacs/emacs.texi (Top) * doc/emacs/mini.texi (Completion): Update menu. (Narrow Completions): New subsection. (Completion Commands, Completion Styles) (Completion Options) * doc/emacs/help.texi (Name Help) * doc/lispref/minibuf.texi (Completion Commands): (Programmed Completion): Update documenation. * etc/NEWS: Announce new feature. --- diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 7d77f13ab21..b9be2de49fd 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi @@ -294,6 +294,7 @@ Completion * Completion Commands:: A list of completion commands. * Completion Exit:: Completion and minibuffer text submission. * Completion Styles:: How completion matches are chosen. +* Narrow Completions:: Restricting completion candidates. * Completion Options:: Options for completion. Help diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi index 99a4173ac29..5bed5d6f037 100644 --- a/doc/emacs/help.texi +++ b/doc/emacs/help.texi @@ -355,6 +355,14 @@ variable, or a face. If the symbol has more than one definition, like it has both definition as a function and as a variable, this command will show the documentation of all of them, one after the other. + Help commands that read a symbol in the minibuffer, such as @kbd{C-h +f}, @kbd{C-h v} and @kbd{C-h o}, provide completions based on known +symbols. @xref{Completion}. You can narrow the list of possible +completions to only include symbols with a given property by typing +@kbd{C-x n m @var{property-name} @key{RET}} in the minibuffer. +@xref{Narrow Completions}, and @ref{Symbol Properties,,,elisp,The +Emacs Lisp Reference Manual}. + @vindex completions-detailed If the @code{completions-detailed} user option is non-@code{nil}, some commands provide details about the possible values when diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index aa7144610a6..19371b7c897 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -290,6 +290,7 @@ Completion}. * Completion Commands:: A list of completion commands. * Completion Exit:: Completion and minibuffer text submission. * Completion Styles:: How completion matches are chosen. +* Narrow Completions:: Restricting completion candidates. * Completion Options:: Options for completion. @end menu @@ -352,6 +353,15 @@ arguments that often include spaces, such as file names. @item @key{RET} Submit the text in the minibuffer as the argument, possibly completing first (@code{minibuffer-complete-and-exit}). @xref{Completion Exit}. +@item C-x n n +Narrow (restrict) the list of possible completions according to the +current minibuffer input +(@code{minibuffer-narrow-completions-to-current}). +@item C-x n m +Narrow the list of possible completions in a command-specific manner +(@code{minibuffer-narrow-completions}). +@item C-x n w +Remove all completions restrictions (@code{minibuffer-widen-completions}). @item ? Display a list of completions (@code{minibuffer-completion-help}). @end table @@ -373,6 +383,27 @@ completion is @samp{auto-fill-mode}, but it only inserts @samp{ill-}, giving @samp{auto-fill-}. Another @key{SPC} at this point completes all the way to @samp{auto-fill-mode}. +@kindex C-x n n @r{(completion)} +@findex minibuffer-narrow-completions-to-current + @kbd{C-x n n} (@code{minibuffer-narrow-completions-to-current}) +narrows the list of possible completions according to the current +minibuffer input. This command clears your current minibuffer input +and restricts the list of possible completions to candidates matching +that input. @xref{Narrow Completions}. + +@kindex C-x n m @r{(completion)} +@findex minibuffer-narrow-completions + @kbd{C-x n m} (@code{minibuffer-narrow-completions}) is similar to +@kbd{C-x n n}, except that this command can provide different ways to +narrow the completions list depending on the kind of candidates in +that list. @xref{Narrow Completions}, for more details. + +@kindex C-x n w @r{(completion)} +@findex minibuffer-widen-completions + @kbd{C-x n w} (@code{minibuffer-widen-completions}) removes all +completions restrictions that you set with @kbd{C-x n n} or with +@kbd{C-x n m}. + @kindex ? @r{(completion)} @cindex completion list If @key{TAB} or @key{SPC} is unable to complete, it displays a list @@ -608,6 +639,57 @@ by setting the variable @code{completion-category-overrides}. For example, the default setting says to use only @code{basic} and @code{substring} completion for buffer names. +@node Narrow Completions +@subsection Completions Narrowing + +@cindex completions restriction +@cindex restrict completions +@cindex completions filter +@cindex filter completions +@cindex completions narrowing + When there are many possible completion candidates, you may want to +narrow the selection to a smaller subset by filtering out some of the +options. You can use the commands @kbd{C-x n n} and @kbd{C-x n m} in +the minibuffer to restrict the completions list. Narrowing the list +of minibuffer completions is different from narrowing buffers +(@pxref{Narrowing}), although the two are conceptually related since +both allow you to focus on some part of a larger whole. + + @kbd{C-x n n} (@code{minibuffer-narrow-completions-to-current} +restricts the list of possible completions to only include candidates +that match the current minibuffer input. This command clears the +minibuffer so you can type another (partial) input and complete it +with completion candidates that also match the previous input. If you +call this command with a negative prefix argument (@kbd{C-- C-x n n}), +it instead excludes all matches for the current input from subsequent +completions. + + @kbd{C-x n m} (@code{minibuffer-narrow-completions} is similar to +@kbd{C-x n n}, but more versatile. This command restricts the list of +possible completions in different ways, depending on what kind of +completion candidates you're dealing with. For example, commands that +read a symbol name from the minibuffer, such as @kbd{C-h f} and +@kbd{C-h o} (@pxref{Name Help}), let you restrict the completions list +with @kbd{C-x n m} to show only symbols with a given property. +@xref{Symbol Properties,,,elisp,The Emacs Lisp Reference Manual}. +When the command does not provide a specific way of restricting +completion candidates, @kbd{C-x n m} prompts you for a regular +expression and narrows the completions list to only include candidates +which match that regular expression. @xref{Regexps}. + +When you narrow the completions list with @kbd{C-x n n} or with +@kbd{C-x n m}, Emacs extends the completions heading line with a +description of the restriction that is currently in effect. The mode +line of the @file{*Completions*} buffer also indicates the restriction +with the text @samp{CompsNarrow}. You can apply multiple restrictions +one after the other to narrow the completions list incrementally. For +example, typing @kbd{M-x C-x n m foo @key{RET} C-x n m bar @key{RET}} +shows only commands that match both @samp{foo} and @samp{bar} in the +completions list. + + You can use @kbd{C-x n w} (@code{minibuffer-widen-completions}) in +the minibuffer to remove the restrictions on the list of possible +completions that you set with @kbd{C-x n n} or with @kbd{C-x n m}. @node Completion Options @subsection Completion Options @@ -725,16 +807,17 @@ Alists,,Action Alists for Buffer Display, elisp, The Emacs Lisp Reference Manual}). @vindex completions-header-format -The variable @code{completions-header-format} is a format spec string to -control the informative line shown before the completions list of -candidates. If it contains a @samp{%s} construct, that get replaced -by the number of completions shown in the completion list buffer. To -suppress the display of the heading line, customize this variable to -@code{nil}. The string that is the value of this variable can have -text properties to change the visual appearance of the heading line; -some useful properties @code{face} or @code{cursor-intangible} -(@pxref{Special Properties,,Properties with Special Meanings, elisp, -The Emacs Lisp Reference Manual}). +The variable @code{completions-header-format} is a format spec string +to control the informative line shown before the completions list of +candidates. Emacs substitutes @samp{%s} and @samp{%r} constructs that +occur in this string with the number of completion candidates and a +description of the current completions restriction, respectively. +@xref{Narrow Completions}. To suppress the display of the heading +line, customize this variable to @code{nil}. The string that is the +value of this variable can have text properties to change the visual +appearance of the heading line; some useful properties are @code{face} +or @code{cursor-intangible} (@pxref{Special Properties,,Properties +with Special Meanings, elisp, The Emacs Lisp Reference Manual}). @vindex completions-highlight-face When @code{completions-highlight-face} names a face, the current diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index aa27de72ba0..471ec848b14 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -1326,6 +1326,41 @@ The list of completions is displayed as text in a buffer named @file{*Completions*}. @end deffn +@defvar minibuffer-narrow-completions-function +The value of this variable is a function that command +@code{minibuffer-narrow-completions} (@kbd{C-x n m} in the minibuffer) +calls to restrict the list of completion candidates. +@code{minibuffer-narrow-completions} calls the function that is the +value of this variable with no arguments, and this function should +return a cons cell @code{(@var{pred} . @var{desc})} where @var{pred} +is a function that takes one argument, a completion candidate, and +returns non-@code{nil} if that candidate should appear in the +@file{*Completions*} list, and @var{desc} is a string describing +@var{pred}. +@end defvar + +@deffn minibuffer-narrow-completions-by-regexp +This function is the default value of +@code{minibuffer-narrow-completions-function}. This function prompts +for a regular expression, and returns a completions predicate that +only keeps candidates matching that regular expression. +@end deffn + +@deffn Command minibuffer-narrow-completions +This function narrows (restricts) the list of possible completions. +It calls the function that the variable +@code{minibuffer-narrow-completions-function} specifies to get a +completions predicate, and adds that predicate to +@code{minibuffer-completion-predicate}. +@end deffn + +@deffn Command minibuffer-narrow-completions-to-current +This is similar to @code{minibuffer-narrow-completions}, except that +@code{minibuffer-narrow-completions-to-current} restricts restricts +the list of possible completions to only include candidates that match +the current minibuffer input. +@end deffn + @defun display-completion-list completions This function displays @var{completions} to the stream in @code{standard-output}, usually a buffer. (@xref{Read and Print}, for more @@ -1368,6 +1403,9 @@ keymap makes the following bindings: @item @key{TAB} @code{minibuffer-complete} + +@item C-x n +@code{minibuffer-narrow-completions-map} @end table @noindent @@ -1375,6 +1413,23 @@ and uses @code{minibuffer-local-map} as its parent keymap (@pxref{Definition of minibuffer-local-map}). @end defvar +@defvar minibuffer-narrow-completions-map +This keymap provides access to commands that deal with restricting the +list of possible completions. By default, this keymap makes the +following bindings: + +@table @asis +@item n +@code{minibuffer-narrow-completions-to-current} + +@item m +@code{minibuffer-narrow-completions} + +@item w +@code{minibuffer-widen-completions} +@end table +@end defvar + @defvar minibuffer-local-must-match-map @code{completing-read} uses this value as the local keymap when an exact match of one of the completions is required. Therefore, no keys @@ -2092,6 +2147,14 @@ The value should be a function for sorting completions, when cycling through completion alternatives. @xref{Completion Options,,, emacs, The GNU Emacs Manual}. Its argument list and return value are the same as for @code{display-sort-function}. + +@cindex @code{narrow-completions-function}, in completion +@item narrow-completions-function +The value should be a function for restricting completions. Command +@code{minibuffer-narrow-completions} (@kbd{C-x n m} in the minibuffer) +calls this function instead of +@code{minibuffer-narrow-completions-function}. @xref{Completion +Commands}. @end table @defun completion-table-dynamic function &optional switch-buffer diff --git a/etc/NEWS b/etc/NEWS index 735a05f6579..a07b54e02fd 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -768,6 +768,13 @@ defined in completion metadata. The new supported completion properties are 'category', 'group-function', 'display-sort-function', 'cycle-sort-function'. ++++ +*** New commands for narrowing (restricting) minibuffer completions list. +You can now use 'C-x n n' ('minibuffer-narrow-completions-to-current') +in the minibuffer to restrict the list of possible completions to only +include candidates matching the current minibuffer input. See the +Info node "(emacs) Narrow Completions" for more information. + ** Pcomplete --- diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 99642d08bbd..c60c057b911 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -200,12 +200,35 @@ type specifier when available." "")))) completions)) +(defun help--symbol-narrow-by-property () + "Restrict symbol completions list to symbols with a given property." + (let ((prop (intern + (completing-read "Symbol property: " + (let ((props (make-hash-table))) + (mapatoms + (lambda (sym) + (let ((plist (symbol-plist sym))) + (while plist + (puthash (car plist) t props) + (setq plist (cddr plist)))))) + props))))) + (cons (lambda (cand &rest _) + (let ((sym (if (symbolp cand) + cand + (intern + (if (stringp cand) + cand + (car cand)))))) + (get sym prop))) + (format "with property %s" prop)))) + (defun help--symbol-completion-table (string pred action) (if (eq action 'metadata) `(metadata ,@(when completions-detailed '((affixation-function . help--symbol-completion-table-affixation))) - (category . symbol-help)) + (category . symbol-help) + (narrow-completions-function . help--symbol-narrow-by-property)) (when help-enable-completion-autoload (let ((prefixes (radix-tree-prefixes (help-definition-prefixes) string))) (help--load-prefixes prefixes))) diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 477e3036b47..1d8efd28996 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -2556,6 +2556,22 @@ It must accept a buffer as its only required argument.") (cons "Minibuf" (make-sparse-keymap "Minibuf")))) (let ((map minibuffer-local-completion-map)) + (bindings--define-key map + [menu-bar minibuf minibuffer-widen-completions] + '(menu-item "Remove Completions Restrictions" + minibuffer-widen-completions + :help "Remove all restrictions on completions list" + :enable (minibuffer-narrow-completions-p))) + (bindings--define-key map + [menu-bar minibuf minibuffer-narrow-completions] + '(menu-item "Restrict Completions" + minibuffer-narrow-completions + :help "Restrict list of completion candidates")) + (bindings--define-key map + [menu-bar minibuf minibuffer-narrow-completions-to-current] + '(menu-item "Restrict to Current Completions" + minibuffer-narrow-completions-to-current + :help "Restrict completions according to minibuffer input")) (bindings--define-key map [menu-bar minibuf ?\?] '(menu-item "List Completions" minibuffer-completion-help :help "Display all possible completions")) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 45aab398078..af61694e923 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1455,7 +1455,21 @@ pair of a group title string and a list of group candidate strings." (defvar completion-tab-width nil) (defvar completion-fail-discreetly nil - "If non-nil, stay quiet when there is no match.") + "If non-nil, stay quiet when there is no match.") + +(defun completion--fail () + (unless completion-fail-discreetly + (ding) + (completion--message + (format + "No match%s" + (if (minibuffer-narrow-completions-p) + (substitute-command-keys + (concat + ", \\[minibuffer-widen-completions] to clear restrictions (" + (minibuffer--completion-predicate-description) + ")")) + ""))))) (defun completion--message (msg) (if completion-show-inline-help @@ -1493,9 +1507,7 @@ when the buffer's text is already an exact match." (cond ((null comp) (minibuffer-hide-completions) - (unless completion-fail-discreetly - (ding) - (completion--message "No match")) + (completion--fail) (minibuffer--bitset nil nil nil)) ((eq t comp) (minibuffer-hide-completions) @@ -1546,9 +1558,9 @@ when the buffer's text is already an exact match." (substring completion 0 comp-pos) minibuffer-completion-table minibuffer-completion-predicate - "")) - comp-pos))) - (completion-all-sorted-completions beg end)))) + "")) + comp-pos))) + (completion-all-sorted-completions beg end)))) (completion--flush-all-sorted-completions) (cond ((and (consp (cdr comps)) ;; There's something to cycle. @@ -2157,16 +2169,17 @@ completions." :version "28.1") (defcustom completions-header-format - (propertize "%s possible completions:\n" 'face 'shadow) + (propertize "%s possible completions%r:\n" 'face 'shadow) "If non-nil, the format string for completions heading line. -The heading line is inserted before the completions, and is intended -to summarize the completions. -The format string may include one %s, which will be replaced with -the total count of possible completions. -If this is nil, no heading line will be shown." +The heading line is inserted before the completions, and is +intended to summarize the completions. The format string may +contain the sequences \"%s\" and \"%r\", which are substituted +with the total count of possible completions and the description +of a description of the current completions restriction, +respectively. If this option is nil, no heading line is shown." :type '(choice (const :tag "No heading line" nil) (string :tag "Format string for heading line")) - :version "29.1") + :version "30.1") (defun completion--insert-strings (strings &optional group-fun) "Insert a list of STRINGS into the current buffer. @@ -2401,6 +2414,16 @@ and with BASE-SIZE appended as the last element." completions) base-size)))) +(defun minibuffer--completion-predicate-description () + (and (functionp minibuffer-completion-predicate) + (let ((descs nil)) + (advice-function-mapc + (lambda (_ alist) + (when-let ((description (alist-get 'description alist))) + (push description descs))) + minibuffer-completion-predicate) + (when descs (mapconcat #'identity descs ", "))))) + (defun display-completion-list (completions &optional common-substring group-fun) "Display the list of completions, COMPLETIONS, using `standard-output'. Each element may be just a symbol or string @@ -2428,15 +2451,20 @@ candidates." (with-suppressed-warnings ((callargs display-completion-list)) (display-completion-list completions common-substring group-fun))) (princ (buffer-string))) - - (with-current-buffer standard-output - (goto-char (point-max)) - (if completions-header-format - (insert (format completions-header-format (length completions))) - (unless completion-show-help - ;; Ensure beginning-of-buffer isn't a completion. - (insert (propertize "\n" 'face '(:height 0))))) - (completion--insert-strings completions group-fun))) + (let ((pred-desc + (if-let ((pd (minibuffer--completion-predicate-description))) + (concat ", " pd) + ""))) + (with-current-buffer standard-output + (goto-char (point-max)) + (if completions-header-format + (insert (format-spec completions-header-format + (list (cons ?s (length completions)) + (cons ?r pred-desc)))) + (unless completion-show-help + ;; Ensure beginning-of-buffer isn't a completion. + (insert (propertize "\n" 'face '(:height 0))))) + (completion--insert-strings completions group-fun)))) (run-hooks 'completion-setup-hook) nil) @@ -2569,9 +2597,7 @@ The candidate will still be chosen by `choose-completion' unless (remove-hook 'after-change-functions #'completions--after-change t) (if completions (completion--message "Sole completion") - (unless completion-fail-discreetly - (ding) - (completion--message "No match")))) + (completion--fail))) (let* ((last (last completions)) (base-size (or (cdr last) 0)) @@ -3061,7 +3087,8 @@ The completion method is determined by `completion-at-point-functions'." "M-g M-c" #'switch-to-completions "M-" #'minibuffer-previous-completion "M-" #'minibuffer-next-completion - "M-RET" #'minibuffer-choose-completion) + "M-RET" #'minibuffer-choose-completion + "C-x n" 'minibuffer-narrow-completions-map) (defvar-keymap minibuffer-local-must-match-map :doc "Local keymap for minibuffer input with completion, for exact match." @@ -3082,6 +3109,15 @@ with `minibuffer-local-must-match-map'." "TAB" #'exit-minibuffer "?" #'self-insert-and-exit) +(defvar-keymap minibuffer-narrow-completions-map + :doc "Keymap for completions narrowing commands." + "n" #'minibuffer-narrow-completions-to-current + "m" #'minibuffer-narrow-completions + "w" #'minibuffer-widen-completions) + +(defalias 'minibuffer-narrow-completions-map + minibuffer-narrow-completions-map) + (defun read-no-blanks-input (prompt &optional initial inherit-input-method) "Read a string from the terminal, not allowing blanks. Prompt with PROMPT. Whitespace terminates the input. If INITIAL is @@ -4941,6 +4977,123 @@ instead of the completion table." (define-key minibuffer-local-map [?\C-x up] 'minibuffer-complete-history) (define-key minibuffer-local-map [?\C-x down] 'minibuffer-complete-defaults) +(defun minibuffer-narrow-completions-p () + "Return non-nil if there are restrictions on current completions list." + (functionp minibuffer-completion-predicate) + (let ((result nil)) + (advice-function-mapc + (lambda (_ alist) + (setq result (alist-get 'description alist))) + minibuffer-completion-predicate) + result)) + +(defvar minibuffer-narrow-completions-function + #'minibuffer-narrow-completions-by-regexp + "Function to use for restricting the list of completions candidates. + +Minibuffer command `minibuffer-narrow-completions' calls this +function with no arguments. This function should return a cons +cell (PRED . DESC) where PRED is a function that takes one +completion candidate and returns non-nil if it should appear in +the *Completions* buffer, and DESC is a string describing PRED.") + +(defun minibuffer-narrow-completions-by-regexp () + "Narrow completion candidates by matching a given regular expression. +This function is the default value of variable +`minibuffer-narrow-completions-function', which see." + (let* ((input (minibuffer-contents)) + (point (- (point) (minibuffer-prompt-end))) + (regexp (minibuffer-with-setup-hook + (lambda () + (insert input) + (goto-char (+ point (minibuffer-prompt-end)))) + (read-regexp "Keep candidates matching regexp: ")))) + (delete-minibuffer-contents) + (cons (lambda (cand &rest _) + (let ((string (cond + ((stringp cand) cand) + ((symbolp cand) (symbol-name cand)) + (t (car cand))))) + (string-match-p regexp string))) + (concat "matching " (prin1-to-string regexp))))) + +(defun minibuffer--add-completions-predicate (pred desc) + "Restrict minibuffer completions list to candidates satisfying PRED. +DESC is a string describing predicate PRED." + (unless minibuffer-completion-predicate + (setq-local minibuffer-completion-predicate #'always)) + (add-function :after-while (local 'minibuffer-completion-predicate) + pred `((description . ,desc))) + (when completion-auto-help + (minibuffer-completion-help)) + (when-let ((completions-buffer (get-buffer "*Completions*"))) + (with-current-buffer completions-buffer + (completions-narrow-mode)))) + +(defun minibuffer-narrow-completions () + "Restrict completion candidates for current minibuffer interaction." + (interactive "" minibuffer-mode) + (let* ((enable-recursive-minibuffers t) + (filter-desc + (funcall (or (completion-metadata-get + (completion--field-metadata (minibuffer-prompt-end)) + 'narrow-completions-function) + minibuffer-narrow-completions-function)))) + (minibuffer--add-completions-predicate (car filter-desc) (cdr filter-desc)))) + +(defun minibuffer-narrow-completions-to-current (arg) + "Restrict completion candidates according to current minibuffer input. +ARG is the numeric prefix argument. When ARG is negative, +exclude matches to current input from completions list." + (interactive "p" minibuffer-mode) + (let* ((table (make-hash-table :test #'equal)) + (start (minibuffer--completion-prompt-end)) + (string (buffer-substring start (point-max))) + (all (completion-all-completions + string + minibuffer-completion-table + minibuffer-completion-predicate + (- (point) start) + (completion--field-metadata start))) + (last (last all))) + (unless all + (user-error "No matching completion candidates")) + (delete-minibuffer-contents) + (setcdr last nil) + (dolist (str all) + (puthash str t table)) + (if (< arg 0) + (minibuffer--add-completions-predicate + (lambda (cand &rest _) + (let ((key (cond + ((stringp cand) cand) + ((symbolp cand) (symbol-name cand)) + (t (car cand))))) + (not (gethash key table)))) + (concat "excluding matches for " (prin1-to-string string))) + (minibuffer--add-completions-predicate + (lambda (cand &rest _) + (let ((key (cond + ((stringp cand) cand) + ((symbolp cand) (symbol-name cand)) + (t (car cand))))) + (gethash key table))) + (concat "narrowing to " (prin1-to-string string)))))) + +(defun minibuffer-widen-completions () + "Remove all restrictions on current completion candidates." + (interactive "" minibuffer-mode) + (advice-function-mapc + (lambda (a p) + (when (alist-get 'description p) + (remove-function (local 'minibuffer-completion-predicate) a))) + minibuffer-completion-predicate) + (when completion-auto-help + (minibuffer-completion-help)) + (when-let ((completions-buffer (get-buffer "*Completions*"))) + (with-current-buffer completions-buffer + (completions-narrow-mode -1)))) + (defcustom minibuffer-default-prompt-format " (default %s)" "Format string used to output \"default\" values. When prompting for input, there will often be a default value, diff --git a/lisp/simple.el b/lisp/simple.el index 692c0dacefc..48b617b17c1 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10284,6 +10284,11 @@ Called from `temp-buffer-show-hook'." :version "22.1" :group 'completion) +(define-minor-mode completions-narrow-mode + "Minor mode for *Completions* buffer with completions narrowing." + :interactive nil + :lighter " CompsNarrow") + ;; This function goes in completion-setup-hook, so that it is called ;; after the text of the completion list buffer is written. (defun completion-setup-function () @@ -10302,7 +10307,14 @@ Called from `temp-buffer-show-hook'." (if minibuffer-completing-file-name (file-name-directory (expand-file-name - (buffer-substring (minibuffer-prompt-end) (point))))))) + (buffer-substring (minibuffer-prompt-end) (point)))))) + (narrow (and (functionp minibuffer-completion-predicate) + (let ((result nil)) + (advice-function-mapc + (lambda (_ alist) + (setq result (alist-get 'description alist))) + minibuffer-completion-predicate) + result)))) (with-current-buffer standard-output (let ((base-position completion-base-position) (base-affixes completion-base-affixes) @@ -10310,7 +10322,8 @@ Called from `temp-buffer-show-hook'." (completion-list-mode) (setq-local completion-base-position base-position) (setq-local completion-base-affixes base-affixes) - (setq-local completion-list-insert-choice-function insert-fun)) + (setq-local completion-list-insert-choice-function insert-fun) + (when narrow (completions-narrow-mode))) (setq-local completion-reference-buffer mainbuf) (if base-dir (setq default-directory base-dir)) (when completion-tab-width