aboutsummaryrefslogtreecommitdiff
path: root/projectile.el
diff options
context:
space:
mode:
authorBozhidar Batsov <bozhidar@batsov.dev>2026-02-14 15:40:27 +0200
committerBozhidar Batsov <bozhidar@batsov.dev>2026-02-14 15:40:27 +0200
commit83ee3f34b630b06f3bcd58f519dea203f8925012 (patch)
treeb17132099441096592decf5e500e23abf369e9e1 /projectile.el
parent073d72120acba3de05184f747630bf7a3641a049 (diff)
Fix projectile-root-top-down to search top-down, not bottom-up (#1729)
projectile-root-top-down used projectile-locate-dominating-file which stops at the first (bottommost) match going up the directory tree. This made it behave identically to projectile-root-bottom-up. Add projectile-locate-dominating-file-top-down which walks the entire directory hierarchy and returns the topmost match. For example, with nested Makefiles at both project/ and project/subdir/, searching from project/subdir/ now correctly returns project/ instead of project/subdir/.
Diffstat (limited to 'projectile.el')
-rw-r--r--projectile.el23
1 files changed, 22 insertions, 1 deletions
diff --git a/projectile.el b/projectile.el
index 407fade..0098b2c 100644
--- a/projectile.el
+++ b/projectile.el
@@ -1312,6 +1312,27 @@ which we're looking."
(setq file nil))))
(and root (expand-file-name (file-name-as-directory root)))))
+(defun projectile-locate-dominating-file-top-down (file name)
+ "Look up the directory hierarchy from FILE for a directory containing NAME.
+Unlike `projectile-locate-dominating-file' which returns the first (bottommost)
+match, this returns the topmost match. Return nil if not found.
+Instead of a string, NAME can also be a predicate taking one argument
+\(a directory) and returning a non-nil value if that directory is the one for
+which we're looking."
+ (setq file (abbreviate-file-name file))
+ (let ((root nil)
+ try)
+ (while (not (or (null file)
+ (string-match locate-dominating-stop-dir-regexp file)))
+ (setq try (if (stringp name)
+ (projectile-file-exists-p (projectile-expand-file-name-wildcard name file))
+ (funcall name file)))
+ (when try (setq root file))
+ (if (equal file (setq file (file-name-directory
+ (directory-file-name file))))
+ (setq file nil)))
+ (and root (expand-file-name (file-name-as-directory root)))))
+
(defvar-local projectile-project-root nil
"Defines a custom Projectile project root.
This is intended to be used as a file local variable.")
@@ -1324,7 +1345,7 @@ This is intended to be used as a file local variable.")
"Identify a project root in DIR by top-down search for files in LIST.
If LIST is nil, use `projectile-project-root-files' instead.
Return the first (topmost) matched directory or nil if not found."
- (projectile-locate-dominating-file
+ (projectile-locate-dominating-file-top-down
dir
(lambda (dir)
(cl-find-if (lambda (f)