Recently I've had an odd problem with Emacs: occasionally, and somewhat randomly, as I wrote code, and only when I wrote Emacs Lisp code, and only when working in emacs-lisp-mode, I'd find that the buffer I was working in would disappear. Not just fully disappear, but more like if I'd used quit-window. Worse still, once this started happening, it wouldn't go away unless I turned Emacs off and on again.

Very un-Emacs!

Normally this would happen when I'm in full flow on something, so I'd just restart Emacs and crack on with the thing I was writing; because of this I wasn't diagnosing what was actually going on.

Then, today, as I was writing require in some code, and kept seeing the buffer go away when I hit q, it dawned on me.

Recently, when I cleaned up expando.el, I added the ability to close the window with q.

--- a/expando.el
+++ b/expando.el
@@ -58,7 +58,8 @@ Pass LEVEL as 2 (or prefix a call with \\[universal-argument] and
   (let ((form (preceding-sexp)))
     (with-current-buffer-window "*Expando Macro*" nil nil
       (emacs-lisp-mode)
-      (pp (funcall (expando--expander level) form)))))
+      (local-set-key (kbd "q") #'quit-window)
+      (pp (funcall (expando--expander level) form)))))

 (provide 'expando)

So, after opening a window for the purposes of displaying the expanded macro, switch to emacs-lisp-mode, locally set the binding so q will call on quit-window, and I'm all good.

Except... not, as it turns out.

To quote from the documentation for local-set-key:

The binding goes in the current buffer’s local map, which in most cases is shared with all other buffers in the same major mode.

D'oh!

Point being, any time I used expando-macro, I was changing the meaning of q in the keyboard map for emacs-lisp-mode. :-/

And so v1.6 of expando.el is now a thing, in which I introduce a derived mode of emacs-lisp-mode and set q in its keyboard map. In fact, I keep the keyboard map nice and simple.

(defvar expando-view-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "q") #'quit-window)
    map)
  "Mode map for `expando-view-mode'.")

(define-derived-mode expando-view-mode emacs-lisp-mode "expando"
  "Major mode for viewing expanded macros.

The key bindings for `expando-view-mode' are:

\\{expando-view-mode-map}")

From now on I should be able to code in full flow state without the worry that my window will disappear at any given moment...