Code Evaluation
Code evaluation is at the heart of interactive programming. CIDER provides a ton of evaluation-related commands that can cover just about any use-case one can possibly imagine.
All evaluation commands are defined in cider-eval.el .
|
Terminology
CIDER’s evaluation commands use a terminology that’s popular within Emacs, but somewhat confusing to people not familiar with it. Let’s take a look at it:
-
defun
- top-level expression -
sexp
- s-expression, form -
last-sexp
- the form preceding the cursor (point
in Emacs lingo) -
sexp-at-point
- the form under/around the cursor -
buffer
- the abstraction used by Emacs to represent any content; most often backed by a file. -
region
- the selected part of a buffer -
load
- a synonym for "evaluate"; most often used in the context of buffers/files
Basic Evaluation
As CIDER derives almost all of its functionality by inspecting the runtime (REPL) state
of your application, you need to evaluate something before functionality like code completion,
eldoc
or definition lookup would work.
Typically the first think you’d do when visiting a Clojure buffer would be to load (evaluate) the buffer with cider-load-buffer
(C-c C-k).
Afterwards most of the time you’d be evaluating expressions one at a time either using
cider-eval-last-sexp
(C-c C-e or C-x C-e) or cider-eval-defun-at-point
(C-c C-c or C-M-x).
Typically this type of evaluation commands would provide you with dual feedback - you’d see the results in both the Emacs minibuffer and in an inline overlay in the source buffer.
In case the result of the evaluation is big (e.g. a map with dozens of keys) it might be best
to display it in a dedicated buffer. You can do this with
cider-pprint-eval-last-sexp
(C-c C-p). As a bonus -
the result will be pretty-printed in the result buffer.
Exotic Evaluation Commands
WIP |
While the basic evaluation commands discussed earlier should be enough for most people, CIDER features a ton of additional evaluation commands. Some of them are so peculiar that one can easily label them "exotic". This section will briefly go over some of them.
Broadly speaking the exotic evaluation commands can be grouped in the following categories:
-
commands that are a variation of some basic commands (e.g.
cider-eval-list-at-point
andcider-eval-sexp-at-point
) -
commands that insert the result in the current buffer (e.g.
cider-eval-last-sexp-and-replace
) -
commands that evaluate an expression in a different context (e.g. with user-supplied bindings)
-
commands that evaluate some particular part of a buffer (e.g.
cider-eval-ns-form
)
Most of the exotic evaluation commands don’t have "top-level" keybindings
and should be accessed via CIDER’s evaluation commands keymap (cider-eval-commands-map
), meaning that they share the standard prefix C-c C-v
. On top of this - several
related commands that pretty-print their result are grouped under C-c C-v C-f
.
Evaluating Clojure Code in the Minibuffer
You can evaluate Clojure code in the minibuffer at almost any time
using M-x cider-read-and-eval
(bound in cider-mode
buffers to
C-c M-:). TAB completion will work in the minibuffer,
just as in REPL and source buffers.
Typing C-c C-v . in a Clojure buffer will insert the defun at point into the minibuffer for evaluation. This way you can pass arguments to the function and evaluate it and see the result in the minibuffer. |
You can also enable other convenient modes in the minibuffer. For
instance, you might want to have both eldoc-mode
and paredit-mode
available to you:
(add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'paredit-mode)
Evaluation Hooks
You can use cider-file-loaded-hook
to trigger some action after a
file has been evaluated.
cider-auto-test-mode is implemented in terms of this hook -
tests are re-run every time you evaluate a file.
|
You can use cider-before-eval-hook
to trigger some action before eval
request is sent to nrepl server.
You can use cider-after-eval-done-hook
to trigger some action after the
eval response was received from nrepl server with status "done".
Synchronous vs Asynchronous Evaluation
nREPL has an asynchronous evaluation model, where eval requests are enqueued and the responses are sent back to the clients when available. This model works great most of the time as doesn’t require clients to block while waiting for responses, but it also requires the clients to able to handle comfortably response callbacks.
Unfortunately, some of Emacs’s internal APIs don’t play well with asynchronous evaluation (e.g. completion, eldoc, etc) and in those cases CIDER simulates synchronous evaluation instead. It’s important to understand several things:
-
CIDER’s sync eval commands should be used sparingly
-
The most common use case for the sync eval API is evaluating some simple and fast to run tooling-related code
-
Sync eval may result in client lock-ups, as Emacs is (mostly) single-threaded by design
CIDER tries to mitigate the latter by imposing a 10 second eval request timeout for sync eval. You can adjust this default if needed:
;; increase the sync request timeout to 1 minute
(setq nrepl-sync-request-timeout 60)
;; disable sync request timeout
(setq nrepl-sync-request-timeout nil)
CIDER internally increases the timeout to 30 seconds for the first sync eval request it does, as it might require a lot of namespaces and take more time to complete. See cider—prep-interactive-eval for details.
|
Configuration
Display Spinner During Evaluation
Some evaluation operations take a while to complete, so CIDER will display a visual indicator (a spinner) in the modeline to indicate this. The evaluation-in-progress spinner can be controlled by several variables:
-
cider-eval-spinner-type
(default value'progress-bar) - controls the appearance of the spinner. See `spinner-types
for all possible options. -
cider-eval-spinner-delay
controls the time (in seconds) after which to show the spinner. The default value is 1 second. -
cider-show-eval-spinner
controls whether to show the spinner at all. Set this variable tonil
to disable it.
CIDER uses internally the excellent package spinner.el. |
Overlays
When you evaluate code in Clojure files, the result is displayed in the buffer itself, in an overlay right after the evaluated code. If you want this overlay to be font-locked (syntax-highlighted) like Clojure code, set the following variable.
(setq cider-overlays-use-font-lock t)
You can disable overlays entirely (and display results in the echo-area at the
bottom) with the cider-use-overlays
variable.
(setq cider-use-overlays nil)
By default, result overlays are displayed at the end of the line. You can set
the variable cider-result-overlay-position
to display results at the end of
their respective forms instead.
Note that this also affects the position of debugger overlays.
(setq cider-result-overlay-position 'at-point)
You can also customize how overlays are persisted using the variable
cider-eval-result-duration
.
By default, its value is 'command
, meaning that result overlays disappear
after the next user-executed command, such as moving the point or scrolling.
Setting the variable to a number represents the duration in seconds until overlays are removed, while setting it to ’change' persists overlays until the next change to the buffer contents.
(setq cider-eval-result-duration 5.0)
(setq cider-eval-result-duration 'change)
Auto-Save Clojure Buffers on Load
Normally, CIDER prompts you to save a modified Clojure buffer when you
type C-c C-k (cider-load-buffer
). You can change this
behavior by adjusting cider-save-file-on-load
.
Don’t prompt and don’t save:
(setq cider-save-file-on-load nil)
Just save without prompting:
(setq cider-save-file-on-load t)
Change the Result Prefix for Interactive Evaluation
Change the result prefix for interactive evaluation (not the REPL prefix). By default the prefix is `⇒ `.
(setq cider-eval-result-prefix ";; => ")
To remove the prefix altogether, just set it to the empty string (""
).
Change the Output Destination
By default CIDER will display the output produced by some evaluation in the REPL buffer, but you can also funnel the output to a dedicated buffer. You can configure this behavior via cider-interactive-eval-output-destination
.
(setq cider-interactive-eval-output-destination 'output-buffer)
Additionally, there’s the variable cider-redirect-server-output-to-repl
that captures output that would normally end up in the nrepl-server
buffer (provided it has been started via cider-jack-in
) and redirects it to the REPL buffer. You can disable this redirection like this:
(setq cider-redirect-server-output-to-repl nil)
The redirection functionality is implemented in cider-nrepl as nREPL middleware. If you’re using CIDER without cider-nrepl no output redirection is going to take place.
|
Keybindings
You might have noticed that CIDER typically has 2-3 different keybindings for many evaluation commands. In case you’ve been wondering "Why?" the answer is pretty simple - legacy. The principle sources of inspiration for CIDER, Emacs and SLIME, provide more or less the same functionality, but use different keybindings. CIDER tried to find a common ground by adopting them both.
On top of this, at some when it became clear that CIDER has set the world record
for evaluation command, we’ve introduced a dedicated keymap for all eval commands
(that’s everything with the prefix C-c C-v). This leads to funny situations
like cider-eval-defun-at-point
having 3 keybindings:
-
C-M-x (Emacs style)
-
C-c C-c (SLIME style)
-
C-c C-v (C-)d (CIDER style)
Okay, those are technically 4 keybindings, but who’s counting!
Some of you are probably wonder why C-c C-v instead of
C-c C-e, right? Again - legacy. Historically C-c C-e
was mapped to cider-eval-last-sexp , otherwise we would have picked
this binding. It’s still possible to recycle it down the road, as
most people are probably using C-x C-e for cider-eval-last-result
and good keybindings are too precious to be wasted like this.
|
Below is a listing of most keybindings for evaluation commands:
Command | Keyboard shortcut | Description |
---|---|---|
|
C-x C-e |
Evaluate the form preceding point and display the result in the echo area and/or in an buffer overlay (according to |
|
C-c C-v w |
Evaluate the form preceding point and replace it with its result. |
|
C-c M-e |
Evaluate the form preceding point and output it result to the REPL buffer. If invoked with a prefix argument, takes you to the REPL buffer after being invoked. |
|
C-u C-c M-p |
Load the form preceding point in the REPL buffer and eval. |
|
C-c C-p |
Evaluate the form preceding point and pretty-print the result in a popup buffer. If invoked with a prefix argument, insert the result into the current buffer as a comment. |
|
C-c C-v C-f d |
Evaluate the top level form under point and pretty-print the result in a popup buffer. If invoked with a prefix argument, insert the result into the current buffer as a comment. |
|
C-M-x |
Evaluate the top level form under point and display the result in the echo area. |
|
C-c C-v l |
Evaluate the list around point. |
|
C-c C-v v |
Evaluate the form around point. |
|
C-u C-M-x |
Debug the top level form under point and walk through its evaluation |
|
C-c C-v z |
Evaluate the preceding top-level form up to the point. |
|
C-c C-v r |
Evaluate the region and display the result in the echo area. |
|
C-c C-b |
Interrupt any pending evaluations. |
|
C-c C-v n |
Eval the ns form. |
|
C-c M-z |
Load (eval) the current buffer and switch to the relevant REPL buffer. Use a prefix argument to change the namespace of the REPL buffer to match the currently visited source file. |
|
C-c C-k |
Load (eval) the current buffer. |
|
C-c C-l |
Load (eval) a Clojure file. |
|
C-c C-M-l |
Load (eval) all Clojure files below a directory. |
You’ll find all evaluation commands and their keybindings in the CIDER Eval menu.
|