It's probably obvious, but let me say it just in case it isn't - I'm super supportive of Artur's idea. I've been thinking about something similar for a while and I believe deciding on something that's going to be used by many Clojure tools (CIDER, Cursive, fireplace, ccw, cljfmt, etc) will be hugely beneficial for everyone. As for the spec itself - I'd only suggest using some keyword instead of `nil`, as it would probably be more intention revealing.
I have no preference about the name of the metadata key itself. On 13 September 2015 at 13:15, 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.