Weekend with Doom Emacs as a Clojure IDE
01 June 2021
This is pretty much a set of notes from what I went through trying to get a good clojure development environment setup and have a change of view from JetBrains Intellij.
Where you might be starting from
Where I started from in my knowledge and you might already be for this to be useful:
- User of VIM keybindings in JetBrains products
- Past experience of intellij clojure plugin cursive and clojure
- User of MacOS Big Sur, with homebrew already installed
- Java installed via asdf
- Clojure build tool leiningen installed with
brew install leiningen
Starting at install
Installing doom emacs is pretty well documented.
Visit the Doom Emacs getting started documentation
Follow the MacOS thread. I went with the installation of emacs-mac for no stronger reason than it was top of the list.
By the end of the linked install guide you should have Emacs.app symlinked to your Applications folder and doom emacs installed and opening with Doom emacs.
Running from the CLI
Being able to launch the Application from the CLI doesn’t come for free.
Railwaycat has thankfully written a script in a gist, see the first comment for a shell script so get this script into a file in your path, ahead of the existing emacs command.
I went with a new command entirely, simply e
, so:
vim /usr/local/bin/e
# paste the script after reviewing for anything nefarious
# write and quit
chmod +x /usr/local/bin/e
The script needs some further attention as right now it won’t work if you don’t pass a parameter.
# won't work:
e
# any of these work:
e .
e file.txt
General Doom Emacs configuration
So now we’re actually in doom emacs, and it’s looking pretty but… what now? This section is going to give a whirlwind tour of the things I immediately wanted to tweak.
Key notation guide for mac users:
SPC
is equal to pressing the spacebarC
is equal to Ctrl, soC-h
isCtrl+h
M
is the Option key
Access the doom emacs config files
You can get to them from your terminal easily, they’re all in ~/.doom.d/
.
Any custom configuration you need can live in the config.el
file.
If you’ve already got emacs open, but want to get to your doom config quickly then hit:
SPC f p
- This lists the doom config files, and you can use
C-j
or C-k
to move up and down the list, hit Enter
to open one.
Reloading config
Once you’ve made changes in your doom config and written the file, at the terminal you can run:
~/.emacs.d/bin/doom sync
Alternatively, you can reload from within emacs for changes that don’t need a full restart:
; sync (reload) doom
SPC h r r
Start Doom Emacs maximised
Launching emacs will likely be opening it in a small window.
So how do I make emacs start maximised?
;; in your config.el, add:
(add-to-list 'default-frame-alist '(fullscreen . maximized))
Adjusting text - increase font size
There’s already a handy guide for how to increase font size
and the doom config.el
comes with example configuration in the comments.
In config.el
:
(setq doom-font (font-spec :family "JetBrainsMono Nerd Font Mono" :size 20))
Use whatever family you like, but I like the jetbrains mono font, so give that a go from a brew cask if you like:
brew tap homebrew/cask-fonts
brew install --cask font-jetbrains-mono-nerd-font
See all the other fonts available in the cask and look for the nerd font variants for icon support.
Finding keybindings for commands
A generally useful tip is how to find the thing that you want to do, and the vim, or evil-mode, keybindings to do it.
Hitting SPC
, that is the spacebar, and waiting a second
will bring up a minibuffer at the bottom of the screen
with a handy guide for where you can go next in your command chain.
Bring up the command prompt with SPC :
(often seen as M-x
in standard emacs keybindings). From here
you can type what you’re trying to do and poke around package commands.
For example, enter doom
, and you’ll see the list start filtering
down, and any commands with keybindings will have a convenient format like:
doom/reload (SPC h r r) Reloads your private config.
Some panels will popup help when you enter a ?
. Also worth exploring
is the which-key
mode and related commands but I didn’t get to that yet.
With so many options built in, and some occasionally remapped from the package’s defaults, it can be hard to find the best practice with this method but spending some time exploring those command options is worth some of your time.
IDE alternative patterns
In my day to day work I reach for Intellij products, so looking for the same conveniences is one of my first stops.
Working with projects
Doom emacs comes with a few conveniences for project work available. projectile is the underlying project tool here.
Hitting SPC p
will bring up the projectile options
Project visual tree, or file viewer
I’m used to the project panel in Intellij, an easy overview of the project structure.
To get a visual project tree, I also enabled the treemacs option in
the doom init.el
- uncomment the :ui > treemacs
option and sync your settings.
When you’re in a file in a source code repository, toggle open treemacs with SPC o p
automatically find this and present it as the root folder.
Search for a file in project
SPC p f
is one way to find a file in a project context. See also SPC SPC
for navigating to a file by name.
One less keypress…!
Project search for text in file
SPC s p
will search in a project for an arbitrary string.
Using Doom Emacs as a Clojure IDE
Getting started with clojure in doom emacs is fairly well documented.
Doom emacs comes with its own set of configuration files in the form of a language module.
Enabling the clojure language module
The place to enable this is in ~/.doom-emacs.d/init.el
Change a couple of things in init.el
:
- Uncomment
:tools
>lsp
to get language server support - Under
:ui
, replaceclojure
with(clojure +lsp)
to enable the language server.
Save your file :w
and sync doom SPC h r r
.
When you first open a clojure file, you’ll get a prompt about installing (clojure-lsp), go ahead!
It’ll take a minute for the language server to start on first access but the interface does a good job of indicating what’s going on.
You might get a prompt about setting the project root for import but it’s well documented on how to proceed.
What’s included in the clojure module
Your clojure module should now be up and running. If you want
to see what you’re actually getting as part of the clojure language module
then you can view the module readme in ~/.emacs.d/modules/lang/clojure/README.org
Core keybindings
The README for the module gives you a list of keybindings, but they don’t always map to the
doom emacs setup. While you can use the tip from earlier to lookup by command name SPC :
here are some quick places to start:
- See
SPC m
, wait for the options to appear. These are the module actions. - Launch (jack in to) the cider reply
SPC m '
- Load buffer into repl
SPC m r l
- Load/refresh namespace
SPC m n r
- Run the test at the cursor
SPC m t t
- Rerun test
SPC m t a
- Rerun failed test
SPC m t r
- Copy code into repl - grab the nearest top level function with
SPC m e D
- Copy code into repl - copy the last S-expression
SPC m e E
- View docs for item under cursor
SPC m h d
I have a feeling I’m going to want to find a way to auto load the current namespace into the repl as part of the test.
Finding the repl when it’s lost
Switch to the repl buffer in the module shortcuts: SPC m r b
I found it easy to lose my repl buffer while learning commands, the buffer
menu is also a reasonable place to start looking for lost buffers. While SPC b b
navigates
workspace buffers, the repl won’t appear in this list.
SPC b B
, note the capital letter B at the end, will show you a list
of all the buffers floating around including your repl.
The project buffer is pretty handy too as a wide view of what’s going on, bring it
up with SPC p b
.
Wrapping text in your repl
If you like your repl window vertical, you might find it’s not got the space it needs to stop text running off the screen.
SPC t w
will toggle soft wrapping.
What are the lightbulbs?
With the lsp
language server enabled, you’re probably seeing
one or more lightbulbs hovering around at the end of each line
as you move around.
These are… maybe useful… quick actions. To execute them, you’re
looking for code actions under SPC c a
.
Code navigation
- Go to definition -
g d
- Show usages -
g D
Refactoring
Refactoring clojure code is supported by clj-refactor.
This is a section I’m looking to improve on myself in terms of giving myself
quicker access. You can find the refactorings available under the SPC m R
refactoring menu. I’ve not found the faster way to access these yet.
Create a new file
One option if you’ve gone with treemacs is to pop open the treemacs
window SPC o p
and use the cf
shortcut from there.
Where’s my #/hash/pound key?
Normally under Option+3
, this gets lost in emacs for UK keyboards at least.
The shortest path to getting this back is to edit your doom config.el
with:
(define-key key-translation-map (kbd "M-3") (kbd "#"))
Qualitative experience
I’ve not completely arrived at an opinion here. It’ll take longer than a weekend for this to be muscle memory. The options above are just a tiny fraction of the differences that you don’t realise are missing until you reach for them.
I’m really liking being back on the keyboard in the more natural hand positioning pure vim gives. Some of the refactoring conveniences aren’t quite there in terms of quick key bindings, but that’s something I can easily adapt.
The power of other clojure specific refactoring is yet to be hit for me, and I’ve really not actually started coding yet while I’ve been trying to get a decent starting point. For that I’ve been using the luminus lein profile to help me get up and running with a ClojureScript environment.
Now to get into actual development. The learning curve is looking pretty steep, not just for emacs but the wider clojure ecosystem. Yet this feels like it’s given me a good starting point for a test driven way of developing with the repl. Exciting!