Overview

An indent spec can be used to specify intricate indentation rules for the more complex macros (or functions). It is provided as a value in the var metadata, under the :style/indent key.

(defmacro with-in-str
  "[DOCSTRING]"
  {:style/indent 1}
  [s & body]
  ...cut for brevity...)

It can take one of 3 forms:


Examples

Here we go into several examples using some well-known macros and forms from clojure.core. Obviously these are already known by clojure-mode, so you don't need to specify them. They are just examples to guide you when writing indent specs for your own macros, or for macros from third party libs.

One very simple example is the do form. All of its arguments get the same indentation, and none of them are special. So its indent spec is simply [0], or 0 for short.

(do
  (something)
  (quick))

(do (whatever)
    (you)
    (want))

Sticking to simplicity, the when-let* macro has one special argument (the binding vector) and there's no out-of-the-ordinary internal structure involved. So the indent spec is just 1 (which is shorthand for [1]).


Let's see something more sophisticated. If the defrecord indent spec used by clojure-mode is [2 :form :form [1]]. This is saying:

(defrecord Thing [a]
  FileNameMap
  (getContentTypeFor [_ file-name]
    (str a "-" file-name))
  Object
  (toString [_]
    "My very own thing!!"))

For something even more complicated: letfn is [1 [[:defn]] :form]. This means

(letfn [(twice [x]
          (* x 2))
        (six-times [y]
          (* (twice y) 3))]
  (six-times 15))

Special Arguments

Many macros have a number of “special” arguments, followed by an arbitrary number of “non-special” arguments (sometimes called the body). The “non-special” arguments have a small indentation (usually 2 spaces). The special arguments are usually on the same line as the macro name, but, when necessary, they are placed on a separate line with additional indentation.

For instance, defrecord has two special arguments, and here's how it might be indented:

(defrecord TheNameOfTheRecord
    [a pretty long argument list]
  SomeType
  (assoc [_ x]
    (.assoc pretty x 10)))

Here's another way one could do it:

(defrecord TheNameOfTheRecord
           [a pretty long argument list]
  SomeType
  (assoc [_ x]
    (.assoc pretty x 10)))

The point of the indent spec is not to specify how many spaces to use.

The point is just to say “a defrecord has 2 special arguments”, and then let the editor and the user come to an agreement on how many spaces they like to use for special and non-special arguments.

Internal indentation

The issue goes a bit deeper. Note the last argument in that defrecord. A regular function form would be internally indented as:

(assoc [_ x]
       (.assoc pretty x 10))

But this is not a regular function call, it's a definition. So we want to specify that this form internally has 1 special argument (the arglist vector), so that it will be indented like this:

(assoc [_ x]
  (.assoc pretty x 10))

The indent spec does this as well. It lets you specify that, for each argument beyond the 2nd, if it is a form, it should be internally indented as having 1 special argument.