5.7 Remap face with local value

There are cases where we need to change the buffer-local attributes of a face. This might be because we have our own minor mode that re-uses a face for a particular purpose, such as a line selection tool that activates hl-line-mode, but we wish to keep it distinct from other buffers. This is where face-remap-add-relative can be applied and may be combined with modus-themes-with-colors to deliver consistent results.

Face specs at scale using the themes’ palette.

In this example we will write a simple interactive function that adjusts the background color of the region face. This is the sample code:

(defvar my-rainbow-region-colors
  (modus-themes-with-colors
    `((red . ,red-subtle-bg)
      (green . ,green-subtle-bg)
      (yellow . ,yellow-subtle-bg)
      (blue . ,blue-subtle-bg)
      (magenta . ,magenta-subtle-bg)
      (cyan . ,cyan-subtle-bg)))
  "Sample list of color values for `my-rainbow-region'.")

(defun my-rainbow-region (color)
  "Remap buffer-local attribute of `region' using COLOR."
  (interactive
   (list
    (completing-read "Pick a color: " my-rainbow-region-colors)))
  (face-remap-add-relative
   'region
   `( :background ,(alist-get (intern color) my-rainbow-region-colors)
      :foreground ,(face-attribute 'default :foreground))))

When my-rainbow-region is called interactively, it prompts for a color to use. The list of candidates is drawn from the car of each association in my-rainbow-region-colors (so “red”, “green”, etc.).

To extend this principle, we may write wrapper functions that pass a color directly. Those can be useful in tandem with hooks. Consider this example:

(defun my-rainbow-region-magenta ()
  (my-rainbow-region 'magenta))

(add-hook 'diff-mode-hook #'my-rainbow-region-magenta)

Whenever we enter a diff-mode buffer, we now get a magenta-colored region.

Perhaps you may wish to generalize those findings in to a set of functions that also accept an arbitrary face. We shall leave the experimentation up to you.