dave yarwood
Conjuring Clojure in Vim: 2020 Edition

date:

October 5, 2020

Clojure tooling for Vim has been getting more and more interesting over the last several years.

When I first came to Clojure, Fireplace was the standard Vim plugin for Clojure development, providing Clojure developers with a great in-editor REPL experience. I think it’s still the case that the majority of Clojurian Vimmers use Fireplace, but in recent years, a number of viable alternatives have begun to appear, including the plugins Acid, Iced, and Conjure.

I’ve tried all of these plugins at one time or another, but I’ve been an avid user of Conjure since pretty early on in the life of the project. Conjure is a Neovim plugin that provides an excellent Clojure development environment out of the box. It is easy enough to get started that I would recommend Conjure to any Vim users who want to try Clojure for the first time.

What is this sorcery?

The elevator pitch for Conjure is that it effortlessly connects to your Clojure REPL and lets you evaluate Clojure code and see the results without having to leave Vim or take your eyes off of your code. You can do all of this with zero configuration, and with a handful of standard key mappings that are easy to learn.

But that really describes all of the Clojure Vim plugins that I mentioned above, so what sets Conjure apart from the rest of the pack?

The author of Conjure, Oliver Caldwell, has put a ton of thought and effort into making the out-of-the-box user experience nice and comfortable.

If you’re a Neovim user and you know how to use a plugin manager like vim-plug, all you have to do is:

  1. Install the Conjure plugin for Neovim.
  2. cd into the directory of a Clojure project. (You can easily start a new one by just making an empty directory.)
  3. Start an nREPL server. (More about this below.)
  4. In another terminal, cd into the same directory and open a Clojure source file in Neovim (e.g. nvim foo.clj).

Conjure will automatically connect to your nREPL server. Then, you can immediately start writing forms like (+ 1 2) and evaluating them by pressing <localleader>ee, and you’ll see the results appear in a neat little popup window.

nREPL and you

If you’re new to Clojure, you might not be familiar with what an nREPL server is, or how to start one.

An nREPL is a type of REPL (Read-Eval-Print Loop) that operates over the network and integrates easily with external tools like Conjure.

There are a handful of existing build tools for Clojure: Leiningen, Boot, and the official Clojure CLI. If you’re working on an existing Clojure project, you can determine which one of these to use based on what type of configuration file you find at the top level of the project:

  • If there is a project.clj file, it’s a Leiningen project.
  • If there is a build.boot file, it’s a Boot project.
  • If there is a deps.edn file, it’s a Clojure CLI project.

If you’re starting a new project, I recommend the official Clojure CLI. It’s easy to get started. deps.edn is optional, you can just evaluate the command below to start an nREPL server and you’re off to the races.

Depending on the build tool you’re using, run one of the following commands to start an nREPL server:

# Leiningen
lein repl

# Boot
boot repl

# Clojure CLI
clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version "LATEST"}}}' -m nrepl.cmdline

That Clojure CLI command is a mouthful! I recommend establishing an alias in your personal deps.edn file, as described here. Then the command is shorter:

clojure -A:nREPL -m nrepl.cmdline


In my own personal deps.edn setup, I have an nrepl-server alias that includes the -m nrepl.cmdline part too, which allows me to run an even shorter command:

clojure -A:nrepl-server

Bringing in dependencies

Your “project file” (project.clj, build.boot or deps.edn, depending on which build tool you’re using) allows you to specify what Clojure libraries your project depends on.

The gif below shows how you can use the popular clj-http library to make an HTTP request and print the response. The first step is to create a deps.edn file that looks like this:

{:deps
 {clj-http {:mvn/version "3.10.1"}}}

Then, simply start your nREPL server and start editing some code!

A refreshing experience

Conjure provides a convenient way to reload any code in your project that has changed since the last time you evaluated it, by using the tooling provided by clojure.tools.namespace. This builds on top of the CIDER nREPL middleware, so to make use of this feature, you’ll need to set it up so that your nREPL includes that middleware.

Once you’ve got that squared away, you can easily reload everything by pressing <localleader>rr. You can even configure Conjure to run hooks before and after refresh, which can be handy when you’re developing something that you might want to restart every time you make changes, like a web server.

Casting spells

One day, in the #conjure channel on Clojurians slack, an off-the-cuff discussion about re-evaluating the same form over and over again during development led to an intriguing new Conjure feature called “eval at mark.”

This feature is also affectionately known as the “spellbook” feature because it lets you evaluate any number of predefined Clojure forms, on demand, just by pressing a few keys. I’ve been using this feature a lot since it was introduced, and I love it!

In a typical workflow, I might set the mark F at a function call in a scratch namespace, and then I can call that function from anywhere, e.g. while I’m editing code in another namespace, by pressing <localleader>emF.

This sort of workflow helps a lot in common scenarios where I’m testing the behavior of a function that I’m writing, and that function itself calls a number of other functions that are defined in other namespaces. Sometimes, in the heat of development, I end up jumping around through a bunch of different files as I’m chasing a bug or implementing a complex feature.

Previously, I had to jump back into my scratch namespace everytime I wanted to re-evaluate a form that calls the function I’m testing. Now, I can stay where I am in the implementation code and just press:

  • <localleader>rr to reload all of the code that changed, then

  • <localleader>emF to re-eval the form at mark F

To tie it all together, here’s a little demo of Conjure’s refresh and “eval at mark” features:

Try it!

If you’re a Vim-using Clojurist or a Clojure-using Vimmer, hopefully I’ve inspired you to give Conjure a try. Go ahead, it’s fun!

Comments?

Reply to this tweet with any comments, questions, etc.!