Subject: Re: bug#66187: read-file-name unexpected behavior when MUSTMATCH is a function

From: Joseph Turner <[email-masked]>
Date: Mon, 18 Dec 2023 21:52:33 -0500

Hello!

For reference, here's the little snippet I'm testing with:

(completing-read "Prompt: " '("a" "b") nil
                 (lambda (input)
                   (string= "a" input)))

where the only expected valid input is "a".

Stefan Monnier <[email-masked]> writes:

>> Here's another potential solution.  While the attached patch seems to
>> work, I'm not sure that minibuffer-completion-confirm should be checked
>> in completion--do-completion instead of completion--complete-and-exit.
>
> It's definitely better to check it in `completion--complete-and-exit`
> (which is about exiting and thus related to whether the content is
> acceptable) than in `completion--do-completion` (which is just about
> completion).

I'm still not sure `completion--complete-and-exit' is the best place to
check that input is valid before exiting.

`completion--do-completion' contains the following cond clause, which
prevents the user from exiting with, e.g., "c".

((null comp)
 (minibuffer-hide-completions)
 (unless completion-fail-discreetly
   (ding)
   (completion--message "No match"))
 (minibuffer--bitset nil nil nil))

Perhaps we should also run that same body when REQUIRE-MATCH is a
function which returns nil?

> The patch looks OK, thanks.  We could make it call `completion-function`
> instead of saying "no match" (after all, it has "complete" in its name),
> but it comes with its own set of problems.

If I understand correctly, the attached patch does this.

I think this works inside of `completion-complete-and-exit', but maybe
not inside of `minibuffer-force-complete-and-exit' since the former
calls `completion--do-completion' internally but the latter does not.

Still exploring ideas...  Thanks!

Joseph

>From 7b779782504a7b94f64f100a1f8bb71c483873e5 Mon Sep 17 00:00:00 2001
From: Joseph Turner <[email-masked]>
Date: Mon, 18 Dec 2023 22:41:24 -0500
Subject: [PATCH] Fix completing-read functional REQUIRE-MATCH behavior

* lisp/minibuffer.el (completion--do-completion):  Refuse to exit
minibuffer when REQUIRE-MATCH is a function which returns nil.
(completion--complete-and-exit): Delegate handling of functional
REQUIRE-MATCH to completion-function.

See bug#66187.
---
 lisp/minibuffer.el | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 5c12d9fc914..5d26ff2423e 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1408,7 +1408,11 @@ when the buffer's text is already an exact match."
                         (- (point) beg)
                         md)))
     (cond
-     ((null comp)
+     ((or (null comp)
+          (and (eq t comp)
+               (functionp minibuffer-completion-confirm)
+               (not (funcall minibuffer-completion-confirm
+                             (buffer-substring beg end)))))
       (minibuffer-hide-completions)
       (unless completion-fail-discreetly
 	(ding)
@@ -1849,10 +1853,8 @@ 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)
+    (funcall completion-function))
    ;; See if we have a completion from the table.
    ((test-completion (buffer-substring beg end)
                      minibuffer-completion-table
-- 
2.41.0