(eval-when-compile
(defvar use-package-expand-minimally))
-(defmacro use-package-expand (name label form)
+(defun use-package-progn (body)
+ (if (= (length body) 1)
+ (car body)
+ `(progn ,@body)))
+
+(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")))
- `(condition-case-unless-debug ,err
- ,form
- (error
- (ignore
- (display-warning 'use-package (error-message-string ,err)
- :error))))))))
+ (list
+ `(condition-case-unless-debug ,err
+ ,(use-package-progn form)
+ (error
+ (ignore
+ (display-warning 'use-package (error-message-string ,err)
+ :error)))))))))
(put 'use-package-expand 'lisp-indent-function 'defun)
(defun use-package-hook-injector (name-string keyword args)
- "Wrap pre/post hook injections around a given keyword form."
+ "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)
- (macroexpand-all
- `(use-package-expand name-string ,(format "%s" keyword)
- ,(plist-get args keyword)))
+ (use-package-expand name-string (format "%s" keyword)
+ (plist-get args keyword))
(let ((keyword-name (substring (format "%s" keyword) 1))
(block (plist-get args keyword)))
(when block
- (macroexpand-all
- `(when (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"))))
- (use-package-expand name-string ,(format "%s" keyword)
- ,(plist-get args keyword))
- (use-package-expand name-string ,(format "post-%s hook" keyword)
- (run-hooks
- ',(intern (concat "use-package--" name-string
- "--post-" keyword-name "-hook"))))))))))
-
-(defun use-package-progn (body)
- (if (= (length body) 1)
- (car body)
- `(progn ,@body)))
-
-(defmacro use-package-with-elapsed-timer (text &rest body)
+ `((when ,(use-package-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")))))
+ ,(use-package-progn
+ (use-package-expand name-string (format "%s" keyword)
+ (plist-get args keyword)))
+ ,(use-package-progn
+ (use-package-expand name-string (format "post-%s hook" keyword)
+ `(run-hooks
+ ',(intern (concat "use-package--" name-string
+ "--post-" keyword-name "-hook")))))))))))
+
+(defun use-package-with-elapsed-timer (text body)
+ "BODY is a list of forms, so `((foo))' if only `foo' is being called."
(declare (indent 1))
(if use-package-expand-minimally
- (use-package-progn body)
+ body
(let ((nowvar (make-symbol "now")))
(if (bound-and-true-p use-package-verbose)
- `(let ((,nowvar (current-time)))
- (message "%s..." ,text)
- (prog1
- ,(use-package-progn body)
- (let ((elapsed
- (float-time (time-subtract (current-time) ,nowvar))))
- (if (> elapsed ,use-package-minimum-reported-time)
- (message "%s...done (%.3fs)" ,text elapsed)
- (message "%s...done" ,text)))))
- (use-package-progn body)))))
-
-(put 'use-package-with-elapsed-timer 'lisp-indent-function 'defun)
+ `((let ((,nowvar (current-time)))
+ (message "%s..." ,text)
+ (prog1
+ ,(use-package-progn body)
+ (let ((elapsed
+ (float-time (time-subtract (current-time) ,nowvar))))
+ (if (> elapsed ,use-package-minimum-reported-time)
+ (message "%s...done (%.3fs)" ,text elapsed)
+ (message "%s...done" ,text))))))
+ body))))
+
+(put 'use-package-with-elapsed-timer 'lisp-indent-function 1)
(defsubst use-package-error (msg)
"Report MSG as an error, so the user knows it came from this package."
"Given a list of forms, return it wrapped in `progn'."
(unless (listp (car args))
(use-package-error (concat label " wants a sexp or list of sexps")))
- (if (= (length args) 1)
- (car args)
- (cons 'progn args)))
+ (mapcar #'macroexpand args))
(defsubst use-package-normalize-value (label arg)
"Normalize a value."
(use-package-as-one (symbol-name head) args
#'use-package-normalize-symbols))
- ((or :defer :demand :disabled)
+ ((or :defer :demand :disabled :no-require)
(if (null args)
t
(use-package-only-one (symbol-name head) args
;; Should we defer loading of the package lazily?
(defer-loading (and (not (plist-get args :demand))
(or commands deferral
+ (plist-get args :no-require)
(plist-get args :bind-keymap)
(plist-get args :bind-keymap*))))
+ (pre-compile-load
+ ;; When byte-compiling, load the package here so that all of its
+ ;; symbols are in scope.
+ (when (bound-and-true-p byte-compile-current-file)
+ `((eval-when-compile
+ ,@(mapcar #'(lambda (var) `(defvar ,var))
+ (plist-get args* :defines))
+ (with-demoted-errors
+ ,(format "Error in %s: %%S" name-string)
+ ,(if use-package-verbose
+ `(message "Compiling package %s" ,name-string))
+ ,(unless (plist-get args* :no-require)
+ `(require ',name-symbol nil t)))))))
+
;; These are all the configurations to be made after the package has
;; loaded.
(config-body
- (use-package-cat-maybes
- (list (use-package-hook-injector name-string :config args))
-
- (mapcar #'(lambda (var)
- (if (listp var)
- `(diminish ',(car var) ,(cdr var))
- `(diminish ',var)))
- (plist-get args :diminish))))
-
- (config-body*
- (and config-body
- (macroexpand
- `(use-package-with-elapsed-timer
- ,(format "Configuring package %s" name-string)
- ,@config-body))))
+ (use-package-with-elapsed-timer
+ (format "Configuring package %s" name-string)
+ (use-package-cat-maybes
+ (use-package-hook-injector name-string :config args)
+
+ (mapcar #'(lambda (var)
+ (if (listp var)
+ `(diminish ',(car var) ,(cdr var))
+ `(diminish ',var)))
+ (plist-get args :diminish)))))
(config-defun
(make-symbol (concat "use-package--" name-string "--config"))))
`(eval-and-compile (add-to-list 'load-path ,path)))
(plist-get args :load-path))
- (list (plist-get args :preface))
+ pre-compile-load
+
+ (plist-get args :preface)
;; Setup any required autoloads
(if defer-loading
- (delete nil
- (mapcar #'(lambda (command)
- ;; (unless (and (fboundp command)
- ;; (not (autoloadp command)))
- ;; `(autoload #',command ,name-string nil t))
- `(autoload #',command ,name-string nil t))
- commands)))
+ (mapcar #'(lambda (command)
+ `(unless (fboundp ',command)
+ (autoload #',command ,name-string nil t)))
+ commands))
(if (numberp deferral)
- `((run-with-idle-timer ,deferral nil
- #'require ',name-symbol nil t)))
+ `((run-with-idle-timer ,deferral nil #'require ',name-symbol nil t)))
(when (bound-and-true-p byte-compile-current-file)
- (mapcar #'(lambda (fn)
- `(declare-function ,fn ,name-string))
+ (mapcar #'(lambda (fn) `(declare-function ,fn ,name-string))
(append (plist-get args :functions) commands)))
;; (if (and defer-loading config-body)
;; `((defalias ',config-defun #'(lambda () ,config-body*))))
;; The user's initializations
- (list (use-package-hook-injector name-string :init args))
+ (use-package-hook-injector name-string :init args)
(if defer-loading
(use-package-cat-maybes
(if config-body
`((eval-after-load ',name
;; '(,config-defun)
- ',config-body*)))
+ ',(use-package-progn config-body))))
(list t))
- `(,(macroexpand
- `(use-package-with-elapsed-timer
- ,(format "Loading package %s" name-string)
- ,(if use-package-expand-minimally
- (use-package-progn
- (use-package-cat-maybes
- (list `(require ',name-symbol))
- bindings
- config-body
- (list t)))
- `(if (not (require ',name-symbol nil t))
- (ignore
- (display-warning
- 'use-package
- (format "Could not load package %s" ,name-string)
- :error))
- ,@(use-package-cat-maybes
- bindings
- config-body
- (list t)))))))))))
+ (use-package-with-elapsed-timer
+ (format "Loading package %s" name-string)
+ (if use-package-expand-minimally
+ (use-package-cat-maybes
+ (list `(require ',name-symbol))
+ bindings
+ config-body
+ (list t))
+ `((if (not (require ',name-symbol nil t))
+ (ignore
+ (display-warning
+ 'use-package
+ (format "Could not load package %s" ,name-string)
+ :error))
+ ,@(use-package-cat-maybes
+ bindings
+ config-body
+ (list t))))))))))
(defmacro use-package (name &rest args)
"Declare an Emacs package by specifying a group of configuration options.
:pin Pin the package to an archive."
(declare (indent 1))
(unless (member :disabled args)
- (use-package-expand "use-package" "expansion"
- (let* ((name-string (if (stringp name) name (symbol-name name)))
- (name-symbol (if (stringp name) (intern name) name))
- (args* (use-package-normalize-plist name-symbol args))
- (archive-name (plist-get args* :pin))
- (ensure (plist-get args* :ensure))
- (package-name (or (and (eq ensure t) name) ensure)))
- ;; Pin any packages that have been marked with `:pin'.
- (when archive-name
- (use-package-pin-package name-symbol archive-name))
-
- ;; Ensure that the package has been installed, if marked with
- ;; `:ensure'.
- (when package-name
- (require 'package)
- (use-package-ensure-elpa package-name))
-
- ;; At this point, we can expand the macro using the helper function.
- ;; `use--package'.
- (let*
- ((body (use-package-cat-maybes
- (use--package name name-symbol name-string args*)
- (when archive-name
- `((add-to-list 'package-pinned-packages
- '(,name-symbol . ,archive-name))))))
- (pred (plist-get args* :if))
- (expansion (if pred
- `(when ,pred ,@body)
- (use-package-progn body)))
- (requires (plist-get args* :requires))
-
- (pre-compile-load
- ;; When byte-compiling, load the package here so that all of its
- ;; symbols are in scope.
- (when (bound-and-true-p byte-compile-current-file)
- `((eval-when-compile
- ,@(mapcar #'(lambda (var) `(defvar ,var))
- (plist-get args* :defines))
- (with-demoted-errors
- ,(format "Error in %s: %%S" name-string)
- (if use-package-verbose
- (message "Compiling package %s" ,name-string))
- (require ',name-symbol nil t))))))
-
- (body*
- (use-package-cat-maybes
- pre-compile-load
- (list
- (if (null requires)
- expansion
- `(if ,(if (listp requires)
+ (let* ((name-string (if (stringp name) name (symbol-name name)))
+ (name-symbol (if (stringp name) (intern name) name))
+ (args* (use-package-normalize-plist name-symbol args))
+ (archive-name (plist-get args* :pin))
+ (ensure (plist-get args* :ensure))
+ (package-name (or (and (eq ensure t) name) ensure)))
+ ;; Pin any packages that have been marked with `:pin'.
+ (when archive-name
+ (use-package-pin-package name-symbol archive-name))
+
+ ;; Ensure that the package has been installed, if marked with
+ ;; `:ensure'.
+ (when package-name
+ (require 'package)
+ (use-package-ensure-elpa package-name))
+
+ ;; At this point, we can expand the macro using the helper function.
+ ;; `use--package'.
+ (let*
+ ((body (use-package-cat-maybes
+ (use--package name name-symbol name-string args*)
+ (when archive-name
+ `((add-to-list 'package-pinned-packages
+ '(,name-symbol . ,archive-name))))))
+ (pred (plist-get args* :if))
+ (expansion (if pred
+ `((when ,pred ,@body))
+ body))
+ (requires (plist-get args* :requires))
+ (body*
+ (use-package-progn
+ (use-package-expand "use-package" "expansion"
+ (if (null requires)
+ expansion
+ `((if ,(if (listp requires)
`(not (member nil (mapcar #'featurep ',requires)))
`(featurep ',requires))
- ,expansion))))))
-
- ;; If a dynamic test has been requested -- that certain other
- ;; packages must be loaded first, before attempting to load and
- ;; configure this package -- wrap that logic around the expansion.
- (use-package-progn body*))))))
+ ,@expansion)))))))
+ ;; (message "Expanded: %s" (pp-to-string body*))
+ body*))))
(put 'use-package 'lisp-indent-function 'defun)