Skip to content

Commit 073d721

Browse files
committed
Include intermediate directories in projectile-find-dir (#1596)
projectile-project-dirs previously only returned directories that directly contain files, missing intermediate directories that contain only subdirectories (e.g. src/ when it only has src/ComponentA/). Fix by walking each file path's ancestor directories up to the project root, so all intermediate directories are included.
1 parent 7a3708f commit 073d721

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
* [#1748](https://github.com/bbatsov/projectile/issues/1748): Fix `projectile-replace` falling back to the legacy Emacs 25/26 code path on Emacs 27+ because `fileloop` was not loaded.
1212
* [#1741](https://github.com/bbatsov/projectile/issues/1741): Fix `projectile-replace` treating the search string as a regexp instead of a literal string on Emacs 27+.
13+
* [#1596](https://github.com/bbatsov/projectile/issues/1596): `projectile-find-dir` now includes intermediate directories that contain only subdirectories (e.g. `src/` when it only has `src/ComponentA/`, `src/ComponentB/`).
1314
* [#1551](https://github.com/bbatsov/projectile/issues/1551): Don't add nonexistent files to the project cache (e.g. when visiting a new file with `find-file` and then abandoning the buffer).
1415
* [#1554](https://github.com/bbatsov/projectile/issues/1554): Fix `projectile-files-with-string` failing on special characters when using `grep` or `git-grep` by adding the `-F` (fixed-string) flag.
1516
* [#1897](https://github.com/bbatsov/projectile/issues/1897): Filter deleted-but-unstaged files from `git ls-files` output in alien/hybrid indexing (when `fd` is not used).

projectile.el

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,8 +2281,19 @@ project-root for every file."
22812281
"Return a list of dirs for PROJECT."
22822282
(delete-dups
22832283
(delq nil
2284-
(mapcar #'file-name-directory
2285-
(projectile-project-files project)))))
2284+
(cl-mapcan #'projectile--directory-ancestors
2285+
(projectile-project-files project)))))
2286+
2287+
(defun projectile--directory-ancestors (path)
2288+
"Return a list of the directory of PATH and all its ancestor directories.
2289+
For example, \"src/foo/bar.el\" returns (\"src/foo/\" \"src/\")."
2290+
(let ((dir (file-name-directory path))
2291+
result)
2292+
(while (and dir (not (equal dir "")))
2293+
(push dir result)
2294+
(let ((parent (file-name-directory (directory-file-name dir))))
2295+
(setq dir (unless (equal parent dir) parent))))
2296+
result))
22862297

22872298
(defun projectile-current-project-dirs ()
22882299
"Return a list of dirs for the current project."

test/projectile-test.el

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,20 @@ Just delegates OPERATION and ARGS for all operations except for`shell-command`'.
554554
(expect files :to-contain "existing.txt")
555555
(expect files :not :to-contain "deleted.txt")))))))
556556

557+
(describe "projectile-project-dirs"
558+
(it "includes intermediate directories that contain only subdirectories"
559+
(spy-on 'projectile-project-files
560+
:and-return-value '("src/ComponentA/a.cc"
561+
"src/ComponentB/b.cc"
562+
"config/config_file"))
563+
(let ((dirs (projectile-project-dirs "/project/")))
564+
;; Leaf directories
565+
(expect dirs :to-contain "src/ComponentA/")
566+
(expect dirs :to-contain "src/ComponentB/")
567+
(expect dirs :to-contain "config/")
568+
;; Intermediate directory (only has subdirectories, no direct files)
569+
(expect dirs :to-contain "src/"))))
570+
557571
(describe "projectile-index-directory"
558572
(it "skips unreadable directories"
559573
(unless (eq system-type 'windows-nt)

0 commit comments

Comments
 (0)