Convolute Lisp S-Expressions With Smartparens
Discover the magic of convoluting s-expressions when editing Lisp code. Once it clicks, it could save you many hundreds of keystrokes.
“Convoluting a lisp s-expression” sounds like computer science ivory tower bollocks, but after I actually learned what it was and how to use it, I’m seeing it pop up quite regularly when writing lisp. Let me show you the magic; I promise every time you get to use it, you’ll feel like a king!
Let’s say you’ve been writing some code in a stream-of-consciousness way. First you bind some local variables using
let and call
(let ((x 1) (y 2)) (do-something x y))
Oh, but now you only want to
condition-p is true:
(let ((x 1) (y 2)) (when condition-p (do-something x y)))
…but wait, if
condition-p is false then the
let bindings are useless! You can see that the
when should have wrapped around the
let instead of just the body inside
let. Now you have to tediously flip everything around by hand, right?
sp-convolute-sexp to the rescue 🦸♂️
Put your point at the opening parenthesis of
(do-something x y) and run
M-x sp-convolute-sexp and in one fell swoop…
(when condition-p (let ((x 1) (y 2)) (do-something x y)))
So many keystrokes saved, right? Never mind feeling like a king — you’ll feel like a wizard 🧙
A More Abstract Explanation
It doesn’t matter how many s-expressions there are in the surrounding code — they usually won’t get in the way. You just have to keep a few specific rules in mind. Let’s break it down in an abstract example, with no distracting “reality” or whatever that is 🤓
(outer x y z (inner a b c d e f) j k l)
If you convolute around any of the s-expressions
a b c d e f then the s-expression surrounding
outer will be swapped with the s-expression surrounding
inner and all the s-expressions immediately preceding your cursor will be chopped off and moved alongside
So when we simply convolute around
a we’ll get:
(inner (outer x y z a b c d e f j k l))
But had we convoluted around
d then we would have gotten:
(inner a b c (outer x y z d e f j k l))
I like to map it to a binding that includes the
% character, since it visually reminds me of swapping something above to below and reinforces that pattern in my head so I remember to use it.
I’ve included it in my Smartparens hydra, which I’ve been working on improving as I write more and more lisp. But that’s a future post.