Michael Alyn Miller

Vim + tmux + Clojure


There are a number of things that excite me about Clojure, but as someone that still uses Forth, the REPL was the thing that immediately attracted me to the language. The challenge for me as a Vim user was getting that REPL working in an environment that I felt comfortable with. Emacs users have SLIME and Eclipse users have Counterclockwise. Vim users have VimClojure, but I wanted something a little more lightweight. Thankfully we also have vim-slime, which turned out to be the perfect fit for me.

vim-slime is a Vim plugin that gives you an easy way to send text from a Vim buffer to tmux (or screen, but I wanted to learn tmux). There are a couple of other HOWTOs on this setup, but frankly they all seemed really complex for something that I felt should be simple. My hope is that the rest of this article will help you get started on building your own Vim + tmux + Clojure config

But first, here is a screenshot of my Clojure environment:

Vim and a Clojure REPL in a tmux window

You can see my Vim buffer on the left, a Clojure REPL in the top-right, and a UNIX shell in the bottom-right. I can easily switch between these panes using vi-style key sequences and, thanks to vim-slime, can send code to the REPL with a simple Control-c, Control-c sequence.

Configuring tmux

I recommend that you configure tmux first; we’ll build on that configuration over the next few sections.

Here is a copy of my .tmux.conf file:

# ##############################################################
# Global settings.
#

# Switch the prefix to Ctrl-a since Ctrl-b interferes with Vim.
set -g prefix C-a
unbind C-b

# Change the default input delay in order to improve Vim
# performance.
set -sg escape-time 1

# Number windows and panes starting at 1 so that we can jump to
# them easier.
set -g base-index 1
set -g pane-base-index 1

# vi mode.
set -g mode-keys vi
set -g status-keys vi

# 256-color mode.
set -g default-terminal "screen-256color"


# ##############################################################
# Key bindings.
#

# Reload .tmux.conf with "r".
bind r source-file ~/.tmux.conf \; display "Reloaded!"

# Split windows with a more visual set of characters.
bind | split-window -h
bind - split-window -v

# Select panes with vi-style movement commands.
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# Resize panes with vi-style movement commands.
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

Most of those options should be self-explanatory and many of them were taken directly from Brian P. Hogan’s excellent book on tmux. In any event, only a few of those options are actually required in order to use vim-slime; most of them just make it a bit easier to work with tmux.

Once you have configured tmux to your liking, start a new tmux session with tmux new. I use PuTTY as my terminal emulator and connect to tmux in a 161x49 character window. That lets me have one 80x48 Vim editor and two 80x24 shell windows.

You can create the same setup by pressing Control-a, | to split the pane horizontally, and then press Control-a, - to split the pane vertically. You can then move around between the panes by pressing Control-a and the vi movement keys (h, j, k, l).

Configuring Vim

I am going to assume that you already have a .vimrc file and know how to install plugins with Pathogen. You should start with the following Vim bundles and then expand from there (paredit is worth learning, for example):

You then need to enable all of those items in your .vimrc file like so:

" Clojure options.
let g:slime_target = "tmux"

autocmd Syntax clojure RainbowParenthesesLoadRound
autocmd BufEnter *.clj RainbowParenthesesToggle
autocmd BufLeave *.clj RainbowParenthesesToggle

let g:rbpt_colorpairs = [
    \ ['magenta',     'purple1'],
    \ ['cyan',        'magenta1'],
    \ ['green',       'slateblue1'],
    \ ['yellow',      'cyan1'],
    \ ['red',         'springgreen1'],
    \ ['magenta',     'green1'],
    \ ['cyan',        'greenyellow'],
    \ ['green',       'yellow1'],
    \ ['yellow',      'orange1'],
    \ ]
let g:rbpt_max = 9

Using vim-slime

Start Vim in your large tmux pane (type vim test.clj so that we get a Clojure buffer) and launch a Clojure REPL (using lein repl, for example) in your top-right pane. Remember that you can use Control-a and h, j, k, or l to move around between panes.

Type a Clojure form into your Vim buffer, perhaps something like the following:

(* 3 3 3)

Go back into command mode, position your cursor anywhere over that form, and press Control-c, Control-c. This is probably the first time that you have used vim-slime since launching Vim, which means that vim-slime needs some information about tmux in order to route your Clojure code to the proper tmux pane.

You will almost certainly want to accept the default socket name (of “default”). The tmux target pane is going to depend on a few things. First, did you name your tmux session or did you use the default name? Have you created any other tmux windows? In which pane is your Clojure REPL? Your target pane should be “:1.2” assuming that have followed this tutorial to the letter. How would you determine that on your own though?

The value to the left of the colon is the name of tmux session. You can leave that blank until you start using named tmux sessions. The period-separated numbers to the right of the colon are the window number and the pane number. Your current tmux window number is in the status bar at the bottom of the screen. tmux pane numbers can be displayed by pressing Control-a, q.

You can also type tmux list-panes -a into a shell window to see the names of all of the valid vim-slime targets.

Final thoughts

Emacs and Eclipse can probably do more than what is possible with this configuration, so you might want to consider those options if you are shopping around for both a new editor and a new programming language. As a Vim user though, I have been really happy with this configuration and have found it to be a great way to integrate the Clojure REPL into my development flow. I also like the fact that I can use these same tools for interactive development in other languages: shell scripts, Node.js, Python, etc.

There is only one disadvantage that I have found with this configuration, and it was one of the reasons that I initially considered switching editors: tmux doesn’t work on Windows and I do most of my development on Windows. I have some thoughts on how to fix that problem though. More on that in a future post.