I'm using hl-mode as a minor mode for deft. How do I make the highlighted line change color (e.g. to gray) when the deft window isn't the current window, and then back to the default highlight color when the deft window becomes the current window again?
It turns out there is an option for this, see emacs.stackexchange.com/a/15141/780.– glucasAug 28, 2015 at 12:57
I've implemented this for
hl-line-mode using the
Here's the code:
(defface hl-line-inactive '((t nil)) "Inactive variant of `hl-line'." :group 'hl-line) (defun hl-line-update-face (window) "Update the `hl-line' face in WINDOW to indicate whether the window is selected." (with-current-buffer (window-buffer window) (when hl-line-mode (if (eq (current-buffer) (window-buffer (selected-window))) (face-remap-reset-base 'hl-line) (face-remap-set-base 'hl-line (face-all-attributes 'hl-line-inactive)))))) (add-hook 'buffer-list-update-hook (lambda () (walk-windows #'hl-line-update-face nil t)))
What this code is doing:
- Define a new face
hl-line-inactiveto be used in inactive windows. You can use
M-x customize-faceto modify the attributes of this face to your taste.
- Define a function to temporarily remap the highlighting face in inactive windows. A window is considered inactive if it is not displaying the same buffer as the currently selected window.
- Add a hook to
hl-line-update-facefor all the visible windows.
The code above (which I'm using in my own
init file) is much simpler than what I originally posted. Thanks @Drew for the suggestion to use
walk-windows. I also read more about face remapping (see Face Remapping in the Emacs Lisp Manual) and realized I could remove a lot of the code.
For posterity, here's what I originally posted:
;; Define a face for the inactive highlight line. (defface hl-line-inactive '((t nil)) "Inactive variant of `hl-line'." :group 'local) (defun toggle-active-window-highlighting () "Update the `hl-line' face in any visible buffers to indicate which window is active." (let ((dups)) (mapc (lambda (frame) (mapc (lambda (window) (with-current-buffer (window-buffer window) (when hl-line-mode (make-local-variable 'face-remapping-alist) (let ((inactive (rassoc '(hl-line-inactive) face-remapping-alist))) (if (eq window (selected-window)) (progn (setq dups (get-buffer-window-list nil nil 'visible)) (setq face-remapping-alist (delq inactive face-remapping-alist))) (unless (or inactive (memq window dups)) (add-to-list 'face-remapping-alist '(hl-line hl-line-inactive)))))))) (window-list frame))) (visible-frame-list)))) (add-hook 'buffer-list-update-hook #'toggle-active-window-highlighting)
See also function
walk-windows, which you can use to iterate over the windows of visible frames, etc. (And +1 for
buffer-list-update-hook, which gets called by
select-window.)– DrewAug 11, 2015 at 20:37
+1 for this! Not so much for the hl-line stuff in specific, but I've been looking off and on for years to find a reliable way of shading the backgrounds of inactive windows in a frame. This works! Thanks! Dec 29, 2015 at 22:59
Thank you, this is awesome! Unfortunately, it seems to have problems when using
global-hl-line-mode. It seems that
hl-line-modefor each buffer. It uses an overlay instead of using the
hl-lineface. I've been fiddling with it for a while with no luck. Any suggestions? Should I open a separate question? Nov 21, 2018 at 16:31
You may want to use
buffer-list-update-hookis call the buffer is changed.– updogliuMar 31, 2021 at 12:03
You can use
window-selection-change-functions. By adding a function locally the function is called each time when the window showing that buffer has been selected/deselected (see the docstring for more info).
This can be used to toggle
hl-line-face face for the deft buffer:
(defvar-local deft-hl-line-toggle-cookie+ nil) (defun deft-toggle-hl-line-face+ (w) (cond ((eq (current-buffer) (get-buffer deft-buffer)) (when deft-hl-line-toggle-cookie+ (face-remap-remove-relative deft-hl-line-toggle-cookie+))) (t (with-current-buffer (get-buffer deft-buffer) (setq deft-hl-line-toggle-cookie+ (face-remap-add-relative hl-line-face `(:inherit ,hl-line-face :background "gray"))))))) (defun deft-hl-line-toggle-setup+ () (add-hook 'window-selection-change-functions 'deft-toggle-hl-line-face+ nil t)) (add-hook 'deft-mode-hook 'deft-hl-line-toggle-setup+)
Thanks for answering this question despite it being so old! Your solution of using a buffer-local hook is much cleaner and less resource-intensive than previous solutions. May 17, 2021 at 9:20