Skip to content

Commit e57c7cc

Browse files
committed
Move indent documentation into own file
1 parent e779ab5 commit e57c7cc

File tree

8 files changed

+349
-379
lines changed

8 files changed

+349
-379
lines changed

README.md

Lines changed: 38 additions & 379 deletions
Large diffs are not rendered by default.

docs/INDENTS.md

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# Indentation
2+
3+
When we talk about how rules affect indentation of source code, we
4+
refer to <code>(foo arg<sub>1</sub> arg<sub>2</sub>...
5+
arg<sub>n</sub>)</code> as a form, `foo` as a form symbol, and
6+
<code>arg<sub>1</sub> arg<sub>2</sub> ... arg<sub>n</sub></code> as
7+
form arguments.
8+
9+
The default indentation rules are encoded
10+
[here](cljfmt/resources/cljfmt/).
11+
12+
Rules affect indentation of form arguments. A form argument is
13+
eligible for indentation only when it is the first element on a line.
14+
15+
An indentation rule specifies an indentation type and indentation type
16+
arguments. One or more rules can be applied to a form symbol.
17+
18+
Indentation types are:
19+
20+
* `:inner` -
21+
two character indentation applied to form arguments at a depth
22+
relative to a form symbol
23+
24+
* `:block` -
25+
first argument aligned indentation applied to form arguments at form
26+
depth 0 for a symbol
27+
28+
## Form depth
29+
30+
A rule for depth n affects indentation of form arguments relative to
31+
form symbol at depth n.
32+
33+
Form depth is the nested depth of any element within the form.
34+
35+
A contrived example will help to explain depth:
36+
37+
```clojure
38+
(foo
39+
bar
40+
(baz
41+
(qux plugh)
42+
corge)
43+
(grault
44+
waldo
45+
(thud wubble flob)))
46+
```
47+
48+
If we look at the example code as a tree, we can visualize the effect
49+
of different form depths relative to `foo`:
50+
51+
![form depth 0 diagram](images/form-depth-0.png)
52+
![form depth 1 diagram](images/form-depth-1.png)
53+
![form depth 2 diagram](images/form-depth-2.png)
54+
55+
## Default behavior
56+
57+
In the absence of indentation rules:
58+
59+
```clojure
60+
(foo bar (foo bar
61+
baz == formats to => baz
62+
bang) bang)
63+
```
64+
65+
```clojure
66+
(foo (foo
67+
bar == formats to => bar
68+
bang) bang)
69+
```
70+
71+
## Inner rules
72+
73+
The `:inner` rule applies an indentation of two spaces to all eligible
74+
form arguments of forms at a given form depth. It has 2 rule type
75+
arguments:
76+
77+
* `form-depth` -
78+
apply inner indentation within forms at this depth
79+
80+
* `limit-to-form-index` -
81+
optionally limit indentation formatting to a single form, by default
82+
formatting is applied to all forms at `form-depth`
83+
84+
Indent rule:
85+
86+
```clojure
87+
{foo [[:inner 0]]}
88+
```
89+
90+
Will indent all arguments for symbol `foo` at depth `0` by two spaces:
91+
92+
```clojure
93+
(foo bar (foo bar
94+
baz == formats to => baz
95+
bang) bang)
96+
```
97+
98+
Indent rule:
99+
100+
```clojure
101+
{foo [[:inner 1]]}
102+
```
103+
104+
Results in `:inner` indenting form arguments at depth `1`. Form
105+
`(bang...)` is at depth `1` so its arguments are affected:
106+
107+
```clojure
108+
(foo bar (foo bar
109+
baz baz
110+
(bang == formats to => (bang
111+
quz quz
112+
qoz)) qoz))
113+
```
114+
115+
Because no rule was specified for depth 0, default indentation is
116+
applied to `bar` `baz` and `(bang...)`.
117+
118+
## Limiting inner indentation
119+
120+
Sometimes it is useful to limit `:inner` indentation to one, rather
121+
than all, forms at the specified depth. For example, we'd like `letfn`
122+
to use inner indentation only in its binding vector.
123+
124+
Let's look at `letfn` example in the absence of any indentation rules:
125+
126+
```clojure
127+
(letfn [(double [x]
128+
(* x 2))] ;; want inner indentation here
129+
(let [y (double 2)
130+
z (double 3)]
131+
(println y
132+
z))) ;; but not here
133+
```
134+
135+
Applying the rule:
136+
137+
```clojure
138+
{letfn [[:inner 2]]}
139+
```
140+
141+
Brings in the `letfn` function body to where we want it by affecting
142+
form `(double [x]...)`:
143+
144+
```clojure
145+
(letfn [(double [x]
146+
(* x 2))] ;; want inner indentation here
147+
(let [y (double 2)
148+
z (double 3)]
149+
(println y
150+
z))) ;; but not here
151+
```
152+
153+
But also affects all other forms at depth `2`. In this case,
154+
`(println...)` indentation is affected in an undesirable way. To limit
155+
formatting to `(double [x]...)`, the `0`th form at depth `2`, the
156+
`limit-to-form-index` rule type argument is added:
157+
158+
```clojure
159+
{letfn [[:inner 2 0]]}
160+
```
161+
162+
... giving us:
163+
```clojure
164+
(letfn [(double [x]
165+
(* x 2))] ;; want inner indentation here
166+
(let [y (double 2)
167+
z (double 3)]
168+
(println y
169+
z))) ;; but not here
170+
```
171+
172+
Remember that when calculating `limit-to-form-index`, all forms at the
173+
specified depth are included, even self-evaluating ones. Given:
174+
175+
```clojure
176+
(foo a b c
177+
(e f
178+
g)
179+
(h i
180+
j))
181+
```
182+
183+
To affect inner indentation within form `(e...)` only, we use a rule
184+
of:
185+
186+
```clojure
187+
{foo [[:inner 1 3]]}
188+
```
189+
190+
Which results in:
191+
192+
```clojure
193+
(foo a b c
194+
(e f
195+
g)
196+
(h i
197+
j))
198+
```
199+
200+
Because `(e...)` is the 4th (index `3`) at form depth `1`.
201+
202+
#### Block rules
203+
204+
The `:block` rule works like the `:inner` rule under some
205+
circumstances, and like a normal list form under others. It takes one
206+
argument:
207+
208+
* `line-threshold-index` -
209+
if the argument at this index starts a new line, all following lines
210+
will be indented by a constant 2 spaces. Any other lines are
211+
indented normally.
212+
213+
For example:
214+
215+
```clojure
216+
{foo [[:block 0]]}
217+
```
218+
219+
If the argument at index 0 (the first argument) does not start a new
220+
line, the form is indented as normal:
221+
222+
```clojure
223+
(foo bar (foo bar
224+
baz == formats to => baz
225+
bang) bang)
226+
```
227+
228+
If it does, the lines are indented with a constant 2 spaces:
229+
230+
```clojure
231+
(foo (foo
232+
bar == formats to => bar
233+
baz baz
234+
bang) bang)
235+
```
236+
237+
To give another example
238+
239+
```clojure
240+
{foo [[:block 1]]}
241+
```
242+
243+
This time we're looking at the argument at index 1 (the second
244+
argument). If it starts a new line, the indent is constant:
245+
246+
```clojure
247+
(foo bar (foo bar
248+
baz == formats to => baz
249+
bang) bang)
250+
```
251+
252+
But if it does not, start a new line, normal indentation rules are
253+
used instead:
254+
255+
```clojure
256+
(foo bar baz == formats to => (foo bar baz
257+
bang) bang)
258+
```
259+
260+
Any lines before the threshold are always indented normally:
261+
262+
```clojure
263+
(foo (foo
264+
bar bar
265+
baz == formats to => baz
266+
bang) bang)
267+
```
268+
269+
## Multiple rules
270+
271+
Multiple rules can be specified. Picking up from our previous `letfn`
272+
example, the rule:
273+
274+
```clojure
275+
{letfn [[:inner 2 0]]}
276+
```
277+
278+
Gave us:
279+
280+
```clojure
281+
(letfn [(double [x]
282+
(* x 2))] ;; want inner indentation here
283+
(let [y (double 2)
284+
z (double 3)]
285+
(println y
286+
z))) ;; but not here
287+
```
288+
289+
Adding a `:block` rule:
290+
291+
```clojure
292+
{letfn [[:block 1][:inner 2 0]]}
293+
```
294+
295+
Matches the [current default rule for `letfn`][default-rule] and
296+
results in indenting the `(let...` to where we want it:
297+
298+
```clojure
299+
(letfn [(double [x]
300+
(* x 2))] ;; want inner indentation here
301+
(let [y (double 2)
302+
z (double 3)]
303+
(println y
304+
z))) ;; but not here
305+
```
306+
307+
In this case, single form argument `[(double...)]` does not break the
308+
`line-arg-count-threshold` of `1` and we therefore get inner
309+
indentation for form argument `(let...)`.
310+
311+
[default-rule]: cljfmt/resources/cljfmt/indents/clojure.clj

0 commit comments

Comments
 (0)