Search through Scheme, Common Lisp, and Clojure symbols the same way that you search through Emacs Lisp symbols

enzu.ru
4 min readMar 24, 2024
I’ve gotten addicted to Clojure lately

One of my favorite parts of Emacs is using something like Helm or Ivy to search through available Emacs Lisp symbols and then view their documentation and code definitions. This makes developing in Emacs Lisp a seamless joy.

Now with Vert&co, it’s easier to do this searching via the default Emacs completing-read functionality. One can also hook up completing-read to Ivy with this line of Emacs Lisp:

(setq completing-read-function #'ivy-completing-read)

The ability to search through Lisp symbols so helpful that I wondered if I could write a way to do it for Scheme, Clojure, and Common Lisp.

Common Lisp, with nearly a thousand symbols (not counting the ones added by mandatory packages like Alexandria and Serapeum which add 207 and 467 symbols respectively), could most benefit from this feature, as one is unlikely to memorize every helpful symbol name.

In this post, I’ll document how to set up Lisp symbol searching using Geiser, SLY, and CIDER with completing-read. I initially planned to either make these into packages or contribute them upstream, but package maintainers and MELPA encouraged me to make a blog entry instead, which I think was the right call. Nonetheless, I have packages available for those that would prefer it, as I use these in package form myself.

One limitation is that I haven’t really tested this approach with multiple Geiser, SLY, and CIDER sessions running, as I generally only run one of each at a time.

Scheme and Geiser

You can use the code below to make Scheme symbols searchable from Geiser:

(require 'geiser)

(defun completing-read-geiser--get-symbol (unparsed-string)
"Grab symbol from UNPARSED-STRING."
(string-match "\\(?:^\\|[^:]:\\)[[:space:]]+\\([^[:space:]]+\\)" unparsed-string)
(match-string 1 unparsed-string))

(defun completing-read-geiser-search ()
"Send apropos command to Geiser."
(let* ((response-alist (geiser-eval--send/wait `(apropos ".*")))
(response-string (cdr (assoc 'output response-alist)))
(response-list (butlast (split-string response-string "\n")))
(response-list-parsed (mapcar #'completing-read-geiser--get-symbol response-list)))
response-list-parsed))

(defun completing-read-geiser ()
"Get list of symbols available in your Geiser session."
(interactive)
(geiser-doc-symbol
(make-symbol (completing-read "Look up symbol in Geiser: "
(completing-read-geiser-search)))))

You can also just hook up the package that I wrote instead that contains the above code:

(straight-use-package
'(completing-read-geiser
:type git
:host github
:repo "enzuru/completing-read-geiser"))
(require 'completing-read-geiser)

completing-read-geiser will now pull up a searchable list of all symbols defined in the connected Geiser session, and let you view their manual definitions and source code. I like setting that function to C-h s in Scheme modes:

(define-key scheme-mode-map (kbd "C-h s") 'completing-read-geiser-describe-symbol)
(define-key geiser-repl-mode-map (kbd "C-h s") 'completing-read-geiser-describe-symbol)

Common Lisp and SLY

You can use the code below to make Common Lisp symbols searchable from SLY. It probably wouldn’t be hard to adapt this to SLIME either, but I haven’t tried:

(require 'sly)

(defun completing-read-sly-search ()
"Send apropos command to SLY."
(sly-eval `(common-lisp:apropos-list "" nil t)))

(defun completing-read-sly ()
"Get list of symbols available in your SLYsession."
(interactive)
(sly-describe-symbol
(completing-read "Look up symbol in SLY: "
(completing-read-sly-search))))

You can also just hook up the package that I wrote instead that contains the above code:

(straight-use-package
'(completing-read-sly
:type git
:host github
:repo "enzuru/completing-read-sly"))
(require 'completing-read-sly)

completing-read-sly will now pull up a searchable list of all symbols defined in the connected SLY session, and let you view their description and source code. I like setting that function to C-h s in Common Lisp modes:

(define-key common-lisp-mode-map (kbd "C-h s") 'completing-read-sly-describe-symbol)
(define-key sly-mrepl-mode-map (kbd "C-h s") 'completing-read-sly-describe-symbol)

Clojure and CIDER

You can use the code below to make Clojure symbols searchable from CIDER:

(require 'cider)

(defun completing-read-cider-search ()
"Send apropos command to CIDER."
(cider-complete ""))

(defun completing-read-cider ()
"Get list of symbols available in your CIDER session."
(interactive)
(cider-doc-lookup
(completing-read "Look up symbol in CIDER: "
(completing-read-cider-search))))

You can also just hook up the package that I wrote instead that contains the above code:

(straight-use-package
'(completing-read-cider
:type git
:host github
:repo "enzuru/completing-read-cider"))
(require 'completing-read-cider)

completing-read-cider will now pull up a searchable list of all symbols defined in the connected CIDER session, and let you view their documentation and source code. I like setting that function to C-h s in Clojure modes:

(define-key clojure-mode-map (kbd "C-h s") 'completing-read-cider-describe-symbol)
(define-key cider-repl-mode-map (kbd "C-h s") 'completing-read-cider-describe-symbol)

Happy hacking!

My .emacs.d/ may be of further help and can be viewed here: https://github.com/enzuru/.emacs.d

--

--

enzu.ru

Learning content for the GNU operating system and Lisp user space, developed through my eponymous charity (https://enzu.ru)