Overriding project.el project root in Emacs
I've recently been experimenting with replacing
Projectile with the built-in
so far it has impressed me. Not only are all of Projectile's useful features available, but for
runs significantly faster in large repositories. If you're not familiar, both of these packages
provide functions to search and operate on files and directories in the same project. If you're
using Git, a "project" is probably synonymous with a repository.
Unfortunately, project detection is not always as easy as looking for a
.git/ nearby, and sometimes Emacs gets it wrong. Projectile solves this by also
looking for a
.projectile file, which overrides detection and says "this is the
project root". This happens to be one of the features missing in
Luckily, we can provide our own function to
project.el which looks for a file like
this in the current and parent directories. Even better, the excellent Emacs community has
already jumped on this, and a splendid solution was
provided by Michael Stapelberg.
Alas, Michael couldn't have forseen that Emacs would change the project root data format in
Emacs 29, so the provided function only works in earlier versions. However, adding in forward
compatibility isn't much trouble. And while we're at it, we can also provide support for anyone
else moving from Projectile like I am, by allowing
.projectile to serve as a
project root marker alongside Michael's
(defun project-root-override (dir) "Find DIR's project root by searching for a '.project.el' file. If this file exists, it marks the project root. For convenient compatibility with Projectile, '.projectile' is also considered a project root marker. https://blog.jmthornton.net/p/emacs-project-override" (let ((root (or (locate-dominating-file dir ".project.el") (locate-dominating-file dir ".projectile"))) (backend (ignore-errors (vc-responsible-backend dir)))) (when root (if (version<= emacs-version "28") (cons 'vc root) (list 'vc backend root))))) ;; Note that we cannot use :hook here because `project-find-functions' doesn't ;; end in "-hook", and we can't use this in :init because it won't be defined ;; yet. (use-package project :config (add-hook 'project-find-functions #'project-root-override))
Now we can use
touch .project.el in any directory, and
recognize it as the project root!
By the way, the snippet above makes use of use-package which provides fantastic package configuration and loading ability. John Wiegley is currently working on adding it into Emacs itself, so it shouldn't be long before this code snippet is fully native!
One note, in an ideal world, I'd prefer the root marker to be just
.project.el, but this is already widely used by other tools like Eclipse and I'd
rather not cause conflicts. If you'd like to use this in your own Emacs, obviously you can
change the function to check for anything you want.