]> git.eshelyaron.com Git - emacs.git/commitdiff
Support narrowing (restricting) minibuffer completions
authorEshel Yaron <me@eshelyaron.com>
Thu, 21 Dec 2023 19:43:59 +0000 (20:43 +0100)
committerEshel Yaron <me@eshelyaron.com>
Fri, 19 Jan 2024 10:05:42 +0000 (11:05 +0100)
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.

doc/emacs/emacs.texi
doc/emacs/help.texi
doc/emacs/mini.texi
doc/lispref/minibuf.texi
etc/NEWS
lisp/help-fns.el
lisp/menu-bar.el
lisp/minibuffer.el
lisp/simple.el

index 7d77f13ab2171b209ce830e2bbb9a489dc1f9f22..b9be2de49fd5509e2d66606a59cc29b213cefa74 100644 (file)
@@ -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
index 99a4173ac2918cec2d8e860d158916cf1a30a49f..5bed5d6f037b9e9221cc57772ae8e24064825286 100644 (file)
@@ -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
index aa7144610a68df3f1cc17f1e23f885de602c27d8..19371b7c897bb4f13550691dd668358fbe96c672 100644 (file)
@@ -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
index aa27de72ba0ef5d3e566966a6723c4a419280368..471ec848b142b683019097938744b47767478a61 100644 (file)
@@ -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
index 735a05f65796171bd63bfad53df8a5b3992cb563..a07b54e02fd34ce9a1e29c8334dfa4f137101710 100644 (file)
--- 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
 
 ---
index 99642d08bbd230ad62309f1b8e6ead466cdb7cf1..c60c057b911538b4ed1aed83755875b4971ecb7a 100644 (file)
@@ -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)))
index 477e3036b47b86990d161e0836532ed6f45898c5..1d8efd2899626c2922a24d6a69fbb72d4c85e27e 100644 (file)
@@ -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"))
index 45aab3980783594840c59e838d8005a499dd9d23..af61694e923d3dac5f12c1fe629fcf59f0d1b510 100644 (file)
@@ -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-<up>"    #'minibuffer-previous-completion
   "M-<down>"  #'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,
index 692c0dacefc9159e6a053bb5fe14894750bbc4b4..48b617b17c1aa5d7b6ed51c953ed9122296129a6 100644 (file)
@@ -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