The Cursive REPL

The REPL is an integral part of any Clojure development environment, and Cursive is no exception. Cursive uses nREPL, which is now the de-facto standard REPL infrastructure for Clojure.

Local REPLs

REPLs are started using Run Configurations. If you’re using Leiningen in your project you can start your REPL using Leiningen directly which will ensure that Leiningen plugins (such as lein-immutant) will work correctly. Otherwise you can start a REPL based on an IntelliJ module configuration.

To create a new configuration, open Run→Edit Configurations…, and create a new configuration with +. Choose a local Clojure REPL as shown.

You can then name your configuration. You can also choose whether to run your REPL using Leiningen or directly - if your project is managed using Leiningen you almost certainly want to start the REPL with Leiningen. Depending on the option you choose you can then also select which module or Leiningen project to execute from, as well as specifying JVM args, environment variables and the working directory.

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.

At the bottom of the configuration editor window, you can modify the tasks to execute before running your configuration. Of particular interest are the “Synchronize Leiningen projects” and “Make” configurations, which will cause the dependencies from a Leiningen project to be synchronized with the Cursive project, and the project to be built. Note that synchronizing the Leiningen project is not necessary for a Leiningen run configuration to work correctly, as Leiningen will re-read the project file before launching the REPL - this option will only slow your REPL startup.

If you want to modify the default settings for new instances of a particular run configuration type, you can do so under the Defaults 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, you will get an option to create a run configuration directly.

Starting a debug REPL

One very useful feature is the ability to debug a REPL session. This is now 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.

REPL startup timeout

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.

Remote REPLs

Alternatively, if you already have an nREPL server running somewhere, you can connect to it using a Remote configuration. There are two options here - either you can configure it to connect to a host and port, or you can configure it to connect to and get the port from the port file written by Leiningen. 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.

Using the REPL

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 the tab title at the top of the tool window. 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 (Cmd Enter on the Mac). 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).

Interaction with the editor

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 Tools→REPL. “Load file in REPL” will send the contents of the current editor window to the REPL, execute its contents and switch to the first namespace in the file, if any. 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”. It will not change the active namespace in the 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.

REPL commands

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. Since 1.3.0, Cursive now allows you to assign keybindings to arbitrary commands.

When you have the REPL running, you can add a new command using Tools→REPL→Add new REPL Command:

You must provide a name for the command, which will be used to name the IntelliJ action. The commands have two main types - either they will repeat the last command executed at the REPL, or you can enter a specific command to be run. You can choose whether to have the current file loaded before the command is run, or whether to have all out of date files synchronised as described above. You can also choose whether the command should be run in the current REPL namespace, or in a specific namespace you choose. Finally, you can choose whether the command should be specific to the open project, or global for all projects.

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 Tools→REPL→Commands and can be invoked from there. If required, you can also later edit the commands using Tools→REPL→Edit REPL commands.