Nicolas Martyanoff – Brain dump About

Fixing unquote-splicing behaviour with Paredit

Paredit is an Emacs package for structural editing. It is particularly useful in Lisp languages to manipulate expressions instead of just characters.

One of the numerous little features of Paredit is the automatic insertion of a space character before a delimiting pair. For example, if you are typing (length, typing ( will have Paredit automatically insert a space character before the opening parenthesis, to produce the expected (length ( content.

Paredit is smart enough to avoid doing so after quote, backquote or comma characters, but not after an unquote-splicing sequence (,@) which is quite annoying in languages such as Scheme or Common Lisp. As almost always in Emacs, this behaviour can be customized.

Paredit decides whether to add a space or not using the paredit-space-for-delimiter-p function, ending up with applying a list of predicates from paredit-space-for-delimiter-predicates.

Let us add our own. For more flexibility, we will start by defining a list of prefixes which are not to be followed by a space:

(defvar g-paredit-no-space-prefixes (list ",@"))

We then write our predicate which simply checks if we are right after one of these prefixes:

(defun g-paredit-space-for-delimiter (endp delimiter)
  (let ((point (point)))
    (or endp
        (seq-every-p
         (lambda (prefix)
           (and (> point (length prefix))
                (let ((start (- point (length prefix)))
                      (end point))
                  (not (string= (buffer-substring start end) prefix)))))
         g-paredit-no-space-prefixes))))

Finally we add a Paredit hook to append our predicate to the list:

(defun g-init-paredit-space-for-delimiter ()
  (add-to-list 'paredit-space-for-delimiter-predicates
               'g-paredit-space-for-delimiter))

(add-hook 'paredit-mode-hook 'g-init-paredit-space-for-delimiter)

Not only does it fix the problem for unquote-slicing, but it makes it easy to add new prefixes. For example I immediately added #p (used for pathnames in Common Lisp, e.g. #p"/usr/bin/") to the list.

Share the word!

Liked my article? Follow me on Twitter or on Mastodon to see what I'm up to.