Skip to main content

Emacs: Buffer-switch indicator

Most of the time, I have many windows open in Emacs, so it really helps to have an indicator of the current window (and buffer) especially when switching between windows.

I've created the following elisp snippet to be used as an advice :around the function select-window:

(defun local-buffer-background-indicator-on-buffer-switch-around-advice (func &rest args)
  "Advice to change background momentarily on buffer switch."

  (let* ((old-buffer (current-buffer))
         (return (apply func args))
         (new-buffer (current-buffer))
         (case-fold-search t))
    (unless (or (eq new-buffer old-buffer)
            (string-match-p "\\*minibuf" (concat (buffer-name old-buffer) (buffer-name new-buffer))))
      (buffer-face-set '(:background "black"))
      (run-at-time 0.25 nil (lambda ()
                              (when (buffer-live-p new-buffer)
                                (with-current-buffer new-buffer
                                  (buffer-face-set nil))))))
    return))

The function would make the background black for quarter of a second just to indicate the current buffer.

Adding the above as an advice:

(advice-add #'select-window :around #'local-buffer-background-indicator-on-buffer-switch-around-advice)

Notes:

  • The function is advised :around select-window, which is called by all of the usual buffer-switching (e.g. find-file, find-alternate-file) and window-switching (e.g. other-window, next-window) functions. As a buffer lives inside a window, the advised function is a buffer switching indicator. Understandably, the function could be advised :around any window-switching function(s) to make it applicable for such case(s).

  • The function keeps track of the previous buffer, then calls select-window and saves the returned buffer object for eventual return (as buffer objects are self-evaluating), then keeps track of the new buffer. (eq new-buffer old-buffer) check is needed in case of term-mode (and alike) as it calls select-window after each keypress (it needs to send any raw keypress events to the terminal). So we want to avoid highlighting the buffer again and again after any keypress while in the term-mode. I also don't want to highlight the minibuffer so ignored such switching from/to minibuffer.

  • I use a theme with light black (color hex-code #1d2021) background so for me making the background pure black (color hex-code #000000) is fine to indicate the highlighted buffer. This can be changed to suit ones need.

  • The background is changed by using the buffer-face-set function -- this enables the buffer-face-mode minor mode and change any face properties at once. This is basically a shortcut for setting the buffer-local variable buffer-face-mode-face to set any face properties and then enabling the buffer-face-mode. For example, in our case, (buffer-face-set '(:background "black")) would be analogous to:

(setq-local buffer-face-mode-face '((:background "black")))
(buffer-face-mode 1)
  • When it's time to disable the highlighting of the buffer, buffer-face-set is called with nil as argument to disable the buffer-face-mode. This is done after quarter of a second (using run-at-time) and can be increased/decreased as needed.

  • Prior to changing the background of the whole buffer, I tried to keep things minimal by only changed the background of the mode line (leveraging the mode-line-active and mode-line-inactive faces) but it looked at bit flaky when multiple horizontal/vertical splits are present.


References:

  1. select-window
  2. :around advice
  3. term-mode
  4. Minibuffer
  5. buffer-face-set
  6. buffer-face-mode
  7. buffer-face-mode-face
  8. run-at-time
  9. Mode line
  10. mode-line-active/ mode-line-inactive faces

Comments

Comments powered by Disqus