jwiegley / use-package

A use-package declaration for simplifying your .emacs
https://jwiegley.github.io/use-package
GNU General Public License v3.0
4.39k stars 259 forks source link

:bind does not defer loading but also requires :commands to be defined #971

Closed bgoodr closed 1 year ago

bgoodr commented 2 years ago

The manual for use-package implies that :bind should be sufficient to defer loading the package:

4.16 ‘:mode’, ‘:interpreter’
============================

Similar to ‘:bind’, you can use ‘:mode’ and ‘:interpreter’ to establish
a deferred binding within the ‘auto-mode-alist’ and
‘interpreter-mode-alist’ variables.  The specifier to either keyword can
be a cons cell, a list of cons cells, or a string or regexp:

     (use-package ruby-mode
       :mode "\\.rb\\'"
       :interpreter "ruby")

     ;; The package is "python" but the mode is "python-mode":
     (use-package python
       :mode ("\\.py\\'" . python-mode)
       :interpreter ("python" . python-mode))

   If you aren’t using ‘:commands’, ‘:bind’, ‘:bind*’, ‘:bind-keymap’,
‘:bind-keymap*’, ‘:mode’, or ‘:interpreter’ (all of which imply
‘:defer’; see the docstring for ‘use-package’ for a brief description of
each), you can still defer loading with the ‘:defer’ keyword:

     (use-package ace-jump-mode
       :defer t
       :init
       (autoload 'ace-jump-mode "ace-jump-mode" nil t)
       (bind-key "C-." 'ace-jump-mode))

   This does exactly the same thing as the following:

     (use-package ace-jump-mode
       :bind ("C-." . ace-jump-mode))

That does not happen as I expect it to: The use-package call loads the package immediately, and does not defer it unless I also specify the :commands directive. I should not have to specify both :bind and :commands, as I've already specified the :bind. I should not have to specify the function bound to the keys twice in the same use-package construct.

Steps to reproduce:

Add the following to .emacs.d/init.el:

(use-package my-test-package
  :load-path "my-elisp/general"
  ;; :commands (my-test-package-function)
  :bind (("C-c d" . 'my-test-package-function)))

Notice the :commands is commented out above.

Add this to your path under a my-elisp/general that is in your load-path:

(message "my-test-package.el was loaded")

(defun my-test-package-function ()
  (interactive)
  (message "my-test-package-function called"))

(provide 'my-test-package)

Invoke emacs. Then invoke C-h e to see the "my-test-package.el was loaded".

Uncomment out the :commands directive above, and retest. Now the package is not loaded since "my-test-package.el was loaded" does not then show up right away. Then type C-c d followed by C-h e, and then see both the "my-test-package.el was loaded" message and the "my-test-package-function called" message as expected.

GNU Emacs version 27.2 use-package version: 20210207.1926

matta commented 2 years ago

@bgoodr , try this:

(use-package my-test-package
  :bind (("C-c d" . my-test-package-function)))

I.e. don't quote my-test-package-function in the form given to :bind.

This other approach fixes it too:

(use-package my-test-package
  :bind ("C-c d" . 'my-test-package-function))

I.e. remove the parentheses around the form given to :bind but continue to quote my-test-package-function. I think this is the less preferred workaround. All the use-package documentation shows plain, unquoted, symbols in :bind forms.

I do think there is a bug here -- it would be best if the :bind form was consistent with respect to how it treats quoted symbols -- but this should get you going.

By the way, one way to debug this is M-x pp-macroexpand-last-sexp. Use it with the cursor at the end of the use-package form and it will pop up a buffer with the code the macro expands to.

bgoodr commented 2 years ago

@matta Very nice sleuthing, that. Thank you!

Removing the single-quote in front of the function name inside the :bind is the preferred fix for me. And, I agree with you that it could be made more clear somewhere in the docs.

And the hint about M-x pp-macroexpand-last-sexp is mighty helpful. What I had been doing is using a lisp-interaction-mode buffer and using (pp (macro-expand-1 '(my macro form here))) with C-j to repeatedly expand it, but didn't go deeper than that to see what it was expanding into, using macro-expand-all instead of macro-expand-1.

doolio commented 1 year ago

@bgoodr it seems you resolved your issue. Can this issue therefore be closed?

skangas commented 1 year ago

@bgoodr it seems you resolved your issue. Can this issue therefore be closed?

Having read the discussion, I'm going to assume the answer is "yes" and close it for now.

But this is just tentative; please let us know if there is more to do here and we can reopen. Thanks.

bgoodr commented 1 year ago

Yes, that is correct. Thanks, @skangas