In the world of 3D-modeling, back in the day before sculpting and retopo were invented, there were two different styles of modeling. Point-by-point (where you create a point, join it up to your other points with a line, and join that line up with your other lines with a face) and box modeling, where you start with a box, and cut and push and add loops to it.
When I’m using paredit to work on Lisp code, I’m using it like a box modeler.
The core primitives for me are wrapping and raising.
I start by inserting an empty pair and as I write, I keep adding pairs in. In the following evolving example, the bar character | represents my cursor.
(|)
(let ((|)))
(let ((foo|)))
(let ((foo (|))))
(let ((foo (bar|))))
(let ((foo (bar (|)))))
(let ((foo (bar (+ 11 12|)))))
(let ((foo (bar (+ 11 12))))|)
(let ((foo (bar (+ 11 12))))
(|))
(let ((foo (bar (+ 11 12))))
(frobnicate foo foo|))
So far, so normal. Like any other paredit user. Now let’s say I later realize that I need one of those foos to be reversed.
Let me first show you what I would not do:
(let ((foo (bar (+ 11 12))))
(frobnicate (|) foo foo))
(let ((foo (bar (+ 11 12))))
(frobnicate (reverse|) foo foo))
(let ((foo (bar (+ 11 12))))
(frobnicate (reverse foo|) foo))
Using a forward-slurp-sexp
.
Instead, I’d start by wrapping the foo, and then adding the new operator.
(let ((foo (bar (+ 11 12))))
(frobnicate (|foo) foo))
(let ((foo (bar (+ 11 12))))
(frobnicate (reverse |foo) foo))
If I later decide I don’t want that foo reversed after all, I can use
raise-sexp
on it. Wrapping and raising are the core primitives of
working with the syntax tree as a tree, always preserving the
syntactic structure, as opposed to seeing it just as text that happens
to have a matching paren that you want to push rightwards by slurping.
There’s also splicing and splice-killing that are useful.