emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 7fc3f1b0d1 2/2: Make Eshell globs ending in "/" match directories


From: Lars Ingebrigtsen
Subject: master 7fc3f1b0d1 2/2: Make Eshell globs ending in "/" match directories only
Date: Sun, 26 Jun 2022 10:53:18 -0400 (EDT)

branch: master
commit 7fc3f1b0d14ad390ca361a40ecf02eaa9f1b202a
Author: Jim Porter <jporterbugs@gmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Make Eshell globs ending in "/" match directories only
    
    * lisp/eshell/em-glob.el (eshell-glob-convert): Return whether to
    match directories only.
    (eshell-glob-entries): Add ONLY-DIRS argument.
    
    * test/lisp/eshell/em-glob-tests.el
    (em-glob-test/match-any-directory): New test.
    (em-glob-test/match-recursive)
    (em-glob-test/match-recursive-follow-symlinks): Add test cases for
    when "**/" or "***/" are the last components in a glob.
    
    * etc/NEWS: Announce this change (bug#56227).
---
 etc/NEWS                          |  6 ++++++
 lisp/eshell/em-glob.el            | 45 +++++++++++++++++++++++++++------------
 test/lisp/eshell/em-glob-tests.el | 15 +++++++++++--
 3 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 4e091e5a14..c85e8e0256 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1849,6 +1849,12 @@ values passed as a single token, such as '-oVALUE' or
 'eshell-eval-using-options' macro.  See "Defining new built-in
 commands" in the "(eshell) Built-ins" node of the Eshell manual.
 
+---
+*** Eshell globs ending with '/' now match only directories.
+Additionally, globs ending with '**/' or '***/' no longer raise an
+error, and now expand to all directories recursively (following
+symlinks in the latter case).
+
 ** Shell
 
 ---
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 8acdaee233..58b7a83c09 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -273,17 +273,23 @@ include, and the second for ones to exclude."
 
 (defun eshell-glob-convert (glob)
   "Convert an Eshell glob-pattern GLOB to regexps.
-The result is a list, where the first element is the base
-directory to search in, and the second is a list containing
-elements of the following forms:
+The result is a list of three elements:
 
-* Regexp pairs as generated by `eshell-glob-convert-1'.
+1. The base directory to search in.
 
-* `recurse', indicating that searches should recurse into
-  subdirectories.
+2. A list containing elements of the following forms:
 
-* `recurse-symlink', like `recurse', but also following symlinks."
+   * Regexp pairs as generated by `eshell-glob-convert-1'.
+
+   * `recurse', indicating that searches should recurse into
+     subdirectories.
+
+   * `recurse-symlink', like `recurse', but also following
+     symlinks.
+
+3. A boolean indicating whether to match directories only."
   (let ((globs (eshell-split-path glob))
+        (isdir (eq (aref glob (1- (length glob))) ?/))
         start-dir result last-saw-recursion)
     (if (and (cdr globs)
              (file-name-absolute-p (car globs)))
@@ -302,7 +308,8 @@ elements of the following forms:
         (setq last-saw-recursion nil))
       (setq globs (cdr globs)))
     (list (file-name-as-directory start-dir)
-          (nreverse result))))
+          (nreverse result)
+          isdir)))
 
 (defun eshell-extended-glob (glob)
   "Return a list of files matched by GLOB.
@@ -331,17 +338,21 @@ regular expressions, and these cannot support the above 
constructs."
          glob))))
 
 ;; FIXME does this really need to abuse eshell-glob-matches, message-shown?
