Let's pretend we have a macro:
POFTHEDAY> (defmacro super-let (name value &body body) `(let ((,name ,value)) ,@body)) POFTHEDAY> (super-let foo 100500 (format nil "Foo is ~A" foo)) "Foo is 100500"
But what if we want Emacs to indent it like this?
POFTHEDAY> (super-let foo 100500 (format nil "Foo is ~A" foo)) "Foo is 100500"
Then we can set indentation rule, and
trivial-indent will make it work for both SLIME and SLY:
;; This rule says: indent first two arguments ;; with 11 spaces if they are on their own line. ;; And other arguments indent like usual function's body. POFTHEDAY> (trivial-indent:define-indentation super-let (11 11 &body)) ;; And now all super-let form will be indented according to this rule. POFTHEDAY> (super-let blah 'minor (format nil "blah -> ~A" blah)) "blah -> MINOR"
I have an advice for you. If you are using
SLY, it might cache indentation rules. When you've defined a rule but don't see an effect, call
(slynk:update-indentation-information) in the REPL.
Now let's try to define a more complex indentation rule. Yesterday I wrote such macro for running Genetic Algorithm:
(def macro run-ga ((genome &key (population-size 100) (max-iterations 1000) (survive-ratio 0.5)) &body fitness-code) (let ((var-names (get-var-names genome))) (unless genome ...))) ;; After that you might run it like this: (run-ga (((x 0 10) (y -10 10) (z '(:foo :bar :bazz))) :max-iterations 100 :survive-ratio 0.2) ;; Our fitness-function (abs (- (ecase z (:foo 10) (:bar 100) (:bazz 1000)) (+ x y))))
As you can see, without special rules, these algorithm parameters are hard to distinguish from the genom definition (the first argument).
But what if we want to separate keyword arguments visually and to make this form look like this?
(run-ga (((x 0 10) (y -10 10)s (z '(:foo :bar :bazz))) :max-iterations 100 :survive-ratio 0.2) ;; Our fitness-function (abs (- (ecase z (:foo 10) (:bar 100) (:bazz 1000)) (+ x y))))
Then we might define the following rule:
POFTHEDAY> (trivial-indent:define-indentation genetic-algorithm:run-ga ((&whole &lambda &rest -4) &body))
It says, that
run-ga macro has a list-like first argument. Keyword
&whole &lambda tells that first item of this list would be indented as a regular lambda-list.
&rest -4 tells Emacs to deindent rest items of the first list.
&body keyword says to handle the rest of the macro arguments like a function's body.
There is also ability to define a custom function which will decide how to indent a form. But I didn't use this feature yet.
You can read detail about the structure of indentation rules in this Emacs docstring.