Computers Log: Clojure
I’ve recently become quite interested in the Lisp family of languages and have settled on learning Clojure. Below is a log of some of the setup required to get a NeoVim editor setup with auto-complete and some handy in-editor REPL evaluation. Most of the well-ranked search engine results I found to do this were 5-10 years old so I’ll document this here for myself and posterity.
Options Options Options
I explored a bunch of options here but largely found old articles and
dead ends. slimv
didn’t work for me as I’d hoped because clojure-swank
is deprecated and throws horrible strange traces on my machine.
fireplace.vim
seemed to be the best option I found next but it didn’t
talk SWANK (some REPL server protocol for editors aka emacs). It speaks
nREPL – well that was familiar, lein repl
starts that!
I pulled on this nREPL thread a bit and (a) it’s incredibly powerful and terrifying. I may or may not plan to leave an nREPL running in prod code one day for live debugging or hotfixes, but it’s cool I could! (b) Also I rediscovered Conjure (which I’d previously run across and forgotten) and it looks perfect for a newb like me.
Base
It’s another (much longer) log to explain why I’m using Alpine, just go with it. Be sure you have at least Clojure and Leiningen installed before following along below.
apk add clojure leiningen
REPL Setup
How not to start your REPL: clojure
instead try lein repl
which will get you nREPL which is a network socket REPL and REPL-y which
is a command line interface to nREPL.
Back to editing, my cursory understanding is that nREPL largely provides a evaluation but code definitions and auto-completion data are coming from cider-nrepl.
This is middleware that interprets incoming data from the editor to nREPL and either passes it through to nREPL or provides its own response.
I setup cider-nrepl
like so – I’m sure there are better ways to do
this but I’m just following ‘Quick Start’ guides and trying to make
things work. I am a beginner in Clojure who happens to be documenting,
not an expert, if you want to tell me how to do better please reach out
:)
To make this work on a per user basis – versus per project we can
create a profile for lein
and provide arbitrary overrides to the
project.clj
config for all the projects we work in.
I put the following in ~/.lein/profiles.clj
:
{:user {:plugins [[cider/cider-nrepl "0.28.7"]]}}
(update the version number to taste, by running lein search cider-nrepl
)
For the Pythonistas out there – think of this like an override to every
requirements-dev.txt file in all your projects. Or keeping certain
tools installed by the package manager outside your venv (like tox
).
Finally to ensure lein
got it quickly – it’s supposed to do this
automatically I’m just paranoid – you can run: lein deps
And to double check you can see the jar files downloaded in the typical
Maven location here:
~/.m2/repository/cider/cider-nrepl
Starting nREPL for NeoVim
There are plugins to kick off a nREPL when Vim starts but I haven’t used one yet, I’m doing this so far (but will look at vim-jack-in soon):
lein repl :headless
Which will output a line like this:
nREPL server started on port 34351 on host 127.0.0.1 -
nrepl://127.0.0.1:34351
Take the port and write it into ~/.nrepl-port
like so:
echo 34351 > ~/.nrepl-port
This is so Conjure can find the nREPL – otherwise you can tell it
inside of Vim like so :ConjureConnect 34351
.
Conjure
I actually switched to NeoVim to setup Clojure, I’d been meaning to try it anyway and some of the flashy bits of Conjure looked appealing enough to pull the trigger.
apk add neovim neovim-doc
I feel like Vim plugin managers always made a mess of my config backups so I’m not using one. The tldr; is you don’t need one so I pulled up the article where I learned about that[1] and followed along:
TLDR;
- Given your Vim directory (~/.config/nvim), create a
pack
directory - Then create and name a directory whatever you want under
pack
to organize your plugins - Create
start
andopt
directories inside of that. Plugins instart
will be loaded at start-up but you must ask for plugins to be loaded fromopt
(via:packadd
) - Start-up Vim (
nvim
) and run:helptags ALL
to integrate the package docs into:help
(for:help conjure
later, which you’ll want)
There – less code, fewer dependencies, fewer problems.
mkdir -p ~/.config/nvim/pack/clojure/start
cd ~/.config/nvim/pack/clojure/start
git clone https://github.com/Olical/conjure.git
I’m also not much one for custom config in Vim anymore, so my config is a single line (and you may already have it set):
~/.config/nvim/init.vim
(note the difference of location Vim users!)
let maplocalleader = ","
Conjure claimed to make ,
that the default leader when I opened nvim
and ran :ConjureSchool
but alas it didn’t work until I put that line
in place.
You should now be able to open up a new file (anywhere) with nREPL
running (anywhere) but with the port set (~/.nrepl-port
or set with
:ConjureConnect
) and do this:
nvim ~/tmp.clj
(* 4 8)
And while on the same line in command-mode type ,ee
and the expression
will be evaluated and => 32
will be appended to the line temporarily
in a light blue (your colors may differ).
If you’re having trouble with the leader key in Vim (,
) then try
running the full command :ConjureEval
and you should likewise get the
pink debug box and light blue.
Auto-complete
I went down lots of rabbit holes to get autocomplete working. It turned
out to be easy. Per the Conjure docs (:help conjure
but probably on
their site too) which lists
deoplete up top.
Python3 support is a hard requirement for deoplete but not just local but also Python3 RPC support via msgpack. So I had to install the Python client to NeoVim:
apk add py3-pynvim
Then I could install the plugin:
cd ~/.config/nvim/pack/clojure/start/
git clone https://github.com/Shougo/deoplete.nvim.git
(if you’re reading the deoplete instructions and installing nvim-yarp
and vim-hug-neovim-rpc
stop, those are only needed for Vim 8 not
NeoVim)
And one more line in the config file to enable it:
~/.config/nvim/init.vim
let g:deoplete#enable_at_startup = 1
I found that I had to ’re-seat’ the plugin once installed before it
started working by running the following from inside of nvim
:
:UpdateRemotePlugins
Probably something about the msgpack API built-in to NeoVim and registering deoplete initially but I didn’t look into it much.
References
- [1] History and effective use of Vim
- Conjure
- Setup cider-nrepl
- deoplete
- Conjuring Clojure in Vim: 2020 Edition for further learning
Opinions expressed on this site are my own.