Skip to content

Commit b58a332

Browse files
committed
Add a section on project-specific configuration to the manual
1 parent 81bbe28 commit b58a332

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

doc/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
** xref:config/indentation.adoc[Indentation]
2828
** xref:config/eldoc.adoc[Eldoc]
2929
** xref:config/misc.adoc[Misc]
30+
** xref:config/project_config.adoc[Project-specific Configuration]
3031
* xref:indent_spec.adoc[Indentation Specification]
3132
* Using the REPL
3233
** xref:repl/basic_usage.adoc[Basic Usage]
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
= Project-specific Configuration
2+
:experimental:
3+
4+
A pretty common question about CIDER is how to handle project-specific configuration.
5+
There are many reasons for wanting to do something like this, but probably the first
6+
that comes to mind is running Leiningen with some specific profile or adding "-A:fig"
7+
to the jack-in command when using the Clojure CLI (a.k.a. `tools.deps`).
8+
9+
TIP: If you simply need to edit a jack-in command on the fly you're probably better off
10+
prefixing the command with kbd:[C-u] (e.g. kbd:[C-u C-c C-x j j]), which will
11+
allow you to edit the entire command string in the minibuffer.
12+
13+
CIDER doesn't have any special provisions for project-specific configuration, as this
14+
is something well supported in Emacs itself. Unfortunately the functionality in Emacs has the
15+
slight weird name "dir-local variables", which is probably not the thing people would
16+
start googling for. On the bright side - the Emacs functionality is much more generic
17+
than dealing with project-specific configuration.
18+
19+
Very simply put, all you need to do is to create in the root of your project a file named
20+
`.dir-locals.el` which should look something like:
21+
22+
[source,emacs-lisp]
23+
----
24+
((clojurescript-mode
25+
(cider-clojure-cli-global-options . "-A:fig")
26+
(eval . (cider-register-cljs-repl-type 'super-cljs "(do (foo) (bar))"))
27+
(cider-default-cljs-repl . super-cljs)))
28+
----
29+
30+
The structure of the file is a mapping of major modes and some variables
31+
that need to be set in them. As CIDER is not a major mode most of the time you'll
32+
probably be setting variables in `clojure-mode` or `clojurescript-mode`. Note that
33+
`clojurescript-mode` derives from `clojure-mode`, so whatever applies to `clojure-mode`
34+
will apply to `clojurescript-mode` as well. You can also evaluate code by using
35+
`eval` as the variable name in the variable to value mapping, but that's something
36+
you'll rarely need in practice.
37+
38+
Normally, you'd simply create the `.dir-locals.el` manually and edit it like any other
39+
Emacs Lisp code. If you, however, feel
40+
overwhelmed by its syntax you can simply do `M-x add-dir-local-variable` and
41+
you'll be able to select the major-mode, the variable and its value
42+
interactively. One small problem with this approach is that the resulting
43+
`.dir-local.el` will be created in the current directory, which may be a problem
44+
depending on what you're trying to do. Users of
45+
https://github.com/bbatsov/projectile[Projectile] may leverage the
46+
project-aware `projectile-edit-dir-locals` command instead.
47+
48+
Here's one slightly more complex `.dir-locals.el`:
49+
50+
[source,emacs-lisp]
51+
----
52+
((emacs-lisp-mode
53+
(bug-reference-url-format . "https://github.com/clojure-emacs/cider/issues/%s")
54+
(bug-reference-bug-regexp . "#\\(?2:[[:digit:]]+\\)")
55+
(indent-tabs-mode . nil)
56+
(fill-column . 80)
57+
(sentence-end-double-space . t)
58+
(emacs-lisp-docstring-fill-column . 75)
59+
(checkdoc-symbol-words . ("top-level" "major-mode" "macroexpand-all" "print-level" "print-length"))
60+
(checkdoc-package-keywords-flag)
61+
(checkdoc-arguments-in-order-flag)
62+
(checkdoc-verb-check-experimental-flag)
63+
(elisp-lint-indent-specs . ((if-let* . 2)
64+
(when-let* . 1)
65+
(let* . defun)
66+
(nrepl-dbind-response . 2)
67+
(cider-save-marker . 1)
68+
(cider-propertize-region . 1)
69+
(cider-map-repls . 1)
70+
(cider--jack-in . 1)
71+
(cider--make-result-overlay . 1)
72+
;; need better solution for indenting cl-flet bindings
73+
(insert-label . defun) ;; cl-flet
74+
(insert-align-label . defun) ;; cl-flet
75+
(insert-rect . defun) ;; cl-flet
76+
(cl-defun . 2)
77+
(with-parsed-tramp-file-name . 2)
78+
(thread-first . 1)
79+
(thread-last . 1)))))
80+
----
81+
82+
Did you manage to guess what it is? That's CIDER's own `.dir-locals.el`, which
83+
ensures that all people hacking on the Elisp codebase are going to be using some
84+
common code style settings. That's why everything's scoped to `emacs-lisp-mode`.
85+
86+
For a Clojure-centric example let's take a look at ``cider-nrepl``'s `.dir-locals.el`:
87+
88+
[source,emacs-lisp]
89+
----
90+
((clojure-mode
91+
(clojure-indent-style . :always-align)
92+
(indent-tabs-mode . nil)
93+
(fill-column . 80)))
94+
----
95+
96+
Here the point is to ensure everyone working on the Clojure codebase using Emacs would
97+
be sharing the same code style settings.
98+
99+
Often in the wild you'll see dir-local entries with `nil` as the major mode there.
100+
This odd looking notation simply means that the configuration specified there will
101+
be applied to every buffer regardless of its major mode. Use this approach sparingly, as there's
102+
rarely a good reason to do this.
103+
104+
Another thing to keep in mind is that you can have multiple `.dir-locals.el` files in your project.
105+
Their overall effect will be cumulative with the innermost file taking precedence for any files
106+
in the directories beneath it. I've never needed this in practice, but I can imagine it being
107+
useful for people who have multiple projects in a mono repo, or people who apply different conventions
108+
to "real" code and its tests.
109+
110+
You might be wondering when do changes to `.dir-locals.el` get reflected in the Emacs buffers
111+
affected by them. The answer is to this question is "when the buffers get created". If you change
112+
something in `.dir-locals.el` you'll normally have to re-create the related buffers.
113+
Or you can do in the hacker way and apply https://emacs.stackexchange.com/questions/13080/reloading-directory-local-variables[a bit of Elisp magic].
114+
115+
TIP: There are more aspects to dir-locals, but they are beyond the scope of this article.
116+
If you're curious for all the gory details you should check out https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html[the official Emacs documentation on dir-locals].

0 commit comments

Comments
 (0)