diff --git a/core/core-modules.el b/core/core-modules.el index b9c368385..b38546b86 100644 --- a/core/core-modules.el +++ b/core/core-modules.el @@ -507,54 +507,54 @@ CATEGORY and MODULE can be omitted When this macro is used from inside a module t)) (defmacro after! (targets &rest body) - "Evaluate BODY after TARGETS (packages) have loaded. + "Evaluate BODY after TARGETS have loaded. -This is a wrapper around `with-eval-after-load' that: - -1. Suppresses warnings for disabled packages at compile-time -2. No-ops for TARGETS that are disabled by the user (via `package!') -3. Supports compound TARGETS statements (see below) - -TARGETS is a list of packages in one of these formats: +TARGETS is a symbol or list of them. These are package names, not modes, +functions or variables. It can be: - An unquoted package symbol (the name of a package) (after! helm BODY...) - An unquoted list of package symbols (i.e. BODY is evaluated once both magit and git-gutter have loaded) (after! (magit git-gutter) BODY...) -- An unquoted, nested list of compound package lists, using :or/:any and/or - :and/:all +- An unquoted, nested list of compound package lists, using any combination of + :or/:any and :and/:all (after! (:or package-a package-b ...) BODY...) (after! (:and package-a package-b ...) BODY...) (after! (:and package-a (:or package-b package-c) ...) BODY...) + Without :or/:any/:and/:all, :and/:all are implied. -Note that: -- :or and :any are equivalent -- :and and :all are equivalent -- If these are omitted, :and is implied." +This is a wrapper around `eval-after-load' that: + +1. Suppresses warnings for disabled packages at compile-time +2. No-ops for TARGETS that are disabled by the user (via `package!') +3. Supports compound TARGETS statements (see below) +4. Prevents eager expansion pulling in autoloaded macros all at once" (declare (indent defun) (debug t)) - (unless (and (symbolp targets) - (memq targets (bound-and-true-p doom-disabled-packages))) - (list (if (or (not (bound-and-true-p byte-compile-current-file)) - (dolist (next (doom-enlist targets)) - (unless (keywordp next) - (if (symbolp next) - (require next nil :no-error) - (load next :no-message :no-error))))) - #'progn - #'with-no-warnings) - (if (symbolp targets) - `(with-eval-after-load ',targets ,@body) - (pcase (car-safe targets) - ((or :or :any) - (macroexp-progn - (cl-loop for next in (cdr targets) - collect `(after! ,next ,@body)))) - ((or :and :all) - (dolist (next (cdr targets)) - (setq body `((after! ,next ,@body)))) - (car body)) - (_ `(after! (:and ,@targets) ,@body))))))) + (if (symbolp targets) + (unless (memq targets (bound-and-true-p doom-disabled-packages)) + (list (if (or (not (bound-and-true-p byte-compile-current-file)) + (require next nil 'noerror)) + #'progn + #'with-no-warnings) + (let ((body (macroexp-progn body))) + `(if (featurep ',targets) + ,body + ;; We intentionally avoid `with-eval-after-load' to prevent + ;; eager macro expansion from pulling (or failing to pull) in + ;; autoloaded macros/packages. + (eval-after-load ',targets ',body))))) + (let ((target (car-safe targets))) + (cond ((not (keywordp target)) + `(after! (:and ,@targets) ,@body)) + ((memq target '(:or :any)) + (macroexp-progn + (cl-loop for next in (cdr targets) + collect `(after! ,next ,@body)))) + ((memq target '(:and :all)) + (dolist (next (cdr targets)) + (setq body `((after! ,next ,@body)))) + (car body)))))) (provide 'core-modules) ;;; core-modules.el ends here