Rich Comments Support#
Why bother with Rich comments? Read on. Consider watching this Youtube video for a demo of the workflow using the (in?)famous FizzBuzz problem as an example.
Things in comment
are not evaluated#
The Clojure comment
macro is defined like so:
(defmacro comment
"Ignores body, yields nil"
{:added "1.0"}
[& body])
It has no forms in its body and will therefore always (as long as the Clojure Reader can read it) evaluate to nil
. That is: nothing in the (comment ...)
form will get evaluated when the file is loaded.
This makes it a very good ”place” where you can develop code, experiment with code, and keep example code. Since you will be able to load/evaluate the current file without worrying that the code in the comment
form will get evaluated. This also holds true when using tools that hot-reload the code on save, such as Figwheel, shadow-cljs and Krell.
To develop or refine a function you might:
- Open up a
(comment ...)
form - Inside this form, type a first, super simple, version (or refinement) of your function and evaluate it
- Inside the same
comment
form, type some code to test your function and evaluate that- Or type and evaluate some code you might need for your function
- Repeat from 2., until the function does what you want it to do
- Move the function definition out of the
comment
form - Clean up the
comment
form to keep some of the test code as example use, or ”design decision log” for the function.
Note
Using (comment ...)
forms for developing code is very common among Clojure coders. Rich Hickey is known for using it, which is why they are called Rich comments to begin with (even if it also is a very rich experience).
Calva encourages Rich comments#
Calva has several features to facilitate the Rich comments workflow, e.g.
- A command that helps you create a new Rich comment form quickly: Calva: Add Rich Comment, ctrl+alt+r c
- A snippet for creating Rich comment form quickly. Typing
(rcf
, will make it appear. - Special Syntax highlight. By default
comment
forms are rendered in italics - Special top-level form context
- Special formatting
Note that the command and snippet for creating Rich comments add the keyword :rcf
right before the closing paren. This makes the closing paren stay and not fold when you format the code. The special formatting (see below) will treat this and also any ignored (with #_
) form at the end of the form specially.
comment
is top-level#
To make it easy to evaluate forms in (comment ...)
forms, they create a new top-level context. Instead of you having to place the cursor with precision before evaluating the current form, you can have the cursor anywhere within a comment
enclosed form and Evaluate Top-Level Form.
This carries over to all commands in Calva which deal with the top level form. Including custom command snippets.
Special formatting#
To invite a Rich comments workflow, the Calva command Format Current Form will not fold the closing bracket of the (comment ...)
form. Instead it will place this bracket on a line of its own (or keep it there).
(comment
)
With the cursor somewhere directly inside the comment form (denoted with a |
):
(comment
(def foo
:foo)|)
tab
(comment
(def foo
:foo)
|)
!!! Note "Only for the current comment form”
The special formatting only applies in the current comment
form. When outside it, formatting tucks the closing paren in again. That's why fold when done, below works like it does. This also applies to VS Code commands like Format Document, or when you have Format On Save enabled. There are several reasons for this, and one is that there is no cljfmt
config for it and leaving the closing comment un-tucked might give you troubles with CI pipelines that enforce some cljfmt config be followed. (Another reason is that it would be pretty hard to do on the whole document.)
Special formatting disabled for trailing :rcf
#
If the Rich comment ends with :rcf
(or an ignored form), the special formatting doesn't happen. So if you have:
(comment
(def foo
:foo)
|
:rcf)
And hit tab, you will get:
(comment
(def foo
:foo)
|
:rcf)
Thinking space is kept#
The formatter will not remove newlines between the cursor and the closing bracket. So if you have entered a few lines to get ”thinking” room:
(comment
(def foo
:foo)
|
)
tab
(comment
(def foo
:foo)
|
)
Fold when done#
To fold the trailing paren automatically, place the cursor immediately outside (before or after) the form:
(comment
(def foo
:foo))|
tab
(comment
(def foo
:foo))|
Enabled by default#
You can disable this behavior with the setting: calva.fmt.keepCommentTrailParenOnOwnLine
.
Only for the Current Form#
Note
This treatment only applies to formatting of the current form. With fold when done as an exception.