-(defun eshell-glob-entries (path globs)
+(defun eshell-glob-entries (path globs only-dirs)
   "Match the entries in PATH against GLOBS.
 GLOBS is a list of globs as converted by `eshell-glob-convert',
-which see."
+which see.
+
+If ONLY-DIRS is non-nil, only match directories; otherwise, match
+directories and files."
   (let* ((entries (ignore-errors
                     (file-name-all-completions "" path)))
          (case-fold-search eshell-glob-case-insensitive)
          glob glob-remainder recurse-p)
     (if (rassq (car globs) eshell-glob-recursive-alist)
         (setq recurse-p (car globs)
-              glob (cadr globs)
+              glob (or (cadr globs)
+                       (eshell-glob-convert-1 "*" t))
               glob-remainder (cddr globs))
       (setq glob (car globs)
             glob-remainder (cdr globs)))
@@ -363,7 +374,13 @@ which see."
             (if glob-remainder
                 (when isdir
                   (push (concat path name) dirs))
-              (push (concat path name) eshell-glob-matches)))
+              (when (or (not only-dirs)
+                        (and isdir
+                             (not (and (eq recurse-p 'recurse)
+                                       (file-symlink-p
+                                        (directory-file-name
+                                         (concat path name)))))))
+                (push (concat path name) eshell-glob-matches))))
           (when (and recurse-p isdir
                      (not (member name '("./" "../")))
                      (setq pathname (concat path name))
@@ -372,9 +389,9 @@ which see."
                                 (directory-file-name pathname)))))
             (push pathname rdirs))))
       (dolist (dir (nreverse dirs))
-        (eshell-glob-entries dir glob-remainder))
+        (eshell-glob-entries dir glob-remainder only-dirs))
       (dolist (rdir (nreverse rdirs))
-        (eshell-glob-entries rdir globs)))))
+        (eshell-glob-entries rdir globs only-dirs)))))
 
 (provide 'em-glob)
 
diff --git a/test/lisp/eshell/em-glob-tests.el 
b/test/lisp/eshell/em-glob-tests.el
index 65f340a8da..b733be35d9 100644
--- a/test/lisp/eshell/em-glob-tests.el
+++ b/test/lisp/eshell/em-glob-tests.el
@@ -60,6 +60,12 @@ component ending in \"symlink\" is treated as a symbolic 
link."
     (should (equal (eshell-extended-glob "*.el")
                    '("a.el" "b.el")))))
 
+(ert-deftest em-glob-test/match-any-directory ()
+  "Test that \"*/\" pattern matches any directory."
+  (with-fake-files '("a.el" "b.el" "dir/a.el" "dir/sub/a.el" "symlink/")
+    (should (equal (eshell-extended-glob "*/")
+                   '("dir/" "symlink/")))))
+
 (ert-deftest em-glob-test/match-any-character ()
   "Test that \"?\" pattern matches any character."
   (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el")
@@ -71,7 +77,9 @@ component ending in \"symlink\" is treated as a symbolic 
link."
   (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el" "dir/sub/a.el"
                      "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
     (should (equal (eshell-extended-glob "**/a.el")
-                   '("a.el" "dir/a.el" "dir/sub/a.el")))))
+                   '("a.el" "dir/a.el" "dir/sub/a.el")))
+    (should (equal (eshell-extended-glob "**/")
+                   '("dir/" "dir/sub/")))))
 
 (ert-deftest em-glob-test/match-recursive-follow-symlinks ()
   "Test that \"***/\" recursively matches directories, following symlinks."
@@ -79,7 +87,10 @@ component ending in \"symlink\" is treated as a symbolic 
link."
                      "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
     (should (equal (eshell-extended-glob "***/a.el")
                    '("a.el" "dir/a.el" "dir/sub/a.el" "dir/symlink/a.el"
-                     "symlink/a.el" "symlink/sub/a.el")))))
+                     "symlink/a.el" "symlink/sub/a.el")))
+    (should (equal (eshell-extended-glob "***/")
+                   '("dir/" "dir/sub/" "dir/symlink/" "symlink/"
+                     "symlink/sub/")))))
 
 (ert-deftest em-glob-test/match-recursive-mixed ()
   "Test combination of \"**/\" and \"***/\"."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]