Write Clojure with Neovim and Conjure

This is step-by-step process to setup vim to be a great (Clojure) editor. This post covers:

  1. Why Neovim
  2. Starting configuration
  3. Plugins

One: Use Neovim

A few years ago I didn't see the value in using Neovim over Vim. That has recently changed. I learned that Neovim:

  1. Supports Lua in addition to Vimscript
    • Lua is incredible for writing plugins
    • A suite of Lua based plugins are pushing the boundaries on what you can expect in vim
  2. Has extensions for treesitter
    • This has major implications for performance and plugin development
    • Treesitter builds a concrete syntax tree for your source file as you edit, providing plugins more handholds into the source file.
    • Using Treesitter with markdown, for example, enables proper syntax highlighting for embedded code blocks.
  3. Has a built in language server client

Installation instructions are here.

Two: It's dangerous to go alone, take this

When I first started using Neovim I went missing for three days. When I was found by the seaside I got to show the rescue party a neat Lua based configuration and an okay setup.

Thankfully there have been some community efforts to help prevent folks from getting lost out there.

I know use nvim-lua/kickstart.nvim to get started. It's intended to be the starting point for your custom configuration. To build up some foundational knowledge checkout these resources:

Here's the quickstart, assuming *NIX or MacOS:

# Backup anything:
mv ~/.config/nvim{,.bak} || echo ' -- Nothing to backup'

# Clone the repo to ~/.config/nvim
git clone https://github.com/nvim-lua/kickstart.nvim.git ~/.config/nvim

# Start nvim, watch the initial setup go
nvim

# Restart nvim when its done

Three: Add Clojure support

Add languages to treesitter

First we'll add Treesitter support for Clojure:

nvim ~/.config/nvim/init.lua

Search for Configure Treesitter - this is line 287 for me. Adding languages to the ensure_installed portion has treesitter automatically fetch and install support for these languages.

I recommend adding:

The updated block should resemble:

-- ~/.config/nvim/init.lua
-- ...some ways down...

-- [[ Configure Treesitter ]]
-- See `:help nvim-treesitter`
require('nvim-treesitter.configs').setup {
  -- Add languages to be installed here that you want installed for treesitter
  ensure_installed = {
    'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'typescript', 'help', 'vim',
    'markdown', 'bash', 'html', 'css', 'fennel', 'clojure'
  },
---- snip

Save the file and restart nvim. You should see notifications in the status bar that Treesitter is installing support for these languages.

Add Plugins

The main plugin of interest is Conjure which enables interactive development, connecting Neovim to your running program.

For an in-depth demonstration, check out Conjure's author, Oliver Caldwell, and his talk Conversational Software Development: What, Why and How

Additional plugins add support for structural editing. These are:

If you're giving structural editing a try, read through the READMEs above and reference this gist.

Custom plugins are added to: ~/.config/nvim/lua/custom/plugins/init.lua.

After these plugins restart nvim so they install and load.

-- ~/.config/nvim/lua/custom/plugins/init.lua

-- You can add your own plugins here or in other files in this directory!
--  I promise not to create any merge conflicts in this directory :)
--
-- See the kickstart.nvim README for more information
return {
  -- Conjure!
  'Olical/conjure',

  -- Structural editing, optional
  'guns/vim-sexp',
  'tpope/vim-sexp-mappings-for-regular-people',
  'tpope/vim-repeat',
  'tpope/vim-surround',
}

localleader

Conjure makes heavy use of the localleader, typically bound to comma. The kickstart configuration sets this to <space>, but I've found it doesn't seem to break anything if I set it as comma. This nicely separates Conjure keymaps from the rest of our setup.

To make the change, open ~/.config/init.lua and edit:

-- ~/.config/nvim/init.lua
-- around line 43 or so
vim.g.maplocalleader = ','

Give it a spin

To try out your new setup, and learn more about Conjure, execute this command from nvim:

:ConjureSchool

You can install additional language servers, linters, and formatters using Mason:

:Mason

This configuration uses Lazy as a package manager.

:Lazy

Use Telescope to explore files, help pages, key maps, the local buffer... just about everything!

:Telescope keymaps

""" Here's some to get you started:
" [s]earch [f]iles
<Space>sf

" [s]earch [g]rep - might require ripgrep
<Space>sg

" Recent files
<Space>?

" Current buffer
<Space>/

" Switch open buffers
<Space><Space>

The Rabbit Hole

Since you probably arrived here to get set up for writing more Clojure, you might also be interested in Aniseed and Fennel.

Aniseed allows you to write your Neovim configuration, as well as plugins in Fennel, a Lisp which compiles to Lua. Conjure itself is written this way.

Oliver Caldwell has his own magic-kit to get you started on that journey. I'll look for you by the sea.

There's also cajus-nvim, another Aniseed based starter kit.

Published: 2023-03-25

Tagged: neovim clojure conjure

Archive