My knee-jerk reaction is:
 - +10
 - leaving it up to the user is absolutely the right thing to do
 - the name ‘indent’ and what it is actually capturing are at different levels 
of abstraction. Possibly ‘structure’ might be a better name as that is what it 
is describing?

But don’t listen to a word I say - I am hacking through some of my old code 
which uses :admission-date and :start-date interchangeably *for the same data 
structure* - sigh.

My 1.5 cents.

> On 13 Sep 2015, at 11:06 AM, Artur Malabarba <arturmalaba...@gmail.com> wrote:
> 
> Hi everyone,
> 
> 
> 
> Over at CIDER we're adding a feature where the author of a macro (or 
> function) can specify how that macro should be indented by adding an :indent 
> metadata to its definition. This way the editor (and other tools, like 
> cljfmt) will know what's the proper way of indenting any macro (even those 
> custom-defined) without having to hardcode a bajillion names.
> 
> Here's an example of how you specify the indent spec for your macros
> 
> 
> 
> (defmacro with-out-str
>   "[DOCSTRING]"
>   {:indent 0}
>   [& body]
>   ...cut for brevity...)
> 
> (defmacro defrecord
>   "[DOCSTRING]"
>   {:indent [2 nil nil [1]]}
>   [name fields & opts+specs]
>   ...cut for brevity)
> 
> (defmacro with-in-str
>   "[DOCSTRING]"
>   {:indent 1}
>   [s & body]
>   ...cut for brevity...)
> 
> 
> We'd like to hear any opinions on the practicality of this (specially from 
> authors of other editors). 
> Below, I'll be saying “macros” all the time, but this applies just the same 
> to functions.
> 
> 
> 
> 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). These 
> 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 call 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 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 we're working on 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 if it had 1 special argument.
> 
> 
> 
> The spec
> 
> 
> 
> An indent spec can be:
> 
> nil (or absent), meaning “indent like a regular function call”.
> A vector (or list) meaning that this function/macro takes a number of special 
> arguments, and then all other arguments are non-special.
> The first element of this vector is an integer indicating how many special 
> arguments this function/macro takes.
> Each following element is an indent spec on its own, and it applies to the 
> argument on the same position as this element. So, when that argument is a 
> form, this element specifies how to indent that form internally (if it's not 
> a form the spec is irrelevant).
> If the function/macro has more aguments than the vector has elements, the 
> last element of the vector applies to all remaining arguments.
> If the whole spec is just an integer n, that is shorthand for [n].
> 
> 
> Examples
> 
> 
> 
> So, for instance, if I specify the defrecord spec as [2 nil nil [1]], this is 
> saying:
> 
> defrecord has 2 special arguments
> The first two arguments don't get special internal indentation
> All remaining arguments have an internal indent spec of [1] (which means only 
> the arglist is indented specially).
> Another example, reify is [1 nil [1]] (which should be easy to see now).
> 
> 
> (reify Object 
>   (toString [this]
>     (something)
>     else
>     "here"))
> 
> 
> 
> For something more complicated: letfn is [1 [[1]] nil]. This means
> 
> letfn has one special argument (the bindings list).
> The first arg has an indent spec of [[1]], which means all forms inside the 
> first arg have an indent spec of [1].
> The second argument, and all other arguments, are regular forms.
> 
> (letfn [(twice [x]
>           (* x 2))
>         (six-times [y]
>           (* (twice y) 3))]
>   (println "Twice 15 =" (twice 15))
>   (println "Six times 15 =" 
>            (six-times 15)))
> 
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en 
> <http://groups.google.com/group/clojure?hl=en>
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clojure+unsubscr...@googlegroups.com 
> <mailto:clojure+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to