4

For some reason, I need to manually update the custom-theme-load-path list after every update of a theme like smart-mode-line or leuven-theme. Looking for a solution, I came across this SO post. Here is the solution from that post (with slight modification):

;; Ensure that the custom-theme-load-path has all the theme paths added
;; Source: https://stackoverflow.com/a/15381087/1219634
(require 'dash)
  (require 's)
  (-each
      (-map
       (lambda (item)
         (format (concat elpa-dir "/%s") item))
       (-filter
        (lambda (item)
          (or (s-contains? "theme" item)
              (s-contains? "smart-mode-line" item)))
        (directory-files elpa-dir)))
    (lambda (item)
      (add-to-list 'custom-theme-load-path item)))

The above snippet works great and it updates custom-theme-load-path. The catch is that every time I load a theme using load-theme, the custom-theme-load-path resets to the value set by Customize. I have verified this behavior by putting (message "%s" custom-theme-load-path) before and after the call to (load-theme ..).

How can I permanently set the value of custom-theme-load-path so that load-theme cannot reset its value?

Here is a workaround I use to avoid this issue (but I'd like to understand why this is happening):

  • I have wrapped the above snippet in a function called update-custom-theme-load-path.
  • I call that function right before I call (load-theme 'leuven t)
Kaushal Modi
  • 25,651
  • 4
  • 80
  • 183
  • To clarify: custom-theme-load-path is set in Customize. When you update (via package.el) either leuven or smart-mode-line, those packages are no longer on custom-theme-load-path? – Jonathan Leech-Pepin Oct 13 '14 at 13:46
  • @JonathanLeech-Pepin Yes, those paths don't get auto updated even when I install through package.el. I used to manually update the path till I found the above snippet. – Kaushal Modi Oct 13 '14 at 13:48
  • Do you have a call to package-initialize in your init-file? And/or could you test running package-initialize after updating the theme, but before loading it? – Jonathan Leech-Pepin Oct 13 '14 at 13:54
  • I do have (package-initialize). I call it before requiring any of the themes. I also tried C-x C-e on that just now with the themes updated; but that did not update custom-theme-load-path. I load this before requiring any theme/package. – Kaushal Modi Oct 13 '14 at 14:01

1 Answers1

7

The Short Answer

You should not customize the custom-theme-load-path variable in the Customize interface.
So call M-x customize-variable RET custom-theme-load-path and ask to erase customizations (and save changes).

If you want to configure a custom theme directory beyond that which packages automatically add, customize the custom-theme-directory variable instead. That is exactly what this variable is for.


The Long Answer

Any customizations made through the Customize interface are reapplied whenever a theme changes. That’s due to 2 reasons:

  1. Themes are not just about faces, they’re about variables too.
  2. And the user customizations should always supersede the customizations applied by themes.

Thus, whenever a new theme is applied, the user customizations must be reapplied on top of it. Since your customization contains the custom-theme-load-path variable, themes are unable to add themselves to it.

That’s probably why the custom-theme-directory variable was created. This one is safe to customize, because it’s only yours (themes won’t touch it).

Malabarba
  • 23,148
  • 6
  • 79
  • 164
  • 1
    I am under that assumption that custom-theme-directory can contain just one directory. Isn't that true? – Kaushal Modi Oct 13 '14 at 14:56
  • I didn't need to set the custom-theme-directory. But I simply erased the customization of custom-theme-load-path and now the value set to this list in my init.el stick! Thanks! – Kaushal Modi Oct 13 '14 at 15:02
  • 1
    @kaushalmodi Yes, the custom-theme-directory variable is only needed if you want a directory beyond the automatically added ones AND you want to use the customize interface. – Malabarba Oct 13 '14 at 15:04
  • It's almost as though package.el needs to have it's own package-theme-directory that it can add files to, so that installations don't worry about customize overwriting them. – Jonathan Leech-Pepin Oct 13 '14 at 15:04
  • Thanks everyone. In closing I'd like to add that I don't need the snippet I have in the question any more and I can successfully add my forked version of zenburn using (add-to-list 'custom-theme-load-path (concat user-emacs-directory "/from-git/zenburn-emacs/")); I simply need to erase the customization of that list from custom.el in the events I save the customizations using the Customize interface. I don't find the custom-theme-directory variable very useful as it can hold just one directory. – Kaushal Modi Oct 13 '14 at 15:12
  • 1
    custom-theme-directory being one directory is still useful because themes are just individual files. Not so good for version control, but symlinks fix that. – Vamsi Oct 13 '14 at 15:19
  • If it is true that users should not customize option custom-theme-load-path using Customize then it should not be a user option. If this is really the case (dunno - I don't use custom themes), then please file an Emacs bug: M-x report-emacs-bug. User options are by definition customizable using Customize, and that should in fact be the primary way of modifying them (that, or using equivalent customize-* or custom-* functions). Or if your answer applies only to this use case, then please make that clear - it looks like you are advising not to customize the option in general. – Drew Oct 13 '14 at 16:25
  • @Drew Yes, I am advising against the use of the customize interface for this variable. And yes, it's a bug. But it's part if a deeper bug with the customize interface---one which I'm sure they're aware of. Namely, the interface leads to problems when both the user and a package add values to a list. If the user does it first, any further changes will get reverted upon load-theme. If the package does it first, these changes will get saved too when the user makes his changes, and when the package is uninstalled it could leave behind references to itself. – Malabarba Oct 13 '14 at 17:03
  • If the admonition is just to not both (1) use the Customize UI and (2) modify outside of the Customize UI, then of course that is general (and there is no bug, IMO). That wasn't clear (to me). Even then, there is not necessarily a problem, if users use custom* functions to do the modifying and they also save such "outside Customize" changes. What is asking for trouble is both (1) changing outside Customize without using custom* functions and (2) using Customize. But none of this is special to this variable, AFAICT. – Drew Oct 13 '14 at 17:32
  • @Drew Yes, none of this is special to this variable. This variable is just a very common instance of this overall conflict. – Malabarba Oct 13 '14 at 17:47
  • @Malabarba Do you think this info ( "You should not customize the custom-theme-load-path variable in the Customize interface.") should be in the custom-theme-load-path variable doc-string too? I faced this problem a year ago, and people are still facing the same today. – Kaushal Modi Oct 05 '15 at 18:24
  • @kaushalmodi I think it'd be best if this variable weren't a defcustom at all. I'll bring that up on the dev list. – Malabarba Oct 07 '15 at 18:14