From 9ab797cccdcb8bd583c0e3148e1aeb251bf05fec Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 3 Dec 2017 03:07:30 -0800 Subject: [PATCH] A great deal of internal reorganization and simplification All handlers now address their own domain of work; :after has become safer; keyword normalization is multi-stage process; setting use-package-verbose to `debug' produces useful output in the *use-package* buffer in the case of load time errors; use-package errors (even internal) won't stop Emacs from starting (though a serious internal bug that errors out every use-package form may stop anything from being configured!); and more. --- etc/USE-PACKAGE-NEWS | 6 + lisp/use-package/use-package.el | 875 ++++++++++++--------- test/lisp/use-package/use-package-tests.el | 420 +++++----- 3 files changed, 715 insertions(+), 586 deletions(-) diff --git a/etc/USE-PACKAGE-NEWS b/etc/USE-PACKAGE-NEWS index 06adac97188..c65aae64f10 100644 --- a/etc/USE-PACKAGE-NEWS +++ b/etc/USE-PACKAGE-NEWS @@ -18,6 +18,12 @@ - The `:defer-install` keyword has been remove. It may reappear as an add-on module for use-package in a future release. See issue #442 for more details. +- The ordering of several elements of `use-package-keywords' have changed; if + you have this customized you will need to rework your changes. + +- There is no longer a `use-package-debug` option, since `use-package-verbose` + already has the possible value of `debug`. + ### Other changes - Upgrade license to GPL 3. diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el index bfaac24e48e..3dab8ec8521 100644 --- a/lisp/use-package/use-package.el +++ b/lisp/use-package/use-package.el @@ -67,11 +67,6 @@ then the expanded macros do their job silently." (const :tag "Debug" debug)) :group 'use-package) -(defcustom use-package-debug nil - "Whether to display use-package expansions in a *use-package* buffer." - :type 'boolean - :group 'use-package) - (defcustom use-package-check-before-init nil "If non-nil, check that package exists before executing its `:init' block. The check is performed by looking for the module using `locate-library'." @@ -136,15 +131,15 @@ the user specified." '(:disabled :pin :ensure - :if - :when - :unless + :if :when :unless :requires :load-path - :defines - :functions - :preface :no-require + :preface :defines :functions + :after + :custom + :custom-face + :init :bind :bind* :bind-keymap @@ -153,14 +148,15 @@ the user specified." :mode :magic :magic-fallback - :commands :hook + ;; Any other keyword that also declares commands to be autoloaded (such as + ;; :bind) must appear before this keyword. + :commands :defer - :custom - :custom-face - :init - :after :demand + :load + ;; This must occur almost last; the only forms which should appear after + ;; are those that must happen directly after the config forms. :config :diminish :delight) @@ -209,8 +205,23 @@ The default value uses package.el to install the package." :group 'use-package) (defcustom use-package-defaults - '((:config '(t) t) - (:ensure use-package-always-ensure use-package-always-ensure) + '((:config '(t) t) ; this '(t) has special meaning; see + ; the handler for :config + (:init nil t) + (:defer use-package-always-defer + (lambda (args) + (and use-package-always-defer + (not (plist-member args :defer)) + (not (plist-member args :demand))))) + (:demand use-package-always-demand + (lambda (args) + (and use-package-always-demand + (not (plist-member args :defer)) + (not (plist-member args :demand))))) + (:ensure use-package-always-ensure + (lambda (args) + (and use-package-always-ensure + (not (plist-member args :load-path))))) (:pin use-package-always-pin use-package-always-pin)) "Alist of default values for `use-package' keywords. Each entry in the alist is a list of three elements. The first @@ -219,9 +230,19 @@ that can be evaluated to get the default value. The third element is a form that can be evaluated to determine whether or not to assign a default value; if it evaluates to nil, then the default value is not assigned even if the keyword is not present in the -`use-package' form." - :type '(repeat (list symbol sexp sexp))) +`use-package' form. This third element may also be a function, in +which case it receives the list of keywords (in normalized form), +and should return nil or t according to whether defaulting should +be attempted." + :type `(repeat + (list (choice :tag "Keyword" + ,@(mapcar #'(lambda (k) (list 'const k)) + use-package-keywords)) + (choice :tag "Default value" sexp) + (choice :tag "Enable if non-nil" sexp function))) + :group 'use-package) +;;; jww (2017-12-02): This should be in the :set for the option. (when use-package-enable-imenu-support (eval-after-load 'lisp-mode `(let ((sym-regexp (or (bound-and-true-p lisp-mode-symbol-regexp) @@ -308,56 +329,35 @@ whether it's a string or symbol." `(load ,name ,noerror) `(require ',name nil ,noerror))) -(defun use-package-expand (name label form) - "FORM is a list of forms, so `((foo))' if only `foo' is being called." - (declare (indent 1)) - (when form - (if use-package-expand-minimally - form - (let ((err (make-symbol "err"))) - (list - `(condition-case-unless-debug ,err - ,(macroexp-progn form) - (error - (ignore - (display-warning 'use-package - (format "%s %s: %s" - ,name ,label (error-message-string ,err)) - :error))))))))) - -(put 'use-package-expand 'lisp-indent-function 'defun) - (defun use-package-hook-injector (name-string keyword body) "Wrap pre/post hook injections around a given keyword form. ARGS is a list of forms, so `((foo))' if only `foo' is being called." (if (not use-package-inject-hooks) - (use-package-expand name-string (format "%s" keyword) body) + body (let ((keyword-name (substring (format "%s" keyword) 1))) - `((when ,(macroexp-progn - (use-package-expand name-string (format "pre-%s hook" keyword) - `((run-hook-with-args-until-failure - ',(intern (concat "use-package--" name-string - "--pre-" keyword-name "-hook")))))) - ,(macroexp-progn - (use-package-expand name-string (format "%s" keyword) body)) - ,(macroexp-progn - (use-package-expand name-string (format "post-%s hook" keyword) - `((run-hooks - ',(intern (concat "use-package--" name-string - "--post-" keyword-name "-hook"))))))))))) + `((when (run-hook-with-args-until-failure + ',(intern (concat "use-package--" name-string + "--pre-" keyword-name "-hook"))) + ,@body + (run-hooks + ',(intern (concat "use-package--" name-string + "--post-" keyword-name "-hook")))))))) (defun use-package--require (name &optional no-require body) - (use-package--with-elapsed-timer - (format "Loading package %s" name) - (if use-package-expand-minimally - (use-package-concat - (unless no-require - (list (use-package-load-name name))) - body) - (if no-require - body + (if use-package-expand-minimally + (use-package-concat + (unless no-require + (list (use-package-load-name name))) + body) + (if no-require + body + (use-package--with-elapsed-timer + (format "Loading package %s" name) `((if (not ,(use-package-load-name name t)) - (ignore (message (format "Cannot load %s" ',name))) + (ignore + (display-warning 'use-package + (format "Cannot load %s" ',name) + :error)) ,@body)))))) (defun use-package--with-elapsed-timer (text body) @@ -408,6 +408,18 @@ This is in contrast to merely setting it to 0." (setq plist (cddr plist))) p)) +(defun use-package-plist-delete-first (plist property) + "Delete PROPERTY from PLIST. +This is in contrast to merely setting it to 0." + (let (p) + (while plist + (if (eq property (car plist)) + (setq p (nconc p (cddr plist)) + plist nil) + (setq p (nconc p (list (car plist) (cadr plist))) + plist (cddr plist)))) + p)) + (defun use-package-split-list (pred xs) (let ((ys (list nil)) (zs (list nil)) flip) (dolist (x xs) @@ -445,7 +457,7 @@ This is in contrast to merely setting it to 0." (defsubst use-package-concat (&rest elems) "Delete all empty lists from ELEMS (nil or (list nil)), and append them." - (apply #'nconc (delete nil (delete (list nil) elems)))) + (apply #'append (delete nil (delete (list nil) elems)))) (defsubst use-package--non-nil-symbolp (sym) (and sym (symbolp sym))) @@ -484,28 +496,32 @@ This is in contrast to merely setting it to 0." (t (error "Not recognized as regular expression: %s" re)))) -(defun use-package-normalize-plist (name input) - "Given a pseudo-plist, normalize it to a regular plist." - (unless (null input) +(defun use-package-normalize-plist (name input &optional plist merge-function) + "Given a pseudo-plist, normalize it to a regular plist. +The normalized key/value pairs from input are added to PLIST, +extending any keys already present." + (when input (let* ((keyword (car input)) (xs (use-package-split-list #'keywordp (cdr input))) (args (car xs)) (tail (cdr xs)) (normalizer (intern (concat "use-package-normalize/" (symbol-name keyword)))) - (arg - (cond - ((eq keyword :disabled) - (use-package-normalize-plist name tail)) - ((functionp normalizer) - (funcall normalizer name keyword args)) - ((= (length args) 1) - (car args)) - (t - args)))) + (arg (cond ((functionp normalizer) + (funcall normalizer name keyword args)) + ((= (length args) 1) + (car args)) + (t + args)))) (if (memq keyword use-package-keywords) - (cons keyword - (cons arg (use-package-normalize-plist name tail))) + (progn + (setq plist (use-package-normalize-plist + name tail plist merge-function)) + (plist-put plist keyword + (if (plist-member plist keyword) + (funcall merge-function keyword + arg (plist-get plist keyword)) + arg))) (ignore (display-warning 'use-package (format "Unrecognized keyword: %s" keyword) @@ -540,6 +556,16 @@ next value for the STATE." (put 'use-package-process-keywords 'lisp-indent-function 'defun) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :disabled +;; + +(defalias 'use-package-normalize/:disabled 'ignore) + +(defun use-package-handler/:disabled (name keyword arg rest state) + (use-package-process-keywords name rest state)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; :pin @@ -560,13 +586,13 @@ next value for the STATE." (defun use-package-normalize/:pin (name keyword args) (use-package-only-one (symbol-name keyword) args - (lambda (label arg) - (cond - ((stringp arg) arg) - ((use-package--non-nil-symbolp arg) (symbol-name arg)) - (t - (use-package-error - ":pin wants an archive name (a string)")))))) + #'(lambda (label arg) + (cond + ((stringp arg) arg) + ((use-package--non-nil-symbolp arg) (symbol-name arg)) + (t + (use-package-error + ":pin wants an archive name (a string)")))))) (eval-when-compile (defvar package-pinned-packages) @@ -619,12 +645,12 @@ manually updated package." (if (null args) t (use-package-only-one (symbol-name keyword) args - (lambda (label arg) - (if (symbolp arg) - arg - (use-package-error - (concat ":ensure wants an optional package name " - "(an unquoted symbol name)"))))))) + #'(lambda (label arg) + (if (symbolp arg) + arg + (use-package-error + (concat ":ensure wants an optional package name " + "(an unquoted symbol name)"))))))) (defun use-package-ensure-elpa (name ensure state &optional no-refresh) (let ((package @@ -675,6 +701,7 @@ manually updated package." (defsubst use-package-normalize-value (label arg) "Normalize a value." (cond ((null arg) nil) + ((eq t arg) t) ((use-package--non-nil-symbolp arg) `(symbol-value ',arg)) ((functionp arg) @@ -756,9 +783,9 @@ If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list." (let ((body (use-package-process-keywords name rest state))) (if (null requires) body - `((when ,(if (listp requires) + `((when ,(if (> (length requires) 1) `(not (member nil (mapcar #'featurep ',requires))) - `(featurep ',requires)) + `(featurep ',(car requires))) ,@body))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -809,9 +836,7 @@ If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list." (defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate) (defun use-package-handler/:no-require (name keyword arg rest state) - ;; This keyword has no functional meaning. - (use-package-process-keywords name rest - (plist-put state :no-require t))) + (use-package-process-keywords name rest state)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -840,6 +865,26 @@ If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list." `((eval-and-compile ,@arg))) body))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :defines +;; + +(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist) + +(defun use-package-handler/:defines (name keyword arg rest state) + (use-package-process-keywords name rest state)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :functions +;; + +(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist) + +(defun use-package-handler/:functions (name keyword arg rest state) + (use-package-process-keywords name rest state)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; :bind, :bind* @@ -948,18 +993,18 @@ representing symbols (that may need to be autloaded)." (defun use-package-normalize-binder (name keyword args) (use-package-as-one (symbol-name keyword) args - (lambda (label arg) - (unless (consp arg) - (use-package-error - (concat label " a ( . )" - " or list of these"))) - (use-package-normalize-pairs - #'(lambda (k) - (pcase k - ((pred stringp) t) - ((pred vectorp) t))) - #'(lambda (v) (use-package--recognize-function v t #'stringp)) - name label arg)))) + #'(lambda (label arg) + (unless (consp arg) + (use-package-error + (concat label " a ( . )" + " or list of these"))) + (use-package-normalize-pairs + #'(lambda (k) + (pcase k + ((pred stringp) t) + ((pred vectorp) t))) + #'(lambda (v) (use-package--recognize-function v t #'stringp)) + name label arg)))) (defalias 'use-package-normalize/:bind 'use-package-normalize-binder) (defalias 'use-package-normalize/:bind* 'use-package-normalize-binder) @@ -971,8 +1016,8 @@ representing symbols (that may need to be autloaded)." (use-package-concat (use-package-process-keywords name (use-package-sort-keywords - (use-package-plist-maybe-put rest :defer t)) - (use-package-plist-append state :commands commands)) + (use-package-plist-append rest :commands commands)) + state) `((ignore (,(if bind-macro bind-macro 'bind-keys) :package ,name ,@nargs)))))) @@ -1031,10 +1076,7 @@ representing symbols (that may need to be autloaded)." ',(cdr binding) ',(use-package-as-symbol name) ,override)))) arg))) (use-package-concat - (use-package-process-keywords name - (use-package-sort-keywords - (use-package-plist-maybe-put rest :defer t)) - state) + (use-package-process-keywords name rest state) `((ignore ,@form))))) (defun use-package-handler/:bind-keymap* (name keyword arg rest state) @@ -1057,20 +1099,18 @@ representing symbols (that may need to be autloaded)." "Handle keywords which add regexp/mode pairs to an alist." (cl-destructuring-bind (nargs . commands) (use-package--normalize-commands args) - (let ((form - (mapcar - #'(lambda (thing) - `(add-to-list - ',alist - ',(cons (use-package-normalize-regex (car thing)) - (cdr thing)))) - nargs))) - (use-package-concat - (use-package-process-keywords name - (use-package-sort-keywords - (use-package-plist-maybe-put rest :defer t)) - (use-package-plist-append state :commands commands)) - `((ignore ,@form)))))) + (use-package-concat + (mapcar + #'(lambda (thing) + `(add-to-list + ',alist + ',(cons (use-package-normalize-regex (car thing)) + (cdr thing)))) + nargs) + (use-package-process-keywords name + (use-package-sort-keywords + (use-package-plist-append rest :commands commands)) + state)))) (defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode) @@ -1109,37 +1149,74 @@ representing symbols (that may need to be autloaded)." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;;; :commands -;; - -(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist) - -(defun use-package-handler/:commands (name keyword arg rest state) - ;; The actual processing for commands is done in :defer - (use-package-process-keywords name - (use-package-sort-keywords - (use-package-plist-maybe-put rest :defer t)) - (use-package-plist-append state :commands arg))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;;; :defines +;;; :hook ;; -(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist) +(defun use-package-normalize/:hook (name keyword args) + (use-package-as-one (symbol-name keyword) args + #'(lambda (label arg) + (unless (or (use-package--non-nil-symbolp arg) (consp arg)) + (use-package-error + (concat label " a or ( . )" + " or list of these"))) + (use-package-normalize-pairs + #'(lambda (k) + (or (use-package--non-nil-symbolp k) + (and k (let ((every t)) + (while (and every k) + (if (and (consp k) + (use-package--non-nil-symbolp (car k))) + (setq k (cdr k)) + (setq every nil))) + every)))) + #'use-package--recognize-function + name label arg)))) -(defun use-package-handler/:defines (name keyword arg rest state) - (use-package-process-keywords name rest state)) +(defun use-package-handler/:hook (name keyword args rest state) + "Generate use-package custom keyword code." + (cl-destructuring-bind (nargs . commands) + (use-package--normalize-commands args) + (use-package-concat + (cl-mapcan + #'(lambda (def) + (let ((syms (car def)) + (fun (cdr def))) + (when fun + (mapcar + #'(lambda (sym) + `(add-hook (quote ,(intern (format "%s-hook" sym))) + (function ,fun))) + (if (use-package--non-nil-symbolp syms) (list syms) syms))))) + nargs) + (use-package-process-keywords name + (use-package-sort-keywords + (use-package-plist-append rest :commands commands)) + state)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;;; :functions +;;; :commands ;; -(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist) +(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist) -(defun use-package-handler/:functions (name keyword arg rest state) - (use-package-process-keywords name rest state)) +(defun use-package-handler/:commands (name keyword arg rest state) + (use-package-concat + (unless (plist-get state :demand) + ;; Since we deferring load, establish any necessary autoloads, and also + ;; keep the byte-compiler happy. + (let ((name-string (use-package-as-string name))) + (cl-mapcan + #'(lambda (command) + (when (symbolp command) + (append + `((unless (fboundp ',command) + (autoload #',command ,name-string nil t))) + (when (bound-and-true-p byte-compile-current-file) + `((eval-when-compile + (declare-function ,command ,name-string))))))) + (delete-dups arg)))) + (use-package-process-keywords name rest state))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -1149,77 +1226,89 @@ representing symbols (that may need to be autloaded)." (defalias 'use-package-normalize/:defer 'use-package-normalize-predicate) (defun use-package-handler/:defer (name keyword arg rest state) - (let ((body (use-package-process-keywords name rest - (plist-put state :deferred t))) - (name-string (use-package-as-string name))) + (let ((body (use-package-process-keywords name rest state))) (use-package-concat ;; Load the package after a set amount of idle time, if the argument to ;; `:defer' was a number. (when (numberp arg) `((run-with-idle-timer ,arg nil #'require ',(use-package-as-symbol name) nil t))) - ;; Since we deferring load, establish any necessary autoloads, and also - ;; keep the byte-compiler happy. - (cl-mapcan - #'(lambda (command) - (when (symbolp command) - (append - `((unless (fboundp ',command) - (autoload #',command ,name-string nil t))) - (when (bound-and-true-p byte-compile-current-file) - `((eval-when-compile - (declare-function ,command ,name-string))))))) - (delete-dups (plist-get state :commands))) - - body))) - + (if (or (not arg) (null body)) + body + (list (use-package--require-after-load + name (macroexp-progn body))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; :after ;; -(defalias 'use-package-normalize/:after 'use-package-normalize-recursive-symlist) +(defun use-package-normalize/:after (name keyword args) + (setq args (use-package-normalize-recursive-symlist name keyword args)) + (if (consp args) + args + (list args))) -(defun use-package-require-after-load (features) - "Return form for after any of FEATURES require NAME." +(defun use-package--after-count-uses (features) + "Count the number of time the body would appear in the result." (pcase features ((and (pred use-package--non-nil-symbolp) feat) - `(lambda (body) - (list 'eval-after-load (list 'quote ',feat) - (list 'quote body)))) - (`(,(or :or :any) . ,rest) - `(lambda (body) - (append (list 'progn) - (mapcar (lambda (form) - (funcall form body)) - (list ,@(use-package-require-after-load rest)))))) - (`(,(or :and :all) . ,rest) - `(lambda (body) - (let ((result body)) - (dolist (form (list ,@(use-package-require-after-load rest))) - (setq result (funcall form result))) - result))) + 1) + (`(,(or `:or `:any) . ,rest) + (let ((num 0)) + (dolist (next rest) + (setq num (+ num (use-package--after-count-uses next)))) + num)) + (`(,(or `:and `:all) . ,rest) + (apply #'max (mapcar #'use-package--after-count-uses rest))) (`(,feat . ,rest) - (if rest - (cons (use-package-require-after-load feat) - (use-package-require-after-load rest)) - (list (use-package-require-after-load feat)))))) + (use-package--after-count-uses (cons :all (cons feat rest)))))) + +(defun use-package--require-after-load (features body) + "Generate `eval-after-load' statements to represents FEATURES. +FEATURES is a list containing keywords `:and' and `:all', where +no keyword implies `:all'." + (pcase features + ((and (pred use-package--non-nil-symbolp) feat) + `(eval-after-load ',feat + ,(if (member (car body) '(quote backquote \' \`)) + body + (list 'quote body)))) + (`(,(or `:or `:any) . ,rest) + (macroexp-progn + (mapcar #'(lambda (x) (use-package--require-after-load x body)) rest))) + (`(,(or `:and `:all) . ,rest) + (dolist (next rest) + (setq body (use-package--require-after-load next body))) + body) + (`(,feat . ,rest) + (use-package--require-after-load (cons :all (cons feat rest)) body)))) + +(defun use-package--memoize (f arg) + "Ensure the macro-expansion of F applied to ARG evaluates ARG +no more than once." + (let ((loaded (gensym "use-package--loaded")) + (result (gensym "use-package--result")) + (next (gensym "use-package--next"))) + `((lexical-let (,loaded ,result) + (lexical-let ((,next (lambda () + (if ,loaded + ,result + (setq ,loaded t) + (setq ,result ,arg))))) + ,(funcall f ``(funcall ,,next))))))) (defun use-package-handler/:after (name keyword arg rest state) - (let ((body (use-package-process-keywords name rest - (plist-put state :deferred t))) - (name-string (use-package-as-string name))) - (if (and (consp arg) - (not (memq (car arg) '(:or :any :and :all)))) - (setq arg (cons :all arg))) - (use-package-concat - (when arg - (list (funcall - (use-package-require-after-load arg) - (macroexp-progn - (use-package--require name))))) - body))) + (let ((body (use-package-process-keywords name rest state)) + (uses (use-package--after-count-uses arg))) + (if (or (null uses) (null body)) + body + (if (<= uses 1) + (list (use-package--require-after-load + arg (list 'quote (macroexp-progn body)))) + (use-package--memoize + (apply-partially #'use-package--require-after-load arg) + (macroexp-progn body)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -1229,105 +1318,7 @@ representing symbols (that may need to be autloaded)." (defalias 'use-package-normalize/:demand 'use-package-normalize-predicate) (defun use-package-handler/:demand (name keyword arg rest state) - (use-package-process-keywords name rest - (use-package-plist-delete state :deferred))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;;; :init -;; - -(defalias 'use-package-normalize/:init 'use-package-normalize-forms) - -(defun use-package-handler/:init (name keyword arg rest state) - (let ((body (use-package-process-keywords name rest state))) - (use-package-concat - ;; The user's initializations - (let ((init-body - (use-package-hook-injector (use-package-as-string name) - :init arg))) - (if use-package-check-before-init - `((if (locate-library ,(use-package-as-string name)) - ,(macroexp-progn init-body))) - init-body)) - body))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;;; :config -;; - -(defalias 'use-package-normalize/:config 'use-package-normalize-forms) - -(defun use-package-handler/:config (name keyword arg rest state) - (let* ((body (use-package-process-keywords name rest state)) - (name-symbol (use-package-as-symbol name)) - (config-body - (if (equal arg '(t)) - body - (use-package--with-elapsed-timer - (format "Configuring package %s" name-symbol) - (use-package-concat - (use-package-hook-injector (symbol-name name-symbol) - :config arg) - body - (list t)))))) - (if (plist-get state :deferred) - (unless (or (null config-body) (equal config-body '(t))) - `((eval-after-load ,(if (symbolp name) `',name name) - ',(macroexp-progn config-body)))) - (use-package--require name (plist-get state ':no-require) - config-body)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;;; :hook -;; - -(defun use-package-normalize/:hook (name keyword args) - (use-package-as-one (symbol-name keyword) args - (lambda (label arg) - (unless (or (use-package--non-nil-symbolp arg) (consp arg)) - (use-package-error - (concat label " a or ( . )" - " or list of these"))) - (use-package-normalize-pairs - #'(lambda (k) - (or (use-package--non-nil-symbolp k) - (and k (let ((every t)) - (while (and every k) - (if (and (consp k) - (use-package--non-nil-symbolp (car k))) - (setq k (cdr k)) - (setq every nil))) - every)))) - #'use-package--recognize-function - name label arg)))) - -(defun use-package-handler/:hook (name keyword args rest state) - "Generate use-package custom keyword code." - (cl-destructuring-bind (nargs . commands) - (use-package--normalize-commands args) - (use-package-concat - (use-package-process-keywords name - (if commands - (use-package-sort-keywords - (use-package-plist-maybe-put rest :defer t)) - rest) - (if commands - (use-package-plist-append state :commands commands) - state)) - (cl-mapcan - (lambda (def) - (let ((syms (car def)) - (fun (cdr def))) - (when fun - (mapcar - #'(lambda (sym) - `(add-hook (quote ,(intern (format "%s-hook" sym))) - (function ,fun))) - (if (use-package--non-nil-symbolp syms) (list syms) syms))))) - nargs)))) + (use-package-process-keywords name rest state)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -1337,28 +1328,27 @@ representing symbols (that may need to be autloaded)." (defun use-package-normalize/:custom (name keyword args) "Normalize use-package custom keyword." (use-package-as-one (symbol-name keyword) args - (lambda (label arg) - (unless (listp arg) - (use-package-error - (concat label " a ( [comment])" - " or list of these"))) - (if (use-package--non-nil-symbolp (car arg)) - (list arg) - arg)))) + #'(lambda (label arg) + (unless (listp arg) + (use-package-error + (concat label " a ( [comment])" + " or list of these"))) + (if (use-package--non-nil-symbolp (car arg)) + (list arg) + arg)))) (defun use-package-handler/:custom (name keyword args rest state) "Generate use-package custom keyword code." - (let ((body (use-package-process-keywords name rest state))) - (use-package-concat - (mapcar (lambda (def) + (use-package-concat + (mapcar #'(lambda (def) (let ((variable (nth 0 def)) (value (nth 1 def)) (comment (nth 2 def))) (unless (and comment (stringp comment)) (setq comment (format "Customized with use-package %s" name))) `(customize-set-variable (quote ,variable) ,value ,comment))) - args) - body))) + args) + (use-package-process-keywords name rest state))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -1382,12 +1372,66 @@ representing symbols (that may need to be autloaded)." (defun use-package-handler/:custom-face (name keyword args rest state) "Generate use-package custom-face keyword code." + (use-package-concat + (mapcar #'(lambda (def) `(custom-set-faces (quote ,def))) args) + (use-package-process-keywords name rest state))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :init +;; + +(defalias 'use-package-normalize/:init 'use-package-normalize-forms) + +(defun use-package-handler/:init (name keyword arg rest state) + (use-package-concat + ;; The user's initializations + (let ((init-body + (use-package-hook-injector (use-package-as-string name) + :init arg))) + (if use-package-check-before-init + `((if (locate-library ,(use-package-as-string name)) + ,(macroexp-progn init-body))) + init-body)) + (use-package-process-keywords name rest state))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :load +;; + +(defun use-package-normalize/:load (name keyword args) + (setq args (use-package-normalize-recursive-symlist name keyword args)) + (if (consp args) + args + (list args))) + +(defun use-package-handler/:load (name keyword arg rest state) (let ((body (use-package-process-keywords name rest state))) - (use-package-concat - (mapcar (lambda (def) - `(custom-set-faces (quote ,def))) - args) - body))) + (dolist (pkg arg) + (setq body (use-package--require pkg nil body))) + body)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; :config +;; + +(defalias 'use-package-normalize/:config 'use-package-normalize-forms) + +(defun use-package-handler/:config (name keyword arg rest state) + (let* ((body (use-package-process-keywords name rest state)) + (name-symbol (use-package-as-symbol name))) + (if (or (null arg) + (equal arg '(t))) + body + (use-package--with-elapsed-timer + (format "Configuring package %s" name-symbol) + (use-package-concat + (use-package-hook-injector + (symbol-name name-symbol) :config arg) + body + (list t)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -1487,6 +1531,119 @@ representing symbols (that may need to be autloaded)." ;;; The main macro ;; +(defun use-package-unalias-keywords (name args) + (setq args (cl-nsubstitute :if :when args)) + (let (temp) + (while (setq temp (plist-get args :unless)) + (setq args (use-package-plist-delete-first args :unless) + args (append args `(:if (not ,temp)))))) + args) + +(defun use-package--merge-keys (key new old) + (pcase key + (`:if `(and ,new ,old)) + (`:after `(:all ,new ,old)) + (`:defer old) + (_ (append new old)))) + +(defun use-package-normalize-keywords (name args) + (let* ((name-symbol (if (stringp name) (intern name) name)) + (name-string (symbol-name name-symbol))) + + ;; Reduce the set of keywords down to its most fundamental expression. + (setq args (use-package-unalias-keywords name-symbol args)) + + ;; Normalize keyword values, coalescing multiple occurrences. + (setq args (use-package-normalize-plist name-symbol args nil + #'use-package--merge-keys)) + + ;; Add default values for keywords not specified, when applicable. + (dolist (spec use-package-defaults) + (when (pcase (nth 2 spec) + ((and func (pred functionp)) (funcall func args)) + (sexp (eval sexp))) + (setq args (use-package-plist-maybe-put + args (nth 0 spec) (eval (nth 1 spec)))))) + + ;; If byte-compiling, pre-load the package so all its symbols are in + ;; scope. This is done by prepending statements to the :preface. + (when (bound-and-true-p byte-compile-current-file) + (setq args + (use-package-plist-append + args :preface + (use-package-concat + (mapcar #'(lambda (var) `(defvar ,var)) + (plist-get args :defines)) + (mapcar #'(lambda (fn) `(declare-function ,fn ,name-string)) + (plist-get args :functions)) + `((eval-when-compile + (with-demoted-errors + ,(format "Cannot load %s: %%S" name-string) + ,(when (eq use-package-verbose 'debug) + `(message ,(format "Compiling package %s" name-string))) + ,(unless (plist-get args :no-require) + `(load ,name-string nil t))))))))) + + ;; Certain keywords imply :defer, if :demand was not specified. + (when (and (not (plist-member args :demand)) + (not (plist-member args :defer)) + (or (plist-member args :bind) + (plist-member args :bind*) + (plist-member args :bind-keymap) + (plist-member args :bind-keymap*) + (plist-member args :interpreter) + (plist-member args :mode) + (plist-member args :magic) + (plist-member args :magic-fallback) + (plist-member args :commands) + (plist-member args :hook))) + (setq args (append args '(:defer t)))) + + (when (and (plist-member args :load) + (plist-member args :no-require)) + (setq args (use-package-plist-delete args :no-require))) + + (when (and (not (plist-member args :load)) + (not (plist-member args :defer)) + (not (plist-member args :no-require))) + (setq args (append args `(:load (,name))))) + + ;; Sort the list of keywords based on the order of `use-package-keywords'. + (use-package-sort-keywords args))) + +(defun use-package--core (name args) + (let ((orig-args (cl-copy-list args))) + (setq args (use-package-normalize-keywords name args)) + (let ((body (macroexp-progn + (use-package-process-keywords name args + (and (plist-get args :demand) + (list :demand t)))))) + (if (not (eq use-package-verbose 'debug)) + body + `(condition-case-unless-debug err + ,body + (error + (let ((msg (format "%s: %s" ',name (error-message-string err)))) + (with-current-buffer (get-buffer-create "*use-package*") + (goto-char (point-max)) + (insert "-----\n" msg "\n\n" + (pp-to-string ',`(use-package ,name ,@orig-args)) + "\n -->\n\n" + (pp-to-string ',`(use-package ,name ,@args)) + "\n ==>\n\n" + (pp-to-string + ',(let ((use-package-verbose 'errors) + (use-package-expand-minimally t)) + (macroexp-progn + (use-package-process-keywords name args + (and (plist-get args :demand) + (list :demand t))))))) + (emacs-lisp-mode)) + (ignore + (display-warning + 'use-package (concat msg " (see the *use-package* buffer)") + :error))))))))) + ;;;###autoload (defmacro use-package (name &rest args) "Declare an Emacs package by specifying a group of configuration options. @@ -1543,72 +1700,18 @@ this file. Usage: :ensure Loads the package using package.el if necessary. :pin Pin the package to an archive." (declare (indent 1)) - (unless (member :disabled args) - (let ((name-symbol (if (stringp name) (intern name) name)) - (orig-args args) - (args (use-package-normalize-plist name args))) - (dolist (spec use-package-defaults) - (setq args (if (eval (nth 2 spec)) - (use-package-plist-maybe-put - args (nth 0 spec) (eval (nth 1 spec))) - args))) - - ;; When byte-compiling, pre-load the package so all its symbols are in - ;; scope. - (if (bound-and-true-p byte-compile-current-file) - (setq args - (use-package-plist-append - args :preface - (use-package-concat - (mapcar #'(lambda (var) `(defvar ,var)) - (plist-get args :defines)) - (mapcar #'(lambda (fn) `(declare-function - ,fn ,(use-package-as-string name))) - (plist-get args :functions)) - `((eval-when-compile - (with-demoted-errors - ,(format "Cannot load %s: %%S" name) - ,(if (eq use-package-verbose 'debug) - `(message "Compiling package %s" ',name-symbol)) - ,(unless (plist-get args :no-require) - `(load ,(if (stringp name) - name - (symbol-name name)) nil t))))))))) - - (let ((body - `(progn - ,@(use-package-process-keywords name - (let ((args* - (use-package-sort-keywords - (if (and use-package-always-demand - (not (memq :defer args))) - (plist-put args :demand t) - args)))) - ;; The :demand keyword should not override :after - (if (and (plist-member args* :after) - (plist-member args* :demand)) - (setq args* (use-package-plist-delete args* :demand))) - (when (and use-package-always-ensure - (plist-member args* :load-path) - (not (plist-member orig-args :ensure))) - (plist-put args* :ensure nil)) - (unless (plist-member args* :init) - (plist-put args* :init nil)) - (unless (plist-member args* :config) - (plist-put args* :config '(t))) - args*) - (and use-package-always-defer - (list :deferred t)))))) - (when use-package-debug - (display-buffer - (save-current-buffer - (with-current-buffer (get-buffer-create "*use-package*") - (goto-char (point-max)) - (emacs-lisp-mode) - (insert (pp-to-string body)) - (current-buffer))))) - body)))) - + (unless (memq :disabled args) + (if (eq use-package-verbose 'errors) + (use-package--core name args) + (condition-case-unless-debug err + (use-package--core name args) + (error + (ignore + (display-warning + 'use-package + (format "Failed to parse package %s %s: %s" + name args (error-message-string err)) + :error))))))) (put 'use-package 'lisp-indent-function 'defun) diff --git a/test/lisp/use-package/use-package-tests.el b/test/lisp/use-package/use-package-tests.el index 7bc2a486b79..5cf7a342b36 100644 --- a/test/lisp/use-package/use-package-tests.el +++ b/test/lisp/use-package/use-package-tests.el @@ -26,23 +26,36 @@ (require 'use-package) (setq use-package-always-ensure nil - use-package-verbose nil + use-package-verbose 'errors use-package-expand-minimally t - max-lisp-eval-depth 8000) - -;; (let ((byte-compile-current-file nil)) (expand-minimally ())) -(fset 'insert-expansion - [?\C-\M- ?\M-w ?\M-: ?\M-p ?\C-e ?\C-b ?\C-b ?\C-\M-b ?\C-y ?\C-\M-k return ?\C-\M- ?\M-w C-return ?\C-z ?\C-n ?\C-f ?\C-y ?\C-\M-k]) + max-lisp-eval-depth 8000 + max-specpdl-size 8000) (defmacro expand-minimally (form) - `(let ((use-package-verbose nil) + `(let ((use-package-verbose 'errors) (use-package-expand-minimally t)) - (macroexpand ',form))) + (macroexpand-1 ',form))) (defmacro match-expansion (form &rest value) `(should (pcase (expand-minimally ,form) ,@(mapcar #'(lambda (x) (list x t)) value)))) +(defun fix-expansion () + (interactive) + (save-excursion + (unless (looking-at "(match-expansion") + (backward-up-list)) + (when (looking-at "(match-expansion") + (search-forward "(use-package") + (goto-char (match-beginning 0)) + (let ((decl (read (current-buffer)))) + (kill-sexp) + (let ((use-package-verbose 'errors) + (use-package-expand-minimally t)) + (insert ?\n ?\` (pp-to-string (macroexpand-1 decl)))))))) + +(bind-key "C-c C-u" #'fix-expansion emacs-lisp-mode-map) + (eval-when-compile (defun plist-delete (plist property) "Delete PROPERTY from PLIST" @@ -87,11 +100,6 @@ (ert-deftest use-package-test/:disabled () (match-expansion (use-package foo :disabled t) - `()) - - (match-expansion - ;; jww (2017-11-30): Should :disabled ignore its argument? - (use-package foo :disabled nil) `())) (ert-deftest use-package-test/:preface () @@ -176,8 +184,7 @@ (ert-deftest use-package-test/:defer-install () (match-expansion (use-package foo :defer-install t) - `(progn - (require 'foo nil nil)))) + `(require 'foo nil nil))) (ert-deftest use-package-test-normalize/:ensure () (flet ((norm (&rest args) @@ -230,7 +237,6 @@ (match-expansion (use-package foo :load-path "foo") `(progn - (use-package-ensure-elpa 'foo 'nil 'nil) (eval-and-compile (add-to-list 'load-path ,(pred stringp))) (require 'foo nil nil)))) @@ -283,77 +289,82 @@ (ert-deftest use-package-test/:if () (match-expansion (use-package foo :if t) - `(progn - (when (symbol-value 't) - (require 'foo nil nil)))) + `(when t + (require 'foo nil nil))) (match-expansion (use-package foo :if (and t t)) - `(progn - (when (and t t) - (require 'foo nil nil)))) + `(when (and t t) + (require 'foo nil nil))) (match-expansion (use-package foo :if nil) - `(progn - (when nil - (require 'foo nil nil))))) + `(when nil + (require 'foo nil nil)))) (ert-deftest use-package-test/:when () (match-expansion (use-package foo :when t) - `(progn - (when (symbol-value 't) - (require 'foo nil nil)))) + `(when t + (require 'foo nil nil))) (match-expansion (use-package foo :when (and t t)) - `(progn - (when (and t t) - (require 'foo nil nil)))) + `(when (and t t) + (require 'foo nil nil))) (match-expansion (use-package foo :when nil) - `(progn - (when nil - (require 'foo nil nil))))) + `(when nil + (require 'foo nil nil)))) (ert-deftest use-package-test/:unless () (match-expansion (use-package foo :unless t) - `(progn - (unless (symbol-value 't) - (require 'foo nil nil)))) + `(when (not t) + (require 'foo nil nil))) (match-expansion (use-package foo :unless (and t t)) - `(progn - (unless (and t t) - (require 'foo nil nil)))) + `(when (not (and t t)) + (require 'foo nil nil))) (match-expansion (use-package foo :unless nil) - `(progn - (unless nil - (require 'foo nil nil))))) + `(unless nil + (require 'foo nil nil)))) (ert-deftest use-package-test/:requires () (match-expansion (use-package foo :requires bar) - `(progn - (when (not (member nil (mapcar #'featurep '(bar)))) + `(when (featurep 'bar) + (require 'foo nil nil))) + + (let ((byte-compile-current-file t)) + (match-expansion + (use-package foo :requires bar) + `(when (featurep 'bar) + (eval-and-compile + (eval-when-compile + (with-demoted-errors + "Cannot load foo: %S" nil + (load "foo" nil t)))) (require 'foo nil nil)))) + (match-expansion + (use-package foo :requires (bar quux)) + `(when (not (member nil (mapcar #'featurep '(bar quux)))) + (require 'foo nil nil))) + (let ((byte-compile-current-file t)) (match-expansion (use-package foo :requires bar) - `(progn - (when (not (member nil (mapcar #'featurep '(bar)))) - (eval-and-compile - (eval-when-compile - (with-demoted-errors "Cannot load foo: %S" nil - (load "foo" nil t)))) - (require 'foo nil nil)))))) + `(when (featurep 'bar) + (eval-and-compile + (eval-when-compile + (with-demoted-errors "Cannot load foo: %S" nil + (load "foo" nil t)))) + (require 'foo nil nil))))) (ert-deftest use-package-test/:load-path () (match-expansion @@ -420,7 +431,7 @@ (ert-deftest use-package-test/:no-require () (match-expansion (use-package foo :no-require t) - `(progn)) + `nil) (match-expansion (use-package foo :no-require t :config (config)) @@ -431,10 +442,9 @@ (let ((byte-compile-current-file t)) (match-expansion (use-package foo :no-require t) - `(progn - (eval-and-compile - (eval-when-compile - (with-demoted-errors "Cannot load foo: %S" nil nil))))))) + `(eval-and-compile + (eval-when-compile + (with-demoted-errors "Cannot load foo: %S" nil nil)))))) (ert-deftest use-package-test-normalize/:bind () (flet ((norm (&rest args) @@ -469,41 +479,35 @@ (ert-deftest use-package-test/:bind-keymap () (match-expansion (use-package foo :bind-keymap ("C-k" . key)) - `(progn - (ignore - (bind-key "C-k" - #'(lambda () - (interactive) - (use-package-autoload-keymap 'key 'foo nil))))))) + `(ignore + (bind-key "C-k" + #'(lambda nil + (interactive) + (use-package-autoload-keymap 'key 'foo nil)))))) (ert-deftest use-package-test/:bind-keymap* () (match-expansion (use-package foo :bind-keymap* ("C-k" . key)) - `(progn - (ignore - (bind-key* "C-k" - #'(lambda () - (interactive) - (use-package-autoload-keymap 'key 'foo t))))))) + `(ignore + (bind-key* "C-k" + #'(lambda () + (interactive) + (use-package-autoload-keymap 'key 'foo t)))))) (ert-deftest use-package-test/:interpreter () (match-expansion (use-package foo :interpreter "interp") `(progn + (add-to-list 'interpreter-mode-alist '("interp" . foo)) (unless (fboundp 'foo) - (autoload #'foo "foo" nil t)) - (ignore - (add-to-list 'interpreter-mode-alist - '("interp" . foo))))) + (autoload #'foo "foo" nil t)))) (match-expansion (use-package foo :interpreter ("interp" . fun)) `(progn + (add-to-list 'interpreter-mode-alist '("interp" . fun)) (unless (fboundp 'fun) - (autoload #'fun "foo" nil t)) - (ignore - (add-to-list 'interpreter-mode-alist - '("interp" . fun)))))) + (autoload #'fun "foo" nil t))))) (ert-deftest use-package-test-normalize/:mode () (flet ((norm (&rest args) @@ -524,65 +528,52 @@ (match-expansion (use-package foo :mode "interp") `(progn + (add-to-list 'auto-mode-alist '("interp" . foo)) (unless (fboundp 'foo) - (autoload #'foo "foo" nil t)) - (ignore - (add-to-list 'auto-mode-alist - '("interp" . foo))))) + (autoload #'foo "foo" nil t)))) (match-expansion (use-package foo :mode ("interp" . fun)) `(progn + (add-to-list 'auto-mode-alist '("interp" . fun)) (unless (fboundp 'fun) - (autoload #'fun "foo" nil t)) - (ignore - (add-to-list 'auto-mode-alist - '("interp" . fun)))))) + (autoload #'fun "foo" nil t))))) (ert-deftest use-package-test/:magic () (match-expansion (use-package foo :magic "interp") `(progn + (add-to-list 'magic-mode-alist '("interp" . foo)) (unless (fboundp 'foo) - (autoload #'foo "foo" nil t)) - (ignore - (add-to-list 'magic-mode-alist - '("interp" . foo))))) + (autoload #'foo "foo" nil t)))) (match-expansion (use-package foo :magic ("interp" . fun)) `(progn + (add-to-list 'magic-mode-alist '("interp" . fun)) (unless (fboundp 'fun) - (autoload #'fun "foo" nil t)) - (ignore - (add-to-list 'magic-mode-alist - '("interp" . fun)))))) + (autoload #'fun "foo" nil t))))) (ert-deftest use-package-test/:magic-fallback () (match-expansion (use-package foo :magic-fallback "interp") `(progn + (add-to-list 'magic-fallback-mode-alist '("interp" . foo)) (unless (fboundp 'foo) - (autoload #'foo "foo" nil t)) - (ignore - (add-to-list 'magic-fallback-mode-alist - '("interp" . foo))))) + (autoload #'foo "foo" nil t)))) (match-expansion (use-package foo :magic-fallback ("interp" . fun)) `(progn + (add-to-list 'magic-fallback-mode-alist '("interp" . fun)) (unless (fboundp 'fun) - (autoload #'fun "foo" nil t)) - (ignore - (add-to-list 'magic-fallback-mode-alist - '("interp" . fun)))))) + (autoload #'fun "foo" nil t))))) (ert-deftest use-package-test/:commands () (match-expansion (use-package foo :commands bar) - `(progn - (unless (fboundp 'bar) - (autoload #'bar "foo" nil t)))) + `(unless (fboundp 'bar) + (autoload #'bar "foo" nil t))) (match-expansion (use-package foo :commands (bar quux)) @@ -612,8 +603,7 @@ (ert-deftest use-package-test/:defines () (match-expansion (use-package foo :defines bar) - `(progn - (require 'foo nil nil))) + `(require 'foo nil nil)) (let ((byte-compile-current-file t)) (match-expansion @@ -630,8 +620,7 @@ (ert-deftest use-package-test/:functions () (match-expansion (use-package foo :functions bar) - `(progn - (require 'foo nil nil))) + `(require 'foo nil nil)) (let ((byte-compile-current-file t)) (match-expansion @@ -647,17 +636,16 @@ (match-expansion (use-package foo :defer t :functions bar) - `(progn)) + `nil) (let ((byte-compile-current-file t)) (match-expansion (use-package foo :defer t :functions bar) - `(progn - (eval-and-compile - (declare-function bar "foo") - (eval-when-compile - (with-demoted-errors "Cannot load foo: %S" nil - (load "foo" nil t))))))) + `(eval-and-compile + (declare-function bar "foo") + (eval-when-compile + (with-demoted-errors "Cannot load foo: %S" nil + (load "foo" nil t)))))) (let ((byte-compile-current-file t)) (match-expansion @@ -677,8 +665,7 @@ (ert-deftest use-package-test/:defer () (match-expansion (use-package foo) - `(progn - (require 'foo nil nil))) + `(require 'foo nil nil)) (let ((byte-compile-current-file t)) (match-expansion @@ -692,16 +679,15 @@ (match-expansion (use-package foo :defer t) - `(progn)) + `nil) (let ((byte-compile-current-file t)) (match-expansion (use-package foo :defer t) - `(progn - (eval-and-compile - (eval-when-compile - (with-demoted-errors "Cannot load foo: %S" nil - (load "foo" nil t)))))))) + `(eval-and-compile + (eval-when-compile + (with-demoted-errors "Cannot load foo: %S" nil + (load "foo" nil t))))))) (ert-deftest use-package-test-normalize/:hook () (flet ((norm (&rest args) @@ -726,7 +712,7 @@ (ert-deftest use-package-test/:hook () (let ((byte-compile-current-file t)) (should - (equal ; pcase crashes + (equal (expand-minimally (use-package foo :bind (("C-a" . key)) @@ -734,8 +720,10 @@ '(progn (eval-and-compile (eval-when-compile - (with-demoted-errors "Cannot load foo: %S" nil - (load "foo" nil t)))) + (with-demoted-errors + "Cannot load foo: %S" nil + (load "foo" nil t)))) + (add-hook 'hook-hook #'fun) (unless (fboundp 'fun) (autoload #'fun "foo" nil t)) (eval-when-compile @@ -744,7 +732,6 @@ (autoload #'key "foo" nil t)) (eval-when-compile (declare-function key "foo")) - (add-hook 'hook-hook #'fun) (ignore (bind-keys :package foo ("C-a" . key)))))))) @@ -796,9 +783,8 @@ (ert-deftest use-package-test/:after () (match-expansion (use-package foo :after bar) - `(progn - (eval-after-load 'bar - '(require 'foo nil nil)))) + `(eval-after-load 'bar + '(require 'foo nil nil))) (let ((byte-compile-current-file t)) (match-expansion @@ -813,93 +799,96 @@ (match-expansion (use-package foo :after (bar quux)) - `(progn - (eval-after-load 'quux - '(eval-after-load 'bar - '(require 'foo nil nil))))) + `(eval-after-load 'quux + '(eval-after-load 'bar + '(require 'foo nil nil)))) (match-expansion (use-package foo :after (:all bar quux)) - `(progn - (eval-after-load 'quux - '(eval-after-load 'bar - '(require 'foo nil nil))))) + `(eval-after-load 'quux + '(eval-after-load 'bar + '(require 'foo nil nil)))) (match-expansion (use-package foo :after (:any bar quux)) - `(progn - (progn - (eval-after-load 'bar - '(require 'foo nil nil)) - (eval-after-load 'quux - '(require 'foo nil nil))))) + `(lexical-let ,_ + (lexical-let ,_ + (progn + (eval-after-load 'bar + `(funcall ,_)) + (eval-after-load 'quux + `(funcall ,_)))))) (match-expansion (use-package foo :after (:all (:any bar quux) bow)) - `(progn - (eval-after-load 'bow - '(progn - (eval-after-load 'bar - '(require 'foo nil nil)) - (eval-after-load 'quux - '(require 'foo nil nil)))))) + `(lexical-let ,_ + (lexical-let ,_ + (eval-after-load 'bow + '(progn + (eval-after-load 'bar + `(funcall ,_)) + (eval-after-load 'quux + `(funcall ,_))))))) (match-expansion (use-package foo :after (:any (:all bar quux) bow)) - `(progn - (progn - (eval-after-load 'quux - '(eval-after-load 'bar - '(require 'foo nil nil))) - (eval-after-load 'bow - '(require 'foo nil nil))))) + `(lexical-let ,_ + (lexical-let ,_ + (progn + (eval-after-load 'quux + '(eval-after-load 'bar + `(funcall ,_))) + (eval-after-load 'bow + `(funcall ,_)))))) (match-expansion (use-package foo :after (:all (:any bar quux) (:any bow baz))) - `(progn - (progn - (eval-after-load 'bow - '(progn - (eval-after-load 'bar - '(require 'foo nil nil)) - (eval-after-load 'quux - '(require 'foo nil nil)))) - (eval-after-load 'baz - '(progn - (eval-after-load 'bar - '(require 'foo nil nil)) - (eval-after-load 'quux - '(require 'foo nil nil))))))) + `(lexical-let ,_ + (lexical-let ,_ + (progn + (eval-after-load 'bow + '(progn + (eval-after-load 'bar + `(funcall ,_)) + (eval-after-load 'quux + `(funcall ,_)))) + (eval-after-load 'baz + '(progn + (eval-after-load 'bar + `(funcall ,_)) + (eval-after-load 'quux + `(funcall ,_)))))))) (match-expansion (use-package foo :after (:any (:all bar quux) (:all bow baz))) - `(progn - (progn - (eval-after-load 'quux - '(eval-after-load 'bar - '(require 'foo nil nil))) - (eval-after-load 'baz - '(eval-after-load 'bow - '(require 'foo nil nil)))))) + `(lexical-let ,_ + (lexical-let ,_ + (progn + (eval-after-load 'quux + '(eval-after-load 'bar + `(funcall ,_))) + (eval-after-load 'baz + '(eval-after-load 'bow + `(funcall ,_))))))) (match-expansion (use-package foo :after (:any (:all bar quux) (:any bow baz))) - `(progn - (progn - (eval-after-load 'quux - '(eval-after-load 'bar - '(require 'foo nil nil))) + `(lexical-let ,_ + (lexical-let ,_ (progn - (eval-after-load 'bow - '(require 'foo nil nil)) - (eval-after-load 'baz - '(require 'foo nil nil))))))) + (eval-after-load 'quux + '(eval-after-load 'bar + `(funcall ,_))) + (progn + (eval-after-load 'bow + `(funcall ,use-package--next142993)) + (eval-after-load 'baz + `(funcall ,_)))))))) (ert-deftest use-package-test/:demand () (match-expansion (use-package foo :demand t) - `(progn - (require 'foo nil nil))) + `(require 'foo nil nil)) (let ((byte-compile-current-file t)) (match-expansion @@ -933,9 +922,8 @@ ;; #529 - :demand should not override an explicit use of :after (match-expansion (use-package foo :demand t :after bar) - `(progn - (eval-after-load 'bar - '(require 'foo nil nil)))) + `(eval-after-load 'bar + '(require 'foo nil nil))) (let ((byte-compile-current-file t)) (match-expansion @@ -946,7 +934,40 @@ (with-demoted-errors "Cannot load foo: %S" nil (load "foo" nil t)))) (eval-after-load 'bar - '(require 'foo nil nil)))))) + '(require 'foo nil nil))))) + + (match-expansion + (use-package counsel + :load-path "site-lisp/swiper" + :after ivy + :demand t + :diminish + :bind (("C-*" . counsel-org-agenda-headlines) + ("M-x" . counsel-M-x)) + :commands (counsel-minibuffer-history + counsel-find-library + counsel-unicode-char) + :preface (preface-code) + :init + ;; This is actually wrong, but it's just part of the example. + (define-key minibuffer-local-map (kbd "M-r") + 'counsel-minibuffer-history)) + `(progn + (eval-and-compile + (add-to-list 'load-path "/Users/johnw/.emacs.d/site-lisp/swiper")) + (eval-and-compile + (preface-code)) + (eval-after-load 'ivy + '(progn + (define-key minibuffer-local-map (kbd "M-r") + 'counsel-minibuffer-history) + (require 'counsel nil nil) + (if (fboundp 'diminish) + (diminish 'counsel-mode)) + (ignore + (bind-keys :package counsel + ("C-*" . counsel-org-agenda-headlines) + ("M-x" . counsel-M-x)))))))) (ert-deftest use-package-test/:config () (match-expansion @@ -970,11 +991,10 @@ (match-expansion (use-package foo :defer t :config (config)) - `(progn - (eval-after-load 'foo - '(progn - (config) - t)))) + `(eval-after-load 'foo + '(progn + (config) + t))) (let ((byte-compile-current-file t)) (match-expansion -- 2.39.2