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

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

Open bgoodr opened this issue 3 years ago • 2 comments

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

bgoodr avatar Jan 12 '22 06:01 bgoodr

@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.

matta avatar Jan 17 '22 15:01 matta

@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.

bgoodr avatar Jan 23 '22 16:01 bgoodr

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

doolio avatar Nov 14 '22 18:11 doolio

@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.

skangas avatar Nov 14 '22 21:11 skangas

Yes, that is correct. Thanks, @skangas

bgoodr avatar Nov 15 '22 02:11 bgoodr