The REPL is an integral part of any Clojure development environment, and Cursive is no exception. There are various types of REPL available in Clojure, and Cursive supports most of them.
REPLs are started using Run Configurations. To create a new configuration, open , and
create a new configuration with +
. Choose a local Clojure REPL as shown.
You can then name your new configuration and choose which type of REPL to run - see Repl Types below for a description of the different types of REPL available. You can also customise the display name for the REPL, which will be displayed in its tab in the REPL toolwindow.
You can also choose how to run your REPL configuration. Usually, if your project is managed using Leiningen or Deps, you'll want to choose the corresponding option. That will allow you to set profiles or aliases, as well as ensuring that the build tool itself is used to run the REPL. This ensures that things like Leiningen plugins work correctly.
If your project is manually managing dependencies, or using some other build tool such as Maven or Gradle, you should select "Run with IntelliJ project classpath". As the name implies, this will simply use the classpath that IntelliJ has configured rather than fetching it from a build tool.
You can then also select which module to execute from, as well as specifying JVM args, environment variables, the working directory, and any additional parameters. You can also specify if you need the command line to be shortened - a full description of what this option means can be found in the IntelliJ documentation.
To run REPLs using Leiningen, Cursive internally uses the same mechanism as lein trampoline
. If for some reason your
REPL doesn't work correctly using trampoline
, see Remote REPLs below for a workaround.
If you want to modify the default settings for new instances of a particular run configuration type, you can do so under the Templates section in the left hand list. New configurations created of that type will use those settings.
There is also a shortcut method for creating a run configuration - if you right click on the project window anywhere
except inside a source root (for example on the project.clj
or deps.edn
file), you will get an option to create or
run a run configuration directly. Running it will cause a run configuration to be created which you can later customise
if required.
One very useful feature is the ability to debug a REPL session. This is very simple - simply run your local configuration in debug mode and a debugger will be automatically connected to it.
One thing that makes debugging with Clojure very difficult is locals clearing. This means that the Clojure compiler
will insert code to set any memory reference that it can prove will never be used again to nil
. This is a problem when
debugging; you will see many of your local variables set to null
when the code you are looking at could never have
caused them to take that value. This is done to prevent memory leaks from lazy sequences, which are cached in memory
to ensure that the same sequence will always return the same values in the same order. It's very confusing for
newcomers, and very frustrating when debugging for pretty much everyone.
Cursive starts all debug REPLs with locals clearing disabled, and all REPLs provide a toolwindow button () which will toggle it in the REPL server. Note that this is a feature of the compiler, so it only affects code when it is compiled - it's not a run-time flag. This means that if you toggle it you must recompile any code you'd like to debug. This generally means reloading it in the REPL after turning the flag on. Also, be very careful disabling locals clearing in any long-running process (e.g. a production server process) since it may cause memory leaks.
Cursive also supports configuring the REPL startup timeout. This is the time that Cursive will wait for the REPL to start before assuming something has gone wrong. By default it's set to 60 seconds. You can change this value at Settings→Languages & Frameworks→Clojure→REPL startup timeout.
Alternatively, if you already have an nREPL or socket REPL server running somewhere, you can connect to it using a Remote configuration.
Here you can select whether your REPL server is a socket REPL or an nREPL server. As before you can also customise the REPL display name. You can then choose how to connect - either you can configure it to connect to a host and port, or you can configure it to connect to a hostname and get the port from the port file written by Leiningen, Shadow CLJS or some other similar build tool. You can use this option if you want to start a REPL with Leiningen from the command line for some reason (for example, your REPL doesn't work with the trampoline option used by Cursive).
You can start as many REPLs as you like of whatever type, and they'll appear in tabs in the REPL tool window.
Now that you have your REPL running, you can type code into the editor window below, the results appear above. The current namespace is shown in a small overlay in the bottom right of the input pane. The REPL display name is shown in the tab title, and you can change that by double clicking here. You can execute code by pressing Enter if the cursor is at the end of a valid form, or you can execute at any time by pressing Ctrl+Enter. The editor is fully multi-line, and supports all functionality available in the main Clojure editor. You can move through your command history by using the up/down arrow keys, or jump between multi line items using Ctrl and arrow keys (Cmd arrows on Mac). If you don't want the editor to move between history items using the normal arrow keys, you can disable this with Settings→Languages & Frameworks→Clojure→Up/Down arrow keys move between history items.
Using the buttons above the output window, you can interrupt the current execution, toggle soft wrapping of the output, clear the output, stop the REPL and reconnect (for remote REPLs).
Often you'll be editing code in the main project windows, and you'll want to send code from your project to the running REPL. The commands to do this are under . "Load file in REPL" will send the contents of the current editor window to the REPL and execute its contents. A message will be printed out so you can see what happened.
"Load file in REPL" will calculate all the namespace dependencies of the file you're loading, and will
also load those dependencies in the correct order if any of them are out of date. This is very useful when editing
multi-namespace projects as it's often easy to forget when you've updated a file containing a function used by the main
code you're working on. It's also very useful when working on code that's require
'd by its tests.
"Sync files in REPL" will load all out-of-date files from the editor to the REPL in the correct order, using the same transitive dependency calculation as "Load file in REPL".
This loading of dependent namespaces can have unexpected side effects, especially if one of the dependent namespaces creates data that would be overwritten by reloading it. If this bothers you, you can turn off this dependency functionality with Settings→Languages & Frameworks→Clojure→Load out-of-date file dependencies transitively.
You can also switch the REPL namespace to that of the current file using "Switch REPL NS to current file", and execute individual forms from the editor using the "Run form before cursor" and "Run top form" commands. If you have code selected in the editor, both of the Run form commands will send the selection instead.
In the overlay at the bottom right of the REPL input pane, you can see the current REPL namespace and also the REPL
input mode. During normal REPL use this will read "Clojure", indicating that the input pane is expecting Clojure code
to be entered there. But if the REPL server requires input from *in*
, this will change and you'll be able to enter
the text to be supplied to the REPL input.
When using an nREPL REPL this switching is automatic, if you execute (read-line)
or something similar then the nREPL
server will inform Cursive that some input is required and Cursive will switch the editor to a text editor with the
tag "stdin" indicating that the next thing you enter will be sent as stdin to the REPL process.
When using a socket or clojure.main REPL this will have to be switched manually, you can either use the
"Toggle REPL Editor Type" action or there's a hover icon that will show up in the top-right of the REPL editor when you
move the mouse there. So with a socket REPL you would execute (read-line)
, the REPL will hang waiting for input over
the socket, you switch to text mode and send it the text, and then when it's expecting more forms for evaluation you
switch back to Clojure/CLJS mode. While there is some more manual fiddling for this, it's also more flexible - it
allows you to have a REPL that starts a shell or an SQL console, or a text adventure game, or something else requiring
a lot of input, and you can switch into text mode until you're done interacting with whatever it is.
Often, when interacting with the REPL, you will need to repeatedly execute the same commands. This is very common when using the reloaded pattern, but is also useful in other scenarios. Cursive allows you to assign keybindings to arbitrary commands and configure how they are executed, which means they can even be used to create custom versions of the built-in REPL interaction commands.
You can add a new REPL command, or manage your existing ones, in Settings→Languages & Frameworks→Clojure→REPL Commands. Here you can see which commands you have that are global (available in any project) or project specific. The project specific ones can be checked in and shared with team mates.
You must provide a name for the command, which will be used to name the IntelliJ action. Then there are various sections of config controlling how the command will behave:
These items control what will happen before the command is executed:
This section controls the basic behaviour of the command:
When executing a specific command, there are also substitutions available. These will take elements from the current state of the IDE and splice them in to the text of your command before executing it. They are:
Substitution | Value |
---|---|
~selection | The current selection |
~selected-form | The currently selected form if the selection is a single valid form |
~file-name | The name of the current file |
~file-path | The full path of the current file |
~line-number | The 0-based line number of the caret in the current editor |
~file-namespace | The namespace of the current file, if any, as a symbol |
~form-before-caret | The text of the form immediately before the caret |
~top-level-form | The text of the top-level form under the caret |
~current-var | The FQN of the current var under the caret |
~current-test-var | The FQN of the current var under the caret, if it represents a test |
~current-function | The FQN of the current var under the caret, if it represents a function |
Commands using substitutions will only be available when the substitutions they require are valid, for example a REPL
command with ~selection
in its text will not be available if there is no current selection.
Here you can choose whether the command should be executed in the current REPL namespace, the current file namespace, the original namespace (when re-executing a previous command), or in a specific namespace.
Here you can choose what should happen to the result of the execution:
Note that these can be selected independently, so you can perform one, more or all of them, or even just ignore the result entirely.
Here you can configure either the current file or all files to be reloaded from disk after the command is run. This is useful for refactoring or formatting commands where IntelliJ needs to pick the changes up after the command is finished.
Once you have created the command, you can bind a key to the action in Settings→Keymap. You can find the command either searching for its name, or you can collapse the whole tree and then navigate to Main Menu→Tools→REPL→Commands.
The commands will also appear in the main menu under and can be invoked from there. If required, you can also later edit the commands using .
For a lighter-weight alternative to full REPL commands, if you just have some forms in your file that you execute from time to time, you can add an IntelliJ bookmark to the line they appear on, using F11 ( ):
Then you can quickly execute those forms using . This will pop up a chooser showing the Clojure forms found on lines with bookmarks, and you can quickly execute them from there:
It's very common to need to repeat execution of a command you've executed previously. Cursive has a full REPL execution history, which you can use to search previous evaluations and re-execute them. Invoke it using Ctrl+Alt+E ( ), then you can navigate to the previously executed form you want to execute again. Press Enter to execute it directly, or Shift + Enter to copy it to the REPL input form for editing:
However, note that executing immediately using Enter will cause the form to be executed in the same namespace as its previous execution, but modifying it using Shift + Enter will cause it to be executed in the current REPL namespace.
Cursive's visual diff is very useful for comparing data structures, and you can invoke it from the REPL. In REPLs where Cursive controls the startup (most Clojure & Babashka REPLs, and some CLJS ones), you can do it like this:
(cursive/diff <left> <right>)
You can also optionally provide a title for the diff:
(cursive/diff <left> <right> :title <title>)
For example:
(cursive/diff (meta #'defn) (meta #'let) :title "Metadata")
This function is really just a thin wrapper which returns a tagged literal which Cursive interprets, so if for some reason Cursive can't inject it into your REPL automatically (e.g. when you have a Clojure REPL which gets upgraded to a CLJS one), you can do the following (and create your own function if desired, of course):
(tagged-literal 'cursive/diff {:left <left> :right <right> :title <title>})
Again, for example:
(tagged-literal 'cursive/diff {:left (meta #'defn) :right (meta #'let) :title "Metadata"})
Here the :title
entry is optional.
If you're using nREPL, you might want to configure middleware for some REPLs which don't provide the ability to
explicitly configure it. You can do this using the standard .nrepl.edn
file which is documented
here.
It's not essential to understand the following section to use REPLs in Cursive, but it's useful to understand what's going on under the hood when making decisions about which type of REPL to use.
There are two main styles of REPL used in Clojure. The most fundamental type of REPL is implied by the name:
it's a Read Eval Print Loop. So the server listens on some channel, Reads forms from that channel, Evals
them, Prints the result and then Loops around again. We'll refer to this type of REPL as a streaming REPL, since
all the communication between the client and the server happens over two streams: input and output. Cursive provides
this type of REPL via its clojure.main
option.
The other style is what we'll call an RPC (Remote Procedure Call) style REPL. In this style, the client prepares
a data structure describing what to evaluate. It will typically contain the form to be evaluated, the namespace in
which to evaluate it and so on. The server then evaluates the form and sends back a data structure describing the
result. This will contain fields such as the result form, the current namespace after the evaluation, any output
generated over either stdout
or stderr
, and information about any exceptions which have occurred. nREPL uses
this style of communication, and is the main type of REPL used in Cursive.
Each REPL type has advantages and disadvantages. In general, streaming REPLs use a simple model which is easy to understand. Their main advantage is that because their entire protocol is simply two streams, it's possible to 'layer' REPLs, i.e. from within a Clojure REPL you can start a ClojureScript REPL and it will just work, or you can run code which implements something like a SQL interface to a database. Since everything just obeys a simple UNIX-like model, this nesting can work very well. However there are important caveats to this - if the REPL has been customised in any way (i.e. a custom printing function, or a custom prompt) then these features may interfere with each other in subsequent layers, and can't be composed. Christophe Grand wrote about these problems here.
The main limitation of streaming REPLs is that the output is all interleaved over a single stream, so tools like Cursive can't post-process it. When using nREPL with Cursive, by default all output is pretty-printed and syntax highlighted which makes it much more readable. That can't be done with a streaming REPL, since everything comes over the output stream - printed forms, printed output from the evaluations, any exception stacktraces, the prompt for the next evaluation etc. There's really no way to distinguish which part of the output is which, so the client has no choice but to simply print it all out and hope it makes sense to the user. It's also difficult to hide communication from the user in order to implement functionality like completion, since there's only a single stream. RPC style systems like nREPL make tooling development much easier because of this. Recent incarnations of streaming REPLs (e.g. Unrepl and pREPL) solve this by providing a sort of half-way solution where the input is streaming but the responses sent back to the client structured, which solves a lot of these problems.
Currently Cursive supports nREPL, and streaming REPLs via clojure.main
, i.e. a stdin
/stdout
streaming REPL.
Cursive can also connect to a remote socket REPL, and will create a semi-structured protocol over the connection
when it starts up. If you require a purely streaming socket REPL, you can use
Tubular. Quite a lot of Cursive's functionality relies on nREPL, and won't be
available in clojure.main
REPLs.