5.6 Face specs at scale using the themes’ palette

The examples here are for large scale operations. For simple, one-off tweaks, you may prefer the approach documented in the previous section (Case-by-case face specs using the themes’ palette).

The modus-themes-with-colors macro lets you retrieve multiple color values by employing the backquote/backtick and comma notation. The values are stored in the alists modus-themes-operandi-colors and modus-themes-vivendi-colors, while the macro always queries that of the active Modus theme (preview the current palette with the command modus-themes-list-colors).

Visualize the active Modus theme’s palette.

Here is an abstract example that just returns a list of color values while modus-operandi is enabled:

(modus-themes-with-colors
  (list fg-main
        blue-faint
        magenta
        magenta-alt-other
        cyan-alt-other
        fg-special-cold
        blue-alt
        magenta-faint
        cyan
        fg-main
        green-faint
        red-alt-faint
        blue-alt-faint
        fg-special-warm
        cyan-alt
        blue))
;; =>
;; ("#000000" "#002f88" "#721045" "#5317ac"
;;  "#005a5f" "#093060" "#2544bb" "#752f50"
;;  "#00538b" "#000000" "#104410" "#702f00"
;;  "#003f78" "#5d3026" "#30517f" "#0031a9")

Getting a list of colors may have its applications, though what you are most likely interested in is how to use those variables to configure several faces at once. To do so we can rely on the built-in custom-set-faces function, which sets face specifications for the special user theme. That “theme” gets applied on top of regular themes like modus-operandi and modus-vivendi.

This is how it works:

(modus-themes-with-colors
  (custom-set-faces
   `(cursor ((,class :background ,blue)))
   `(mode-line ((,class :background ,yellow-nuanced-bg
                        :foreground ,yellow-nuanced-fg)))
   `(mode-line-inactive ((,class :background ,blue-nuanced-bg
                                 :foreground ,blue-nuanced-fg)))))

The above snippet will immediately refashion the faces it names once it is evaluated. However, if you switch between the Modus themes, say, from modus-operandi to modus-vivendi, the colors will not get updated to match those of the new theme. To make things work across the themes, we need to employ the same technique we discussed in the previous section, namely, to pass our changes at the post-theme-load phase via a hook.

The themes provide the modus-themes-after-load-theme-hook, which gets called from modus-themes-load-operandi, modus-themes-load-vivendi, as well as the command modus-themes-toggle. With this knowledge, you can wrap the macro in a function and then assign that function to the hook. Thus:

(defun my-modus-themes-custom-faces ()
  (modus-themes-with-colors
    (custom-set-faces
     `(cursor ((,class :background ,blue)))
     `(mode-line ((,class :background ,yellow-nuanced-bg
                          :foreground ,yellow-nuanced-fg)))
     `(mode-line-inactive ((,class :background ,blue-nuanced-bg
                                   :foreground ,blue-nuanced-fg))))))

(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces)

A theme-agnostic hook for theme loading.

To discover the faces defined by all loaded libraries, you may do M-x list-faces-display. Be warned that when you :inherit a face you are introducing an implicit dependency, so try to avoid doing so for libraries other than the built-in faces.el (or at least understand that things may break if you inherit from a yet-to-be-loaded face).

Also bear in mind that these examples are meant to work with the Modus themes. If you are cycling between multiple themes you may encounter unforeseen issues, such as the colors of the Modus themes being applied to a non-Modus item.

Finally, note that you can still use other functions where those make sense. For example, the modus-themes-color-alts that was discussed in the previous section. Adapt the above example like this:

...
(modus-themes-with-colors
  (custom-set-faces
   `(cursor ((,class :background ,(modus-themes-color-alts 'blue 'green))))
   ...))