Subject: Re: bug#78926: 30.1; find-file-read-only require-match inconsistency

From: Thierry Volpiatto <[email-masked]>
Date: Tue, 01 Jul 2025 15:13:48 +0000

I modified `completion--complete-and-exit` so that the REQUIRE-MATCH
argument used with a function as value allows this function to exit with
'confirm in addition of nil/non-nil.

I then modified find-file-read-only so that it takes advantage of this:
- If you enter a wilcard you are now asked for confirm.
- If you enter a non existing filename you can't exit ([nomatch].

Note:
Of course the current behavior of find-file-read-only is fine, maybe a
little confusing but it's ok, this patch is just a proof of concept for
REQUIRE-MATCH used as a function with this new behavior.

The patches need to be reworked, didn't fully test the non interactive
usage and nothing is documented, particularly REQUIRE-MATCH in
completing-read, need also you commentaries because I guess not all the
corner cases are completed.

Thanks.

-- 
Thierry
>From efcf6cd7280910b8aaa486af75bec293cd234d21 Mon Sep 17 00:00:00 2001
From: Thierry Volpiatto <[email-masked]>
Date: Tue, 1 Jul 2025 16:48:56 +0200
Subject: [PATCH 1/2] Allow require-match as a function to return 'confirm

---
 lisp/minibuffer.el | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 122459be062..6861c099bb7 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2007,12 +2007,17 @@ appear to be a match."
    ((= beg end) (funcall exit-function))
    ;; The CONFIRM argument is a predicate.
    ((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"))))
+    (pcase (funcall minibuffer-completion-confirm
+                    (buffer-substring beg end))
+      ('confirm
+       (setq minibuffer-completion-confirm 'confirm)
+       (completion--complete-and-exit
+        beg end exit-function completion-function))
+      ((pred (eq nil))
+       (unless completion-fail-discreetly
+	 (ding)
+	 (completion--message "No match")))
+      (_ (funcall exit-function))))
    ;; See if we have a completion from the table.
    ((test-completion (buffer-substring beg end)
                      minibuffer-completion-table
-- 
2.34.1

>From dad76851b4124b0b7aec2e8576e4527bf06acc65 Mon Sep 17 00:00:00 2001
From: Thierry Volpiatto <[email-masked]>
Date: Tue, 1 Jul 2025 16:51:31 +0200
Subject: [PATCH 2/2] Make find-file-read-only ask for confirmation or

prevent exiting when file doesn't exists.
---
 lisp/files.el | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/lisp/files.el b/lisp/files.el
index 04a212b9bca..8aa426ad073 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2072,23 +2072,29 @@ file names with wildcards."
      (current-buffer)))
 
 (defun find-file--read-only (fun filename wildcards)
-  (unless (or (and wildcards find-file-wildcards
-		   (not (file-name-quoted-p filename))
-		   (string-match "[[*?]" filename))
-	      (file-exists-p filename))
-    (error "%s does not exist" filename))
+  ;; On interactive calls WILDCARDS is always non nil.
+  (let ((find-file-wildcards (and wildcards find-file-wildcards)))
+    (unless (find-file--read-only-require-match filename)
+      (error "%s does not exist" filename)))
   (let ((value (funcall fun filename wildcards)))
     (mapc (lambda (b) (with-current-buffer b (read-only-mode 1)))
 	  (if (listp value) value (list value)))
     value))
 
+(defun find-file--read-only-require-match (input)
+  (cond  ((and find-file-wildcards
+               (not (file-name-quoted-p input))
+	       (string-match "[[*?]" input))
+          'confirm)
+         (t (file-exists-p input))))
+
 (defun find-file-read-only (filename &optional wildcards)
   "Edit file FILENAME but don't allow changes.
 Like \\[find-file], but marks buffer as read-only.
 Use \\[read-only-mode] to permit editing."
   (interactive
    (find-file-read-args "Find file read-only: "
-                        (confirm-nonexistent-file-or-buffer)))
+                        #'find-file--read-only-require-match))
   (find-file--read-only #'find-file filename wildcards))
 
 (defun find-file-read-only-other-window (filename &optional wildcards)
-- 
2.34.1