1

Since the first time I set a custom theme in Emacs and then later attempted to modify some faces, I learned how to do it dynamically with the currently loaded and enabled theme.

Now, I am finally trying to build a set of my "own" themes. But of course, I want to base them on other popular themes. And I am a bit perplexed.

What does it mean for a theme to be loaded? What does this exactly do?

;; let's say my currently loaded theme is different
(load-theme 'zenburn :dont-ask :dont-enable)

And If I load a theme but don't enable it, can I still fetch all its faces and their attributes?

I want to do something like: (custom-theme-set-faces 'my-dark-theme ... but instead of listing all the faces and their attributes by hand, I want to get them from another theme (not currently enabled one), and only change selected faces.

2
  • Consider clarifying your question to say what part of the "doc-string" of load-theme is unclear to you. C-h f aka M-x describe-function. In terms of building your own, consider opening up the source code of your favorite theme and tweaking it to create a new one ... changing the name of the theme, creating a new file, etc.
    – lawlist
    Nov 2 '21 at 16:45
  • As I said: it's unclear what it means to "enable theme". The docstring says: "Note that enabling THEME does not disable any other already-enabled themes", implying there can be multiple enabled themes. I don't know, this is confusing. How can there be multiple enabled themes?
    – iLemming
    Nov 2 '21 at 16:50
0

With the great help from amazing Henrik Lissner (Doom Emacs author) and others, I have found answers to my questions:

  • About multiple enabled themes. Why is it possible to enable multiple themes?

If you have multiple themes active at the same time, you have multiple groups of faces active at once. e.g. Theme 1 sets the background of emacs to red. Theme 2 sets the color of bold text to blue. Theme 3 makes comments dark grey.

Activate them all and you have a red background, blue bold text, and dark grey comments. Though, generally, folks don't design their themes to be modular.

  • How to get faces for a loaded yet not enabled theme?

I think you'd need to look into (enable-theme)

I checked the code and found that (enable-theme) does: (get theme 'theme-settings). That however returns a lot of data that I needed to streamline a bit; After a bit of bike-shedding, I wrote this:

(defun color-theme-get-faces (theme)
  "Get list of faces with their attributes of a given THEME.
If theme is not loaded, it loads it first"
  (let* ((theme (get theme 'theme-settings))
         (theme-settings (if theme theme
                           (progn
                             (load-theme theme :no-ask :no-enable)
                             (get theme 'theme-settings))))
         (extract-props (lambda (props)
                          "extracts face props based on display type"
                          (seq-reduce
                           (lambda (acc x)
                             (pcase-let ((`(((,disp-type ,disp-val)) ,face-props) x))
                               (if acc acc
                                 ;; prioritize graphic & color displays
                                 (cond ((eq disp-val 'graphic) face-props)
                                       ((eq disp-val 'color) face-props)
                                       ((eq disp-type 'min-colors) face-props)
                                       (t face-props)))))
                           props nil))))
    (seq-remove
     'null
     (seq-map
      (lambda (x)
        (pcase-let* ((`(,prop-type ,face _ . (,props)) x))
          (when (eq prop-type 'theme-face)
           (list face (funcall extract-props props)))))
      theme-settings))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.