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

`let' around `use-package' not changes hook suffix

Open andreyorst opened this issue 6 years ago • 5 comments

I kinda like, that I don't have to type -hook every time in my whole configuration, but some packages use different names for hooks, and I'd like to set those up with different suffix.

This issue is related to #530 and 004ee52fc812938ed42eba8a09e815299ebcead2. Unfortunately I don't understand how to use this customization options as locally as possible. My first thought was to use let around use-package macro, but this did not worked for me (I've omitted some code):

(let ((use-package-hook-name-suffix "-functions"))
  (use-package vterm
    :bind (("C-`" . aorst/vterm-toggle)
           ("C-t" . aorst/vterm-focus))
    :hook (vterm-exit . aorst/kill-vterm)
    :config
    (defun aorst/vterm-toggle (&optional arg)
      "Toggle `vterm' window on and off with the same command." ...)
      (defun aorst/vterm-focus (&optional arg)
        "Focus `vterm' or open one if there's none." ...)
      (defun aorst/kill-vterm (buf)
        "Kill the `*vterm*' buffer after shell exits."
        (when buf (kill-buffer buf))))))

After expansion I have vterm-exit-hook variable, not vterm-exit-functions variable. Is this a bug, or do I have to configure it in a different manner? If I set suffix to nil the default -hook suffix is still used in this example.

My second attempt was to use setq around the use-package:

(setq use-package-hook-name-suffix "-functions")
(use-package vterm
  :bind (("C-`" . aorst/vterm-toggle)
         ("C-t" . aorst/vterm-focus))
  :hook (vterm-exit . aorst/kill-vterm) ...)
(setq use-package-hook-name-suffix "-hook")

And this worked, however I don't like this approach (this is why we have let in the end) and don't quite understand why let doesn't work the same way in this particular example, but seems to work in the test, added in 004ee52fc812938ed42eba8a09e815299ebcead2.

I'm using Emacs 27 built myself from master, use-package melpa version 20191126.2034, and lexical-binding is set to t.

Maybe :hook-suffix could be added?

(use-package package
  :hook-suffix "special"
  :hook (hook . foo))

would produce hook-special.

andreyorst avatar Dec 06 '19 08:12 andreyorst

use-package is a macro, you should careful with it. I can generate Sexp that you want to use below snippet.

(let ((use-package-hook-name-suffix "-functions"))
  (macroexpand
   '(use-package vterm
     :bind (("C-`" . aorst/vterm-toggle)
            ("C-t" . aorst/vterm-focus))
     :hook (vterm-exit . aorst/kill-vterm))))
;;=> (progn
;;     (unless (fboundp 'aorst/vterm-toggle)
;;       (autoload #'aorst/vterm-toggle "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-focus)
;;       (autoload #'aorst/vterm-focus "vterm" nil t))
;;     (unless (fboundp 'aorst/kill-vterm)
;;       (autoload #'aorst/kill-vterm "vterm" nil t))
;;     (add-hook 'vterm-exit-functions #'aorst/kill-vterm)
;;     (bind-keys :package vterm
;;                ("C-`" . aorst/vterm-toggle)
;;                ("C-t" . aorst/vterm-focus)))

So, you can eval above sexp using eval.

(let ((use-package-hook-name-suffix "-functions"))
  (eval
   (macroexpand
    '(use-package vterm
       :bind (("C-`" . aorst/vterm-toggle)
              ("C-t" . aorst/vterm-focus))
       :hook (vterm-exit . aorst/kill-vterm)))))

Or, there is another option, leaf. leaf respect user's input and doesn't modify, you can config vterm-exit hook without any hacks.

(macroexpand-1
 '(leaf vterm
    :bind (("C-`" . aorst/vterm-toggle)
           ("C-t" . aorst/vterm-focus))
    :hook (vterm-exit . aorst/kill-vterm)))
;;=> (prog1 'vterm
;;     (unless (fboundp 'aorst/kill-vterm)
;;       (autoload #'aorst/kill-vterm "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-toggle)
;;       (autoload #'aorst/vterm-toggle "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-focus)
;;       (autoload #'aorst/vterm-focus "vterm" nil t))
;;     (leaf-keys
;;      (("C-`" . aorst/vterm-toggle)
;;       ("C-t" . aorst/vterm-focus)))
;;     (add-hook 'vterm-exit #'aorst/kill-vterm))

conao3 avatar Feb 22 '21 15:02 conao3

Or, there is another option, leaf. leaf respect user's input and doesn't modify, you can config vterm-exit hook without any hacks.

(macroexpand-1
 '(leaf vterm
    :bind (("C-`" . aorst/vterm-toggle)
           ("C-t" . aorst/vterm-focus))
    :hook (vterm-exit . aorst/kill-vterm)))
;;=> (prog1 'vterm
;;     (unless (fboundp 'aorst/kill-vterm)
;;       (autoload #'aorst/kill-vterm "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-toggle)
;;       (autoload #'aorst/vterm-toggle "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-focus)
;;       (autoload #'aorst/vterm-focus "vterm" nil t))
;;     (leaf-keys
;;      (("C-`" . aorst/vterm-toggle)
;;       ("C-t" . aorst/vterm-focus)))
;;     (add-hook 'vterm-exit #'aorst/kill-vterm))

I've never understood the documentation of leaf also, rapid self promoting in every third issue is not very wise move - it is too verbose, and a lot of statements are self-contained (e.g. A is A, use A for A) but not self explanatory, so I don't see myself using leaf, especially when I've already invested quite a bit of time into use-package which also works for me quite well.

Also, the snippet you've provided in the end will not work, as it produces (add-hook 'vterm-exit #'aorst/kill-vterm), which will create vterm-exit hook, which will never be called, because vterm-exit-functions is the correct one. I understand that I can tell leaf to use :hook (vterm-exit-functions . aorst/kill-vterm), and it would produce correct hook, but I can disable automatic -hook suffix insertion magic in use-package without migrating to leaf, to achieve exactly the same result. The issue is sorely a request for adding another keyword property to use-package to make hook suffix configurable on per use-package form, or to solve it in a different way.

andreyorst avatar Feb 22 '21 16:02 andreyorst

OK, sorry to disturb.

Return to your issue, :hook-suffix is hard to use I think.

(use-package package
  :hook-suffix "special"
  :hook (hook . foo) hook2 hook3)

I guess hook2 and hook3 are normal hooks. Naming like hook-special as hook is unusual. But this snippet should expand hook for hook-special, hook2-special, and hook3-special.

I propose :hook* to temporary ignore use-package-hook-name-suffix. How about think?

conao3 avatar Feb 22 '21 16:02 conao3

I propose :hook* to temporary ignore use-package-hook-name-suffix. How about think?

This is actually a neat idea!

andreyorst avatar Feb 22 '21 17:02 andreyorst

Please patch this, you can use :hook* keyword.

master 9f0b539c21d8ca19e8b366f6ce5552c4bc6f3013
Author:     Naoya Yamashita <[email protected]>
AuthorDate: Tue Feb 23 02:08:26 2021 +0900
Commit:     Naoya Yamashita <[email protected]>
CommitDate: Tue Feb 23 02:11:36 2021 +0900

Parent:     a7422fb Merge pull request #910 from minad/improved-unbind
Merged:     master
Contained:  master
Follows:    2.4 (65)

add :hook* keyword

:hook* is similer to :hook, but it generates add-hook sexp igonring
use-package-hook-name-suffix.

1 file changed, 23 insertions(+)
use-package-core.el | 23 +++++++++++++++++++++++

modified   use-package-core.el
@@ -91,6 +91,7 @@
     :magic
     :magic-fallback
     :hook
+    :hook*
     ;; Any other keyword that also declares commands to be autoloaded (such as
     ;; :bind) must appear before this keyword.
     :commands
@@ -1287,6 +1288,28 @@ meaning:
              (if (use-package-non-nil-symbolp syms) (list syms) syms)))))
     (use-package-normalize-commands args))))
 
+;;;; :hook*
+
+(defalias 'use-package-normalize/:hook* 'use-package-normalize/:hook)
+(defalias 'use-package-autoloads/:hook* 'use-package-autoloads/:hook)
+
+(defun use-package-handler/:hook* (name _keyword args rest state)
+  "Generate use-package custom keyword code."
+  (use-package-concat
+   (use-package-process-keywords name rest state)
+   (cl-mapcan
+    #'(lambda (def)
+        (let ((syms (car def))
+              (fun (cdr def)))
+          (when fun
+            (mapcar
+             #'(lambda (sym)
+                 `(add-hook
+                   (quote ,(intern (symbol-name sym)))
+                   (function ,fun)))
+             (if (use-package-non-nil-symbolp syms) (list syms) syms)))))
+    (use-package-normalize-commands args))))
+
 ;;;; :commands
 
 (defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
(macroexpand-1
 '(use-package vterm
    :bind (("C-`" . aorst/vterm-toggle)
           ("C-t" . aorst/vterm-focus))
    :hook* (vterm-exit-functions . aorst/kill-vterm)))
;;=> (progn
;;     (unless (fboundp 'aorst/vterm-toggle)
;;       (autoload #'aorst/vterm-toggle "vterm" nil t))
;;     (unless (fboundp 'aorst/vterm-focus)
;;       (autoload #'aorst/vterm-focus "vterm" nil t))
;;     (unless (fboundp 'aorst/kill-vterm)
;;       (autoload #'aorst/kill-vterm "vterm" nil t))
;;     (add-hook 'vterm-exit-functions #'aorst/kill-vterm)
;;     (bind-keys :package vterm
;;                ("C-`" . aorst/vterm-toggle)
;;                ("C-t" . aorst/vterm-focus)))

conao3 avatar Feb 22 '21 17:02 conao3