I also love this idea - the more info we give to tools to provide a uniform
formatting, the less I have to worry about configuring my local editor to
match the project styles.

On Sun, Sep 13, 2015 at 3:15 AM, Colin Yates <colin.ya...@gmail.com> wrote:

> 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
> ---
> 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.
>
>
> --
> 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.
>

-- 
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