Nicolas Martyanoff — Brain dump About

Configuring SLIME cross-referencing

The SLIME Emacs package for Common Lisp supports cross-referencing: one can list all references pointing to a symbol, move through this list and jump to the source code of each reference.

Removing automatic reference jumps

While cross-referencing is very useful, the default configuration is frustrating: moving through the list in the Emacs buffer triggers the jump to the reference under the cursor. If you are interested in a reference in the middle of the list, you will have to move to it, opening multiple buffers you do not care about as a side effect. I finally took the time to fix it.

Key bindings for slime-ref-mode mode are stored in the slime-xref-mode-map keymap. After a quick look in slime.el, it is easy to remove bindings for slime-xref-prev-line and slime-xref-next-line:

(define-key slime-xref-mode-map (kbd "n") nil)
(define-key slime-xref-mode-map [remap next-line] nil)
(define-key slime-xref-mode-map (kbd "p") nil)
(define-key slime-xref-mode-map [remap previous-line] nil)

If you are using use-package, it is even simpler:

(use-package slime
  (:map slime-xref-mode-map
      (("n")
       ([remap next-line])
       ("p")
       ([remap previous-line]))))

Changing the way references are used

SLIME supports two ways to jump to a reference:

  1. With return or space, it spawns a buffer containing the source file and close the cross-referencing buffer.
  2. With v, it spawns the source file buffer but keeps the cross-referencing buffer open and keeps it current.

This is not practical to me, so I made a change. The default action, triggered by return, now keeps the cross-referencing buffer open and switches to the source file in the same window. This way, I can switch back to the cross-referencing buffer with C-x b to select another reference without spawning buffers in other windows (I do not like having my windows hijacked by commands).

To do that, I need a new function:

(defun g-slime-show-xref ()
  "Display the source file of the cross-reference under the point
in the same window."
  (interactive)
  (let ((location (slime-xref-location-at-point)))
    (slime-goto-source-location location)
    (with-selected-window (display-buffer-same-window (current-buffer) nil)
      (goto-char (point))
      (g-recenter-window))))

Note the use of g-recenter-window, a custom function to move the current point at eye level. Feel free to use the builtin recenter function instead.

I then bind the function to return and remove other bindings:

(define-key slime-xref-mode-map (kbd "RET") 'g-slime-show-xref)
(define-key slime-xref-mode-map (kbd "SPC") nil)
(define-key slime-xref-mode-map (kbd "v") nil)

Much better now!

Share the word!

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