unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Joseph Turner via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Michael Heerdegen <michael_heerdegen@web.de>
Cc: philipk@posteo.net, 66187@debbugs.gnu.org
Subject: bug#66187: read-file-name unexpected behavior when MUSTMATCH is a function
Date: Tue, 03 Oct 2023 14:18:42 -0700	[thread overview]
Message-ID: <87ttr7nzyj.fsf@breatheoutbreathe.in> (raw)
In-Reply-To: <87h6ngs85e.fsf@web.de>

[-- Attachment #1: Type: text/plain, Size: 4573 bytes --]


Michael Heerdegen <michael_heerdegen@web.de> writes:

> I had a look and tried this:
>
> [2. text/x-diff; 0001-WIP-Bug-66187.patch]
> From ad895d2df5c69e015c2c7eba5116ab2d440e1fbc Mon Sep 17 00:00:00 2001
> From: Michael Heerdegen <michael_heerdegen@web.de>
> Date: Wed, 27 Sep 2023 03:32:37 +0200
> Subject: [PATCH] WIP: Bug#66187
>
> ---
>  lisp/minibuffer.el | 29 +++++++++++++++--------------
>  1 file changed, 15 insertions(+), 14 deletions(-)
>
> diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
> index 2120e31775e..79a8786fbac 100644
> --- a/lisp/minibuffer.el
> +++ b/lisp/minibuffer.el
> @@ -3061,13 +3061,23 @@ completion-file-name-table
>            (funcall (or pred 'file-exists-p) string)))
>
>         (t
> -        (let* ((name (file-name-nondirectory string))
> +        (let* ((test-directory (lambda (s)
> +                                 (let ((len (length s)))
> +                                   (and (> len 0) (eq (aref s (1- len)) ?/)))))
> +               (should-complete
> +                (and pred
> +                     (if (eq pred 'file-directory-p)
> +                         test-directory
> +                       (lambda (f)
> +                         (or (funcall test-directory f)
> +                             (funcall pred f))))))
> +               (name (file-name-nondirectory string))
>                 (specdir (file-name-directory string))
>                 (realdir (or specdir default-directory)))
>
>            (cond
>             ((null action)
> -            (let ((comp (file-name-completion name realdir pred)))
> +            (let ((comp (file-name-completion name realdir should-complete)))
>                (if (stringp comp)
>                    (concat specdir comp)
>                  comp)))
> @@ -3078,18 +3088,9 @@ completion-file-name-table
>                ;; Check the predicate, if necessary.
>                (unless (memq pred '(nil file-exists-p))
>                  (let ((comp ())
> -                      (pred
> -                       (if (eq pred 'file-directory-p)
> -                           ;; Brute-force speed up for directory checking:
> -                           ;; Discard strings which don't end in a slash.
> -                           (lambda (s)
> -                             (let ((len (length s)))
> -                               (and (> len 0) (eq (aref s (1- len)) ?/))))
> -                         ;; Must do it the hard (and slow) way.
> -                         pred)))
> -                  (let ((default-directory (expand-file-name realdir)))
> -                    (dolist (tem all)
> -                      (if (funcall pred tem) (push tem comp))))
> +                      (default-directory (expand-file-name realdir)))
> +                  (dolist (tem all)
> +                    (if (funcall should-complete tem) (push tem comp)))
>                    (setq all (nreverse comp))))
>
>                all))))))

> I thought this would make Emacs complete as you want.  But: what files
> should be shown when hitting TAB?  I decided to show only matching
> files, plus all directories (seems logical, since these may contain
> matching files).

> But that gives a bad user experience: When I tried this I thought it
> would not work because completion did not accept an existing empty
> directory.  Then I saw that it actually was not empty.  But it contained only
> plain files, no subdirectories, and TAB displayed nothing.  Quite confusing!

I dug a little more and realized that the IMO unexpected behavior
resides in completing-read itself.  According to the completing-read
docstring, its REQUIRE-MATCH argument can be

- 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.

I incorrectly assumed that this function would prevent matching items
inside COLLECTION for which the function returns nil.  What it actually
does it accept input which is not part of COLLECTION if the
REQUIRE-MATCH function returns non-nil.  IOW, it doesn't narrow the
potential completion options; it widens them.

For example, given:

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

I expected that the prompt would refuse to complete "b". I was wrong.

Since completing-read is such a fundamental part of Emacs, I doubt it
will be possible to change this behavior.  What do you think about the
attached patch to clarify the completing-read docstring?

Thank you!!

Joseph


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Clarify-completing-read-REQUIRE-MATCH-function-docst.patch --]
[-- Type: text/x-diff, Size: 1316 bytes --]

From 10fa6dd5c659bed2b818fb925445cab2cbbb5325 Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Tue, 3 Oct 2023 14:40:22 -0700
Subject: [PATCH] Clarify completing-read REQUIRE-MATCH function docstring

* src/minibuf.c (Fcompleting_read): Explicitly note that REQUIRE-MATCH
function does not narrow the completion candidates.
---
 src/minibuf.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/minibuf.c b/src/minibuf.c
index 58adde1bf66..616be7091ee 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1999,8 +1999,11 @@ REQUIRE-MATCH can take the following values:
   `minibuffer-complete' right before `minibuffer-complete-and-exit'
   and the input is not an element of COLLECTION.
 - 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.
+  argument.  If the function returns a non-nil value or if
+  the input is a member of COLLECTION, the minibuffer is
+  exited with that argument as the value.  If the function
+  returns nil and the input is not a member of COLLECTION,
+  then the user is not allowed to exit.
 - anything else behaves like t except that typing RET does not exit if it
   does non-null completion.
 
-- 
2.41.0


  reply	other threads:[~2023-10-03 21:18 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-24 21:31 bug#66187: read-file-name unexpected behavior when MUSTMATCH is a function Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-25  3:58 ` Michael Heerdegen
2023-09-25  5:12   ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-25 21:33     ` Michael Heerdegen
2023-09-26  8:37       ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-27  0:26         ` Michael Heerdegen
2023-09-27  0:55           ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-27  1:43             ` Michael Heerdegen
2023-10-03 21:18               ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2023-10-03 23:00                 ` Drew Adams
2023-10-04  3:35                 ` Michael Heerdegen
2023-10-04  5:22                   ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-05  1:12                     ` Michael Heerdegen
2023-10-04  7:03                 ` Eli Zaretskii
2023-10-05 19:34                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-05 20:20                     ` Drew Adams
2023-10-06  4:47                       ` Eli Zaretskii
2023-10-06 13:05                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-06 14:08                           ` Drew Adams
2023-10-06  4:45                     ` Eli Zaretskii
2023-10-06 13:01                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-06 13:46                         ` Eli Zaretskii
2023-10-06 16:43                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-07  5:23                             ` Eli Zaretskii
2023-10-07 14:25                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-07 15:09                                 ` Eli Zaretskii
2023-10-07 15:12                                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-12 21:26                                     ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-11-26  6:49                                       ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-18  0:24                                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-12-19  2:52                                         ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-09  8:06                                           ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-25 20:53                                             ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-28 19:20                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-28 19:28                                                 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-06  5:55                     ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-29 12:00             ` Eli Zaretskii
2023-10-03 20:43               ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-10-04  6:05                 ` Eli Zaretskii
2023-10-04  6:25                   ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ttr7nzyj.fsf@breatheoutbreathe.in \
    --to=bug-gnu-emacs@gnu.org \
    --cc=66187@debbugs.gnu.org \
    --cc=joseph@breatheoutbreathe.in \
    --cc=michael_heerdegen@web.de \
    --cc=philipk@posteo.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).