use-package icon indicating copy to clipboard operation
use-package copied to clipboard

:custom settings being _slightly_ overwritten

Open sellout opened this issue 1 year ago • 5 comments

tl;dr: (get '<some-variable> 'saved-value) changes after the package defining <some-variable> is loaded, depending on whether use-package :custom or custom-set-variables is used to set <some-variable> in an init file.

This is with

  • GNU Emacs 28.1 (build 1, aarch64-apple-darwin21.6.0, NS appkit-2113.60 Version 12.6 (Build 21G115))
  • use-package 20220910.25 (Commit: 570bde6b4b89eb74eaf47dda64004cd575f9d953)

The high-level view is that I have this in my init file:

(use-package epg :custom (epg-gpg-program "/path/to/gpg2"))

And when I start Emacs, M-x customize-variable epg-gpg-program shows me that value ("/path/to/gpg2"), but it says “CHANGED outside Customize.” and is missing the “Customized with use-package epg” comment. Then, if I try to use epg, I get an error “epg-context--make: GPG error: "no usable configuration", OpenPGP”.

Digging into that a bit, I update my init file to

(use-package epg
  :custom (epg-gpg-program "/path/to/gpg2")
  :init (print (symbol-plist 'epg-gpg-program)))

(print (symbol-plist 'epg-gpg-program))

which gives me this in *Messages* (reformatted slightly):

(theme-value ((use-package "/path/to/gpg2"))
 saved-value ("/path/to/gpg2")
 saved-variable-comment "Customized with use-package epg")

(theme-value ((use-package "/path/to/gpg2"))
 saved-value nil
 saved-variable-comment "Customized with use-package epg"
 standard-value ((funcall #'#[0 "��!�

sellout avatar Oct 11 '22 03:10 sellout

Ok, so I forgot how powerful emacs debugging is. I added some advice to put and immediately found the culprit.

In custom-declare-variable:

      ;; If there is a value under saved-value that wasn't saved by the user,
      ;; reset it: we used that property to stash the value, but we don't need
      ;; it anymore.
      ;; This can happen given the following:
      ;; 1. The user loaded a theme that had a setting for an unbound
      ;; variable, so we stashed the theme setting under the saved-value
      ;; property in `custom-theme-recalc-variable'.
      ;; 2. Then, Emacs evaluated the defcustom for the option
      ;; (e.g., something required the file where the option is defined).
      ;; If we don't reset it and the user later sets this variable via
      ;; Customize, we might end up saving the theme setting in the custom-file.
      ;; See the test `custom-test-no-saved-value-after-customizing-option'.
      (let ((theme (caar (get symbol 'theme-value))))
        (when (and theme (not (eq theme 'user)) (get symbol 'saved-value))
          (put symbol 'saved-value nil)))

and custom-theme-recalc-variable says

    ;; We used to save VALSPEC under the saved-value property unconditionally,
    ;; but that is a recipe for trouble because we might end up saving session
    ;; customizations if the user loads a theme.  (Bug#21355)
    ;; It's better to only use the saved-value property to stash the value only
    ;; if we really need to stash it (i.e., VARIABLE is void).
    (condition-case nil
        (default-toplevel-value variable) ; See if it doesn't fail.
      (void-variable (when valspec
                       (put variable 'saved-value valspec))))

So, perhaps the issue isn’t that this property is getting clobbered, but that epg is trying to use those properties directly.

Rather, maybe epg should change from

(and symbol (or (get symbol 'saved-value)
                (get symbol 'customized-value)))

to something like

(and symbol
     (or (get symbol 'theme-value)
         (get symbol 'saved-value)
         (get symbol 'customized-value))
     (symbol-value symbol))

i.e., if there is some form of customization, use the symbol-value, rather than trying to deconstruct all the properties?

sellout avatar Oct 11 '22 05:10 sellout

Although this still doesn’t explain the “CHANGED outside Customize” message. This is because custom-variable-state thinks the variable is 'changed rather than 'themed.

custom-variable-state has a condition

(and (equal comment temp)
     (equal value
            (eval
             (car (custom-variable-theme-value
                   symbol)))))

which, when false, results in 'changed. And it seems like the thing that’s failing with :custom is that (get symbol 'variable-comment) doesn’t match (get symbol 'saved-variable-comment). 'variable-comment isn’t set at all in any of the :custom forms.

It seems like custom-theme-set-variables only sets 'variable-comment if the defcustom form has already been loaded. I removed the conditional from

(and (or now (default-boundp symbol))
     (put symbol 'variable-comment comment))

in that function and now Customize shows me the expected state ('themed) and the comment as I’d expect. I don’t know why that property is conditionalized, though.

sellout avatar Oct 11 '22 06:10 sellout

There seems to be some subtle error in the interaction between use-package, epg and custom. I believe it would be better if we could move this discussion to the Emacs bug tracker to get to the bottom of this.

Could you please open a bug report using M-x report-emacs-bug RET or by emailing the bug-gnu-emacs mailing list?

Thanks.

skangas avatar Nov 27 '22 16:11 skangas

@skangas I think there are two distinct issues here. I don’t think either actually involves use-package, but just the “theme” part of custom. I.e., I think I can come up with a minimal reproduction that exonerates use-package, and I’ll submit to Emacs. I’ll close this with references to those issues once I’ve done that.

sellout avatar Nov 27 '22 18:11 sellout

@sellout Indeed, finding a minimal recipe would be the best way forward. So your plan sounds good to me. Thanks for looking into it.

skangas avatar Nov 28 '22 19:11 skangas