30 March 2020

If you're a Vim user and learning Clojure or another lisp, you don't have to install any plugins right away (let alone switch editors) just to make editing S-expressions palatable. You can get by pretty well with just the built-in features.

It boils down mainly to two keys: % and = . % will jump to a matching paren (or curly/square bracket). = will re-indent a block of code. For example, consider this implementation of the Fibonacci sequence:

(defn fib [n] (if (#{0 1} n) 1 (+ (fib (- n 1)) (fib (- n 2)))))

Suppose we wanted to move the recursive fib calls into a (lazy) let binding. With our cursor on the first line, we'd hit o and then add two lines:

(defn fib [n] (let [fib-1 (delay (fib (- n 1))) fib-2 (delay (fib (- n 2)))] (if (#{0 1} n) 1 (+ (fib (- n 1)) (fib (- n 2)))))

With our cursor at the end of the third line, we could finish editing by hitting this sequence of keys:

0jw : move to opening paren of the if form. =% : re-indent the if form. jjWW : move to the opening paren of the (fib (- n 1)) form. c%@fib-1<esc> : replace that form with @fib-1 . Wc%@fib-2)<esc> : replace the second fib form and add a closing paren for the let form.

(defn fib [n] (let [fib-1 (delay (fib (- n 1))) fib-2 (delay (fib (- n 2)))] (if (#{0 1} n) 1 (+ @fib-1 @fib-2))))

For another example, say we want to add an element to the end of the div in this hiccup form:

[:div [:p "I'm sorry Dave"]]

With our cursor on the opening bracket of the :div form, just hit %i and then <enter>[:p "I'm afraid I can't do that"]<esc> :

[:div [:p "I'm sorry Dave"] [:p "I'm afraid I can't do that"]]

Another useful combination is d% , which deletes the current form. I also sometimes like to use v% to visually select a form before hitting = to re-indent it. (And you can hit == to re-indent just the current line.) In general, you'll find that editing S-expressions is quite natural once you've committed % to muscle memory.

So you can edit S-expressions in plain Vim—but should you?