]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve handling of file name completion predicate
authorEshel Yaron <me@eshelyaron.com>
Thu, 4 Jan 2024 20:09:53 +0000 (21:09 +0100)
committerEshel Yaron <me@eshelyaron.com>
Thu, 4 Jan 2024 21:14:37 +0000 (22:14 +0100)
* lisp/minibuffer.el (completion-file-name-table): Avoid hard-coding
'file-exists-p', call predicate without directory name and set
'default-directory' to that directory instead.
(read-file-name): Update documentation.
* lisp/pcomplete.el (pcomplete--entries): Handle zero-length arg.
* doc/lispref/minibuf.texi (Reading File Names): Elaborate.

doc/lispref/minibuf.texi
lisp/minibuffer.el
lisp/pcomplete.el

index d8f3ca02a0fba85eb7bab8af6c1d544ce14432d3..2bd600fbd3c1104a1a96df75aacaede86af998c2 100644 (file)
@@ -1774,7 +1774,9 @@ current buffer visit no file using @kbd{M-x set-visited-file-name}.
 If @var{predicate} is non-@code{nil}, it specifies a function of one
 argument that decides which file names are acceptable completion
 alternatives.  A file name is an acceptable value if @var{predicate}
-returns non-@code{nil} for it.
+returns non-@code{nil} for it.  If @var{predicate} is @code{nil},
+@code{read-file-name} uses @code{file-exists-p}, so acceptable
+completions are existing file names.
 
 Here is an example of using @code{read-file-name}:
 
index 2e77d9968ec40d70b3bc1c503ab06c44a739b254..1ea69674cc8c9aa6e14e4907cfd189b2ffa4bdfb 100644 (file)
@@ -3357,11 +3357,6 @@ same as `substitute-in-file-name'."
             ;; into more such problematic cases.
             ,(min start (length string)) . ,end)))
 
-       ((eq action 'lambda)
-        (if (zerop (length string))
-            nil          ;Not sure why it's here, but it probably doesn't harm.
-          (funcall (or pred 'file-exists-p) string)))
-
        (t
         (let* ((name (file-name-nondirectory string))
                (specdir (file-name-directory string))
@@ -3374,26 +3369,17 @@ same as `substitute-in-file-name'."
                   (concat specdir comp)
                 comp)))
 
+           ((eq action 'lambda)
+            (or (not pred)
+                (let ((default-directory (expand-file-name realdir)))
+                  (funcall pred name))))
+
            ((eq action t)
             (let ((all (file-name-all-completions name realdir)))
-
-              ;; 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))))
-                  (setq all (nreverse comp))))
-
+              (when pred
+                (setq all
+                      (let ((default-directory (expand-file-name realdir)))
+                        (seq-filter pred all))))
               all))))))
     (file-error nil)))               ;PCM often calls with invalid directories.
 
@@ -3569,9 +3555,13 @@ full file name for INITIAL will usually lead to surprising
 results.
 
 Sixth arg PREDICATE, if non-nil, should be a function of one
-argument; then a file name is considered an acceptable completion
-alternative only if PREDICATE returns non-nil with the file name
-as its argument.
+argument; then a file name is considered existing (and hence an
+acceptable completion alternative) only if PREDICATE returns
+non-nil with the file name as its argument.  PREDICATE is called
+with `default-directory' bound to the direcotry part of the
+candidate file name, while the argument passed to PREDICATE does
+not include a directory part.  If PREDICATE is omitted or nil, it
+defaults to `file-exists-p'.
 
 If this command was invoked with the mouse, use a graphical file
 dialog if `use-dialog-box' is non-nil, and the window system or X
index 564006043e5458a91798956757ac1c8bbc57ae50..46ec67d5de6c31994cd63cbf3c2d103aeae0e1aa 100644 (file)
@@ -897,10 +897,11 @@ this is `comint-dynamic-complete-functions'."
             (let ((file-ignore pcomplete-file-ignore)
                   (dir-ignore pcomplete-dir-ignore))
               (lambda (file)
-                (not
-                 (if (eq (aref file (1- (length file))) ?/)
-                     (and dir-ignore (string-match dir-ignore file))
-                   (and file-ignore (string-match file-ignore file))))))))
+                (and (< 0 (length file))
+                     (not
+                      (if (eq (aref file (1- (length file))) ?/)
+                          (and dir-ignore (string-match dir-ignore file))
+                        (and file-ignore (string-match file-ignore file)))))))))
          (reg-pred (if regexp (lambda (file) (string-match regexp file))))
          (pred (cond
                 ((null (or ign-pred reg-pred))  predicate)