This gist is for anyone who's trying to use emacs + eglot + monorepo (with Clojure or any other language).
When you open a file in a buffer, eglot needs to determine the scope or folder to run the language server in.
By default, the folder eglot will pick as the assumed project root is the repo root (the ancestory directory containing .git
).
But in a monorepo, that's rarely what you want.
In a large repo, analyzing all the *.clj
files with clojure-lsp could take a minute or longer.
As a limiting case, imagine Google with its gargantuan monorepo. Analyzing all the source files would
take an indefinite period of time.
So we need to scope eglot (and clojure-lsp) to a subfolder of the monorepo (e.g. /projects/foo
).
Eglot is built on top of project.el, a sort
of built-in replacement for projectile,
and uses its (project-current)
function to determine the project root.
(You can run M-x eval-expression
(project-current)
to see which folder it picks.)
Sadly project.el doesn't have an easy, built-in way to define what your repo root is (a strange omission for a project management tool.)
However, you can customize the behavior with elisp:
(require 'cl-extra)
(setq project-sentinels '("bb.edn" "deps.edn" "package.json" ".monorepo-project"))
(defun find-enclosing-project (dir)
(locate-dominating-file
dir
(lambda (file)
(and (file-directory-p file)
(cl-some (lambda (sentinel)
(file-exists-p (expand-file-name sentinel file)))
project-sentinels)))))
(add-hook 'project-find-functions
#'(lambda (d)
(let ((dir (find-enclosing-project d)))
(if dir (cons 'vc dir) nil))))
What this does is to instruct project.el (and thus, eglot) to pick the folder with a "dominating file" (in Emacs lingo a sentinel
file found in the a file's parent directory, or its parent directory, or its parent directory etc) called deps.edn
(or package.json
etc) as the project root.
In Clojure, looking for deps.edn
as a sentinel is not a bad assumption. Make sure to adapt the project-sentinels
list
to your own project.
h/t https://michael.stapelberg.ch/posts/2021-04-02-emacs-project-override/
This can now be done more easily with the
project-vc-extra-root-markers
variable