Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to set certain variables by :custom in use-package #1836

Open
peromage opened this issue Sep 22, 2023 · 1 comment
Open

Unable to set certain variables by :custom in use-package #1836

peromage opened this issue Sep 22, 2023 · 1 comment

Comments

@peromage
Copy link

peromage commented Sep 22, 2023

Issue type

  • Bug report

Environment

Emacs version: GNU Emacs 29.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.38, cairo version 1.17.8)
Operating System: Arch Linux
Evil version: Evil version 1.15.0
Evil installation type: MELPA
Graphical/Terminal: Wayland/Terminal
Tested in a make emacs session (see CONTRIBUTING.md): No

Reproduction steps

  1. Set variable evil-want-Y-yank-to-eol with use-package
(pewcfg::use-package evil
  :custom
  (evil-want-Y-yank-to-eol t)
  :config
  (evil-mode 1))
  1. Start Emacs

Expected behavior

The value of evil-want-Y-yank-to-eol is t.

Actual behavior

The value of evil-want-Y-yank-to-eol is nil.

Further notes

This seems to be a bug caused by the initializers stored in evil-pending-custom-initialize.

For example, the custom variable evil-want-Y-yank-to-eol has a initializer evil-custom-initialize-pending-reset which adds a initialization form to the list evil-pending-custom-initialize.

evil/evil-vars.el

Lines 623 to 628 in d28206c

(defcustom evil-want-Y-yank-to-eol nil
"Whether `Y' yanks to the end of the line.
The default behavior is to yank the whole line, like Vim."
:group 'evil
:type 'boolean
:initialize #'evil-custom-initialize-pending-reset

That list is iterated by evil-run-pending-custom-initialize.

evil/evil-vars.el

Lines 68 to 74 in d28206c

(defun evil-run-pending-custom-initialize ()
"Execute the pending initializations.
See `evil-pending-custom-initialize'."
(dolist (init evil-pending-custom-initialize)
(apply (car init) (cdr init)))
(remove-hook 'evil-after-load-hook #'evil-run-pending-custom-initialize))
(add-hook 'evil-after-load-hook #'evil-run-pending-custom-initialize)

That function is called by hook evil-after-load-hook whenever package evil is required.

evil/evil.el

Line 154 in d28206c

(run-hooks 'evil-after-load-hook)

If we expand a use-package form

(message "%s" (pp-to-string (macroexpand-all '(use-package evil 
                                                :init
                                                (something in :init)
                                                :config
                                                (something else in :config)
                                                (evil-mode 1)
                                                :custom
                                                (evil-want-Y-yank-to-eol t)))))

Then we have

(progn
  (use-package-ensure-elpa 'evil
                           '(t)
                           'nil)
  (defvar use-package--warning71
    #'(lambda
        (keyword err)
        (let
            ((msg
              (format "%s/%s: %s" 'evil keyword
                      (error-message-string err))))
          (display-warning 'use-package msg :error))))
  (condition-case err
      (progn
        (let
            ((custom--inhibit-theme-enable nil))
          (if
              (memq 'use-package custom-known-themes)
              nil
            (custom-declare-theme 'use-package 'use-package-theme nil
                                  (list))
            (enable-theme 'use-package)
            (setq custom-enabled-themes
                  (remq 'use-package custom-enabled-themes)))
          (custom-theme-set-variables 'use-package
                                      '(evil-want-Y-yank-to-eol t nil nil "Customized with use-package evil")))
        (condition-case err
            (something in :init)
          ((debug error)
           (funcall use-package--warning71 :init err)))
        (if
            (not
             (require 'evil nil t))
            (display-warning 'use-package
                             (format "Cannot load %s" 'evil)
                             :error)
          (condition-case err
              (progn
                (something else in :config)
                (evil-mode 1)
                t)
            ((debug error)
             (funcall use-package--warning71 :config err)))))
    ((debug error)
     (funcall use-package--warning71 :catch err))))

We can see that custom-theme-set-variables is invoked before require. Then our customized value is inevitably overwritten.

Same thing applies to variables

  • evil-search-module
  • evil-visual-newline-commands
  • evil-motions
  • evil-intercept-maps
  • evil-overriding-maps
  • evil-disable-insert-state-bindings
  • evil-want-Y-yank-to-eol

However, a strange thing is, if these variable are set with setq in either :init or :config block of use-package, they work perfectly fine. I think this might because of the setter of these custom variables, which uses set-default. I don't know too much about this mechanism.

Final thought

evil-pending-custom-initialize was added 11 years ago.
b26b286

This piece of code seems stale and not update-to-date with current use cases. I can see a lot custom variables now in Evil do not use this initialization idiom.

Do we still need it?

@peromage
Copy link
Author

Someone asked the same problem back in 2021 but the issue was closed as it was not considered an Evil bug: #1486 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant