diff --git a/core/core-lib.el b/core/core-lib.el index 38ac70698..d5f77fb82 100644 --- a/core/core-lib.el +++ b/core/core-lib.el @@ -93,20 +93,28 @@ compilation." (save-silently t)) ,@forms))) +(defvar doom--transient-counter 0) (defmacro add-transient-hook! (hook &rest forms) - "Attaches transient forms to a hook (can also be a function, which will be -advised instead). These forms will be evaluated only once when that -function/hook is first invoked, then it detaches itself." + "Attaches transient forms to a HOOK. + +HOOK can be a quoted hook or a sharp-quoted function (which will be advised). + +These forms will be evaluated once when that function/hook is first invoked, +then it detaches itself." (declare (indent 1)) - (let ((fn (intern (format "doom--transient-hook-%s" hook))) - (append (eq (car forms) :after))) - `(progn - (defun ,fn (&rest _) - ,@forms - ,(cond ((functionp hook) `(advice-remove #',hook #',fn)) - ((symbolp hook) `(remove-hook ',hook #',fn)))) - ,(cond ((functionp hook) `(advice-add #',hook ,(if append :after :before) #',fn)) - ((symbolp hook) `(add-hook ',hook #',fn ,append)))))) + (let ((append (eq (car forms) :after)) + (fn (intern (format "doom-transient-hook-%s" (cl-incf doom--transient-counter))))) + `(when ,hook + (fset ',fn + (lambda (&rest _) + ,@forms + (cond ((functionp ,hook) (advice-remove ,hook #',fn)) + ((symbolp ,hook) (remove-hook ,hook #',fn))) + (unintern ',fn nil))) + (cond ((functionp ,hook) + (advice-add ,hook ,(if append :after :before) #',fn)) + ((symbolp ,hook) + (add-hook ,hook #',fn ,append)))))) (defmacro add-hook! (&rest args) "A convenience macro for `add-hook'. Takes, in order: diff --git a/core/core-popups.el b/core/core-popups.el index 454981d71..c84dc3d05 100644 --- a/core/core-popups.el +++ b/core/core-popups.el @@ -285,7 +285,7 @@ properties." "Force spawned term buffer to share with the eshell popup (if necessary)." (when (doom-popup-p) (set-window-dedicated-p nil nil) - (add-transient-hook! eshell-query-kill-processes :after + (add-transient-hook! #'eshell-query-kill-processes :after (set-window-dedicated-p nil t))) (apply orig-fn args)) (advice-add #'eshell-exec-visual :around #'doom*eshell-undedicate-popup)) diff --git a/core/core-projects.el b/core/core-projects.el index 9c016183e..1730a9528 100644 --- a/core/core-projects.el +++ b/core/core-projects.el @@ -151,7 +151,7 @@ see if NAME should be activated. (add-hook! ,name (run-hook-with-args 'doom-project-hook ',name)) ,(when init-form - `(add-transient-hook! ',(intern-soft (format "%s-hook" name)) + `(add-transient-hook! ',(intern (format "%s-hook" name)) ,init-form))))) (provide 'core-projects) diff --git a/modules/feature/snippets/config.el b/modules/feature/snippets/config.el index c51db88be..43ae6397e 100644 --- a/modules/feature/snippets/config.el +++ b/modules/feature/snippets/config.el @@ -13,7 +13,7 @@ :init ;; Ensure `yas-reload-all' is called as late as possible. Other modules could ;; have additional configuration for yasnippet. For example, file-templates. - (add-transient-hook! yas-minor-mode-hook (yas-reload-all)) + (add-transient-hook! 'yas-minor-mode-hook (yas-reload-all)) (add-hook! (text-mode prog-mode snippet-mode) #'yas-minor-mode-on) diff --git a/modules/ui/doom-modeline/config.el b/modules/ui/doom-modeline/config.el index 4886876cd..af30220b1 100644 --- a/modules/ui/doom-modeline/config.el +++ b/modules/ui/doom-modeline/config.el @@ -36,7 +36,7 @@ (def-package! evil-anzu :when (featurep 'evil) :init - (add-transient-hook! evil-ex-start-search (require 'evil-anzu)) + (add-transient-hook! #'evil-ex-start-search (require 'evil-anzu)) :config (setq anzu-cons-mode-line-p nil anzu-minimum-input-length 1 diff --git a/test/core/test-core-lib.el b/test/core/test-core-lib.el index 357e317d2..763c7b21d 100644 --- a/test/core/test-core-lib.el +++ b/test/core/test-core-lib.el @@ -44,14 +44,14 @@ ;; `add-transient-hook!' (ert-deftest transient-hooks () (let (hooks value) - (add-transient-hook! hooks (setq value t)) + (add-transient-hook! 'hooks (setq value t)) (run-hooks 'hooks) (should (eq value t)) (should (null hooks)))) (ert-deftest transient-function () (let (value) - (add-transient-hook! ignore (setq value (not value))) + (add-transient-hook! #'ignore (setq value (not value))) (ignore t) (should (eq value t)) ;; repeat to ensure it was only run once