Playing hide-and-seek with my REPLs


Emacs users know their beloved editor has a penchant for throwing windows and buffers around. Smart Emacs users know how to make Emacs behave with a careful configuration of display-buffer-alist. For instance, I like to have all of my REPLs in a bottom side window, taking up half of the screen size.

(setq display-buffer-alist
      `((,(rx bos (or "*cider-repl"     ; CIDER REPL
                      "*intero"         ; Intero REPL
                      "*idris-repl"     ; Idris REPL
                      "*ielm"           ; IELM REPL
                      "*SQL"))          ; SQL REPL
         (display-buffer-reuse-window display-buffer-in-side-window)
         (side . bottom)
         (reusable-frames . visible)
         (window-height . 0.50))))

I then have a couple of custom functions, lifted from Sebastian Wiesner’s archived configuration, to quickly close the REPL and go back to the buffer I was editing.

(defun mu-find-side-windows (&optional side)
  "Get all side window if any.
If SIDE is non-nil only get windows on that side."
  (let (windows)
    (walk-window-tree
     (lambda (window)
       (let ((window-side (window-parameter window 'window-side)))
         (when (and window-side (or (not side) (eq window-side side)))
           (push window windows)))))
    windows))

;;;###autoload
(defun mu-quit-side-windows ()
  "Quit side windows of the current frame."
  (interactive)
  (dolist (window (mu-find-side-windows))
    (when (window-live-p window)
      (quit-window nil window)
      ;; When the window is still live, delete it
      (when (window-live-p window)
        (delete-window window)))))

(bind-key "C-c w q" #'mu-quit-side-windows)

All of this usually works fine. However, CIDER has recently introduced a new session system which doesn’t play well with this setup. Basically, using quit-window on a CIDER REPL results in a buffer without its related REPL available.

The solution is trivial.

;;;###autoload
(defun mu-hide-side-windows ()
  "Hide side windows of the current frame."
  (interactive)
  (dolist (window (mu-find-side-windows))
    (when (window-live-p window)
      (delete-window window))))

(bind-key "C-c w h" #'mu-hide-side-windows)

Now I just hide the side windows of the current buffer, and the linked REPL is always a key binding away.

Notice that if you are only visiting one buffer and a REPL, pressing C-x 0 in the REPL window or C-x 1 in the buffer where the REPL window was opened has the same effect of C-c w h.