]> 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>
Fri, 19 Jan 2024 10:07:05 +0000 (11:07 +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 b565d4f095bdc6a8f2f021c1573b0d79429dce92..0c0365ca74c83b7606938e19d05888a941fb2fd4 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 2722656c418f525c6c51db66e243be0f6142de40..c288e42120647e09afda9ae4d48d06bf48363f9f 100644 (file)
@@ -3431,11 +3431,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))
@@ -3448,26 +3443,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.
 
@@ -3643,9 +3629,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 196c5f159cd2199b2d2ebdd24a7445daa3189ded..c6669c8d1db3384311391f152b4d08fcecebe8a0 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))))
          ;; `completion-file-name-table' calls `file-exists-p' when
          ;; the predicate is nil.