]> git.eshelyaron.com Git - emacs.git/commitdiff
Begin refactoring for 2.0; NOTE: BREAKING CHANGES
authorJohn Wiegley <johnw@newartisans.com>
Sat, 14 Mar 2015 10:22:43 +0000 (05:22 -0500)
committerJohn Wiegley <johnw@newartisans.com>
Sat, 14 Mar 2015 10:22:43 +0000 (05:22 -0500)
The major change is that :init is now always performed before loading a
file, whether loading is deferred or not.  This is a change from before,
where the semantics of :init varied between demand and defer.  The new
usage is now entirely consistent.

Also, because :init and :config now mean "before" and "after", the
:pre-* and :post-* keywords are gone, as they should no longer be
necessary.

Lastly, an effort has been made to make your Emacs start even in the
presence of use-package configuration failures.  So after this change,
be sure to check your *Messages* buffer.  Most likely, you will have
several instances where you are using :init, but should be using :config
(this was the case for me in a number of places).

lisp/use-package/use-package.el

index 72f6250f4044f43557af0fc6f5677070da73b2d5..75d5ee6187c3e38b85ffab2859cde11216bbf48e 100644 (file)
@@ -4,7 +4,7 @@
 
 ;; Author: John Wiegley <jwiegley@gmail.com>
 ;; Created: 17 Jun 2012
-;; Version: 1.0
+;; Version: 2.0
 ;; Package-Requires: ((bind-key "1.0") (diminish "0.44"))
 ;; Keywords: dotemacs startup speed config package
 ;; X-URL: https://github.com/jwiegley/use-package
@@ -58,7 +58,7 @@ then the expanded macros do their job silently."
   :type 'boolean
   :group 'use-package)
 
-(defcustom use-package-minimum-reported-time 0.01
+(defcustom use-package-minimum-reported-time 0.1
   "Minimal load time that will be reported.
 
 Note that `use-package-verbose' has to be set to t, for anything
@@ -72,16 +72,11 @@ then the expanded macros do their job silently."
   :type 'number
   :group 'use-package)
 
-(defcustom use-package-idle-interval 3
-  "Time to wait when using :idle in a `use-package' specification."
-  :type 'number
-  :group 'use-package)
-
 (defmacro use-package-with-elapsed-timer (text &rest body)
   (declare (indent 1))
   (let ((nowvar (make-symbol "now")))
-    `(if (bound-and-true-p use-package-verbose)
-         (let ((,nowvar (current-time)))
+    (if (bound-and-true-p use-package-verbose)
+        `(let ((,nowvar (current-time)))
            (message "%s..." ,text)
            (prog1
                (progn ,@body)
@@ -92,9 +87,466 @@ then the expanded macros do their job silently."
                           "0.01"))
                    (message "%s...done (%.3fs)" ,text elapsed)
                  (message "%s...done" ,text)))))
-       ,@body)))
+      `(progn ,@body))))
+
+(defsubst use-package-error (msg)
+  "Report MSG as an error, so the user knows it came from this package."
+  (error "use-package: %s" msg))
+
+(defun use-package-normalize-form (label args)
+  "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)))
+
+(defsubst use-package-normalize-value (label arg)
+  "Normalize a value."
+  (cond ((symbolp arg)
+         `(symbol-value ',arg))
+        ((functionp arg)
+         `(funcall #',arg))
+        (t arg)))
+
+(defun use-package-normalize-diminish (name-symbol label arg &optional recursed)
+  "Normalize the arguments to diminish down to a list of one of two forms:
+     SYMBOL
+     (SYMBOL . STRING)"
+  (cond
+   ((symbolp arg)
+    (list arg))
+   ((stringp arg)
+    (list (cons (intern (concat (symbol-name name-symbol) "-mode")) arg)))
+   ((and (consp arg) (stringp (cdr arg)))
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (car (use-package-normalize-diminish
+                           name-symbol label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a string, symbol, "
+             "(symbol . string) or list of these")))))
+
+(defun use-package-only-one (label args f)
+  "Call F on the first member of ARGS if it has exactly one element."
+  (declare (indent 1))
+  (cond
+   ((and (listp args) (listp (cdr args))
+         (= (length args) 1))
+    (funcall f label (car args)))
+   (t
+    (use-package-error
+     (concat label " wants exactly one argument")))))
+
+(defun use-package-as-one (label args f)
+  "Call F on the first element of ARGS if it has one element, or all of ARGS."
+  (declare (indent 1))
+  (if (and (listp args) (listp (cdr args)))
+      (if (= (length args) 1)
+          (funcall f label (car args))
+        (funcall f label args))
+    (use-package-error
+     (concat label " wants a list"))))
+
+(defsubst use-package-is-sympair (x)
+  "Return t if X has the type (STRING . SYMBOL)."
+  (and (consp x)
+       (stringp (car x))
+       (symbolp (cdr x))))
+
+(defun use-package-normalize-pairs (name-symbol label arg &optional recursed)
+  "Normalize a list of string/symbol pairs."
+  (cond
+   ((stringp arg)
+    (list (cons arg name-symbol)))
+   ((use-package-is-sympair arg)
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (car (use-package-normalize-pairs
+                           name-symbol label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a string, (string . symbol) or list of these")))))
+
+(defun use-package-normalize-symbols (label arg &optional recursed)
+  "Normalize a list of symbols."
+  (cond
+   ((symbolp arg)
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (car (use-package-normalize-symbols label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a symbol, or list of symbols")))))
+
+(defun use-package-normalize-paths (label arg &optional recursed)
+  "Normalize a list of filesystem paths."
+  (cond
+   ((or (symbolp arg) (functionp arg))
+    (let ((value (use-package-normalize-value label arg)))
+      (use-package-normalize-paths label (eval value))))
+   ((stringp arg)
+    (let ((path (if (file-name-absolute-p arg)
+                    arg
+                  (expand-file-name arg user-emacs-directory))))
+      (if (file-directory-p path)
+          (list path)
+        (use-package-error
+         (concat label " wants a directory path, or list of paths")))))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x)
+                (car (use-package-normalize-paths label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a directory path, or list of paths")))))
+
+(defun use-package-split-list (pred xs)
+  (let ((ys (list nil)) (zs (list nil)) flip)
+    (dolist (x xs)
+      (if flip
+          (nconc zs (list x))
+        (if (funcall pred x)
+            (progn
+              (setq flip t)
+              (nconc zs (list x)))
+          (nconc ys (list x)))))
+    (cons (cdr ys) (cdr zs))))
+
+(defun use-package-normalize-plist (name-symbol input)
+  "Given a pseudo-plist, normalize it to a regular plist."
+  (if (null input)
+      nil
+    (let* ((head (car input))
+           (xs (use-package-split-list #'keywordp (cdr input)))
+           (args (car xs))
+           (tail (cdr xs)))
+      (append
+       (list
+        (cond ((memq head '(:when :unless)) :if)
+              (t head))
+        (pcase head
+          ((or :bind :bind* :bind-keymap :bind-keymap* :interpreter :mode)
+           (use-package-as-one (symbol-name head) args
+             (apply-partially #'use-package-normalize-pairs name-symbol)))
+
+          ((or :commands :defines :functions :requires)
+           (use-package-as-one (symbol-name head) args
+             #'use-package-normalize-symbols))
+
+          ((or :defer :demand :disabled :ensure)
+           (if (null args)
+               t
+             (use-package-only-one (symbol-name head) args
+               #'use-package-normalize-value)))
+
+          ((or :if :when :unless)
+           (use-package-only-one (symbol-name head) args
+             #'use-package-normalize-value))
+
+          (:diminish
+           (use-package-as-one (symbol-name head) args
+             (apply-partially #'use-package-normalize-diminish name-symbol)))
+
+          ((or :init :config :idle)
+           (use-package-normalize-form (symbol-name head) args))
+
+          (:idle-priority
+           (if (null args)
+               5
+             (use-package-only-one (symbol-name head) args
+               (lambda (label arg)
+                 (if (numberp arg)
+                     arg
+                   (use-package-error
+                    ":idle-priority wants an optional number"))))))
+
+          (:load-path
+           (use-package-as-one (symbol-name head) args
+             #'use-package-normalize-paths))
+
+          (:pin
+           (use-package-only-one (symbol-name head) args
+             (lambda (label arg)
+               (if (stringp arg)
+                   arg
+                 (use-package-error ":pin wants an archive name (a string)")))))
+
+          (_ (use-package-error (format "Unrecognized keyword: %s" head)))))
+       (use-package-normalize-plist name-symbol tail)))))
+
+(defsubst use-package-cat-maybes (&rest elems)
+  "Delete all empty lists from ELEMS (nil or (list nil)), and append them."
+  (apply #'nconc (delete nil (delete (list nil) elems))))
+
+(defsubst use-package-expand (name label form)
+  (declare (indent 1))
+  (and form
+       `(with-demoted-errors
+            ,(format "Failure in %s of %s: %%S" label name)
+          ,form)))
+
+(defun use--package (name-symbol name-string args)
+  "See docstring for `use-package'."
+  (let*
+      ((commands (plist-get args :commands))
+
+       ;; Note: evaluation of this forms possibly extends the value of
+       ;; `commands'.
+       (bindings
+        (append
+         (mapcar #'(lambda (binding)
+                     `(bind-key ,(car binding)
+                                #'(lambda () (interactive)
+                                    (use-package-autoload-keymap
+                                     ',(cdr binding) ,name-symbol nil))))
+                 (plist-get args :bind-keymap))
+
+         (mapcar #'(lambda (binding)
+                     `(bind-key ,(car binding)
+                                #'(lambda () (interactive)
+                                    (use-package-autoload-keymap
+                                     ',(cdr binding) ,name-symbol t))))
+                 (plist-get args :bind-keymap*))
+
+         (mapcar #'(lambda (mode)
+                     (push (cdr mode) commands)
+                     `(add-to-list 'auto-mode-alist ',mode))
+                 (plist-get args :mode))
+
+         (mapcar #'(lambda (interpreter)
+                     (push (cdr interpreter) commands)
+                     `(add-to-list 'interpreter-mode-alist ',interpreter))
+                 (plist-get args :interpreter))
+
+         (mapcar #'(lambda (binding)
+                     (push (cdr binding) commands)
+                     `(bind-key ,(car binding) #',(cdr binding)))
+                 (plist-get args :bind))
+
+         (mapcar #'(lambda (binding)
+                     (push (cdr binding) commands)
+                     `(bind-key* ,(car binding) #',(cdr binding)))
+                 (plist-get args :bind*))))
+
+       ;; Should we defer loading of the package lazily?
+       (defer-loading (and (not (plist-get args :demand))
+                           (or commands (plist-get args :defer))))
+
+       ;; These are all the configurations to be made after the package has
+       ;; loaded.
+       (config-body
+        (use-package-cat-maybes
+         (list (use-package-expand name-string ":config"
+                 (plist-get args :config)))
+
+         (mapcar #'(lambda (var)
+                     (if (listp var)
+                         `(diminish (quote ,(car var)) ,(cdr var))
+                       `(diminish (quote ,var))))
+                 (plist-get args :diminish)))))
+
+    ;; Return the main body of the macro
+    (use-package-cat-maybes
+     ;; Setup the load-path
+     (mapcar #'(lambda (path) `(add-to-list 'load-path ,path))
+             (plist-get args :load-path))
+
+     ;; Setup any required autoloads
+     (if defer-loading
+         (mapcar #'(lambda (command) `(autoload #',command ,name-string nil t))
+                 commands))
+
+     (when (bound-and-true-p byte-compile-current-file)
+       (mapcar #'(lambda (fn)
+                   `(declare-function ,fn ,name-string))
+               (append (plist-get args* :functions) commands)))
+
+     ;; The user's initializations
+     (list (use-package-expand name-string ":init"
+             (plist-get args :init)))
+
+     (if defer-loading
+         (use-package-cat-maybes
+          bindings
+          (if config-body
+              (let ((body
+                     `(use-package-with-elapsed-timer
+                        ,(format "Configuring package %s"
+                                 name-string)
+                        ,@config-body)))
+                (list `(eval-after-load ,name-string
+                         ',body)))))
+       `((use-package-with-elapsed-timer
+           ,(format "Loading package %s" name-string)
+           (if (not (require ',name-symbol nil t))
+               (message "Could not load package %s" ,name-string)
+             ,@(use-package-cat-maybes
+                bindings
+                config-body)
+             t))))
+
+     ;; Any :idle form that should be executed later
+     (let ((idle-body (plist-get args :idle)))
+       (when idle-body
+         `((require 'use-package)
+           (use-package-init-on-idle
+            #'(lambda () ,(use-package-expand name-string ":idle" idle-body))
+            ,(plist-get args :idle-priority)))))
+
+     (list t))))
+
+(defmacro use-package (name &rest args)
+  "Declare an Emacs package by specifying a group of configuration options.
+
+For full documentation, please see the README file that came with
+this file.  Usage:
+
+  (use-package package-name
+     [:keyword [option]]...)
+
+:init          Code to run before PACKAGE-NAME has been loaded.
+:config        Code to run after PACKAGE-NAME has been loaded.  Note that if
+               loading is deferred for any reason, this code does not execute
+               until the lazy load has occurred.
+
+:mode          Form to be added to `auto-mode-alist'.
+:interpreter   Form to be added to `interpreter-mode-alist'.
+
+:commands      Define autoloads for commands that will be defined by the
+               package.  This is useful if the package is being lazily loaded,
+               and you wish to conditionally call functions in your `:init'
+               block that are defined in the package.
+
+:bind          Bind keys, and define autoloads for the bound commands.
+:bind*         Bind keys, and define autoloads for the bound commands,
+               *overriding all minor mode bindings*.
+:bind-keymap   Bind a key prefix to an auto-loaded keymap defined in the
+               package.  This is like `:bind', but for keymaps.
+:bind-keymap*  Like `:bind-keymap', but overrides all minor mode bindings
+
+:defer         Defer loading of a package -- this is implied when using
+               `:commands', `:bind', `:bind*', `:mode' or `:interpreter'.
+:demand        Prevent deferred loading in all cases.
+
+:if EXPR       Initialize and load only if EXPR evaluates to a non-nil value.
+:disabled      The package is ignored completely, the same as `:if nil'.
+:defines       Declare certain variables to silence the byte-compiler.
+:functions     Declare certain functions to silence the byte-compiler.
+:load-path     Add to the `load-path' before attempting to load the package.
+:diminish      Support for diminish.el (if installed).
+:idle          Adds a form to be run on an idle timer after initialization.
+:idle-priority Schedules the :idle form to run with the given priority (lower
+               priorities run first).  Default priority is 5; forms with the
+               same priority are run in the order in which they are evaluated.
+: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-string (if (stringp name) name (symbol-name name)))
+           (name-symbol (if (stringp name) (intern name) name))
+           (args*
+            (condition-case-unless-debug err
+                (use-package-normalize-plist name-symbol args)
+              (error (message (error-message-string err))))))
+
+      ;; Pin any packages that have been marked with `:pin'.
+      (let ((archive-name (plist-get args* :pin)))
+        (when archive-name
+          (use-package-pin-package name archive-name)))
+
+      ;; Ensure that the package has been installed, if marked with
+      ;; `:ensure'.
+      (let* ((ensure (plist-get args* :ensure))
+             (package-name (or (and (eq ensure t) name) 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 name-symbol name-string args*))
+           (pred (plist-get args* :if))
+           (expansion (if pred
+                          `(when ,pred ,@body)
+                        (if (= (length body) 1)
+                            (car body)
+                          `(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)
+                    (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)
+                          `(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.
+        (if (= (length body*) 1)
+            (car body*)
+          `(progn ,@body*))))))
+
+(defun use-package-autoload-keymap (keymap-symbol package override)
+  "Loads PACKAGE and then binds the key sequence used to invoke
+this function to KEYMAP-SYMBOL.  It then simulates pressing the
+same key sequence a again, so that the next key pressed is routed
+to the newly loaded keymap.
+
+This function supports use-package's :bind-keymap keyword.  It
+works by binding the given key sequence to an invocation of this
+function for a particular keymap.  The keymap is expected to be
+defined by the package.  In this way, loading the package is
+deferred until the prefix key sequence is pressed."
+  (if (not (require package nil t))
+      (error "Could not load package %s" package)
+    (if (and (boundp keymap-symbol)
+             (keymapp (symbol-value keymap-symbol)))
+        (let ((key (key-description (this-command-keys-vector)))
+              (keymap (symbol-value keymap-symbol)))
+          (if override
+              ;; eval form is necessary to avoid compiler error
+              `(eval `(bind-key* ,key ,keymap))
+            (bind-key key keymap))
+          (setq unread-command-events
+                (listify-key-sequence (this-command-keys-vector))))
+      (error "use-package: package %s failed to define keymap %s"
+             package keymap-symbol))))
+
+(defconst use-package-font-lock-keywords
+  '(("(\\(use-package\\(?:-with-elapsed-timer\\)?\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
+     (1 font-lock-keyword-face)
+     (2 font-lock-constant-face nil t))))
+
+(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :idle support
+;;
 
-(put 'use-package-with-elapsed-timer 'lisp-indent-function 1)
+(defcustom use-package-idle-interval 3
+  "Time to wait when using :idle in a `use-package' specification."
+  :type 'number
+  :group 'use-package)
 
 (defvar use-package-idle-timer nil)
 (defvar use-package-idle-forms (make-hash-table))
@@ -141,11 +593,12 @@ Return nil when the queue is empty."
     (if next
         (progn
           (when use-package-verbose
-            (message "use-package idle:%s" next))
+            (message "use-package idle: %s" next))
           (condition-case e
               (funcall next)
-            (error "Failure on use-package idle. Form: %s, Error: %s"
-                   next e))
+            (error
+             (error "Failure on use-package idle.  Form: %s, Error: %s"
+                    next e)))
           ;; recurse after a bit
           (when (sit-for use-package-idle-interval)
             (use-package-idle-eval)))
@@ -153,6 +606,11 @@ Return nil when the queue is empty."
       (cancel-timer use-package-idle-timer)
       (setq use-package-idle-timer nil))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :pin and :ensure support
+;;
+
 (eval-when-compile
   (defvar package-pinned-packages)
   (defvar package-archives))
@@ -191,344 +649,11 @@ manually updated package."
   (when (not (package-installed-p package))
     (package-install package)))
 
-(defvar use-package-keywords
-  '(:bind
-    :bind*
-    :commands
-    :config
-    :defer
-    :defines
-    :demand
-    :diminish
-    :disabled
-    :ensure
-    :idle
-    :idle-priority
-    :if
-    :init
-    :interpreter
-    :load-path
-    :mode
-    :pin
-    :pre-init
-    :pre-load
-    :requires
-    :bind-keymap
-    :bind-keymap*)
-  "Keywords recognized by `use-package'.")
-
-(defun use-package-mplist-get (plist prop)
-  "Get the values associated to PROP in PLIST, a modified plist.
-
-A modified plist is one where keys are keywords and values are
-all non-keywords elements that follow it.
-
-As a special case : if the first occurrence of the keyword PROP
-is followed by another keyword or is the last element in the
-list, the function returns t.
-
-Currently this function infloops when the list is circular."
-  (let ((tail plist) found result)
-    (while (and (consp tail)
-                (not (eq prop (car tail))))
-      (pop tail))
-    (when (eq prop (pop tail))
-      (setq found t))
-    (while (and (consp tail)
-                (not (keywordp (car tail))))
-      (push (pop tail) result))
-    (or (nreverse result) found)))
-
-(defun use-package-plist-get (plist prop &optional eval-backquote no-progn)
-  "Compatibility layer between classical and modified plists.
-
-If `use-package-mplist-get' returns exactly one value, that is
-returned ; otherwise the list is returned wrapped in a `progn'
-unless NO-PROGN is non-nil.
-
-When EVAL-BACKQUOTE is non-nil, the value is first evaluated as
-if it were backquoted."
-  (let ((values (use-package-mplist-get plist prop)))
-    (when eval-backquote
-      (setq values (eval (list 'backquote values))))
-    (when values
-      (cond ((not (listp values))
-             values)
-            ((eq 1 (length values))
-             (car values))
-            (t (if no-progn
-                   values
-                 (cons 'progn values)))))))
-
-(defun use-package-mplist-keys (plist)
-  "Get the keys in PLIST, a modified plist.
-
-A modified plist is one where properties are keywords and values
-are all non-keywords elements that follow it."
-  (let ((result))
-    (mapc #'(lambda (elt)
-              (when (keywordp elt)
-                (push elt result)))
-          plist)
-    (nreverse result)))
-
-(defun use-package-validate-keywords (args)
-  "Error if any keyword given in ARGS is not recognized.
-Return the list of recognized keywords."
-  (mapc #'(lambda (keyword)
-            (unless (memq keyword use-package-keywords)
-              (error "Unrecognized keyword: %s" keyword)))
-        (use-package-mplist-keys args)))
-
-(defsubst use-package-maybe-list (sym-or-list)
-  "If SYM-OR-LIST is just (a . b), return ((a . b))"
-  (if (and (consp sym-or-list)
-           (stringp (car sym-or-list)))
-      (list sym-or-list)
-    sym-or-list))
-
-(defmacro use-package (name &rest args)
-  "Use a package with configuration options.
-
-For full documentation. please see commentary.
-
-  (use-package package-name
-     :keyword option)
-
-:init Code to run when `use-package' form evals.
-:bind Perform key bindings, and define autoload for bound
-      commands.
-:bind* Perform key bindings, and define autoload for bound
-      commands, overriding all minor mode bindings.
-:bind-keymap Bind key prefix to an auto-loaded keymap that
-      is defined in the package.  Like bind but for keymaps
-      instead of commands.
-:bind-keymap* like bind-keymap, but overrides all minor mode bindings
-:commands Define autoloads for given commands.
-:pre-load Code to run when `use-package' form evals and before
-       anything else. Unlike :init this form runs before the
-       package is required or autoloads added.
-:mode Form to be added to `auto-mode-alist'.
-:interpreter Form to be added to `interpreter-mode-alist'.
-:defer Defer loading of package -- automatic
-       if :commands, :bind, :bind*, :mode or :interpreter are used.
-:demand Prevent deferred loading in all cases.
-:config Runs if and when package loads.
-:if Conditional loading.
-:disabled Ignore everything.
-:defines Define vars to silence byte-compiler.
-:load-path Add to `load-path' before loading.
-:diminish Support for diminish package (if it's installed).
-:idle adds a form to run on an idle timer
-:idle-priority schedules the :idle form to run with the given
-       priority (lower priorities run first). Default priority
-       is 5; forms with the same priority are run in the order in
-       which they are evaluated.
-:ensure loads package using package.el if necessary.
-:pin pin package to archive."
-  (use-package-validate-keywords args) ; error if any bad keyword, ignore result
-  ;; force this immediately -- one off cost
-  (unless (use-package-plist-get args :disabled)
-    (let* ((commands (use-package-plist-get args :commands t t))
-           (pre-init-body (use-package-plist-get args :pre-init))
-           (pre-load-body (use-package-plist-get args :pre-load))
-           init-body
-           (config-body (use-package-plist-get args :config))
-           (diminish-var (use-package-plist-get args :diminish t))
-           (defines (use-package-plist-get args :defines t t))
-           (idle-body (use-package-plist-get args :idle))
-           (idle-priority (use-package-plist-get args :idle-priority))
-           (keybindings-alist (use-package-plist-get args :bind t t))
-           (overriding-keybindings-alist (use-package-plist-get args :bind* t t))
-           (keymap-alist (use-package-plist-get args :bind-keymap t t))
-           (overriding-keymap-alist
-            (use-package-plist-get args :bind-keymap* t t))
-           (mode (use-package-plist-get args :mode t t))
-           (mode-alist
-            (if (stringp mode) (cons mode name) mode))
-           (interpreter (use-package-plist-get args :interpreter t t))
-           (interpreter-alist
-            (if (stringp interpreter) (cons interpreter name) interpreter))
-           (predicate (use-package-plist-get args :if))
-           (pkg-load-path (use-package-plist-get args :load-path t t))
-           (archive-name (use-package-plist-get args :pin))
-           (defines-eval (if (null defines)
-                             nil
-                           (if (listp defines)
-                               (mapcar #'(lambda (var) `(defvar ,var)) defines)
-                             `((defvar ,defines)))))
-           (requires (use-package-plist-get args :requires t))
-           (requires-test (if (null requires)
-                              t
-                            (if (listp requires)
-                                `(not (member nil (mapcar #'featurep
-                                                          (quote ,requires))))
-                              `(featurep (quote ,requires)))))
-           (name-string (if (stringp name) name (symbol-name name)))
-           (name-symbol (if (stringp name) (intern name) name)))
-
-      (when archive-name
-        (use-package-pin-package name archive-name))
-
-      (let* ((ensure (use-package-plist-get args :ensure))
-             (package-name (or (and (eq ensure t) name) ensure)))
-        (when package-name
-          (require 'package)
-          (use-package-ensure-elpa package-name)))
-
-      (if diminish-var
-          (setq
-           config-body
-           `(progn
-              ,config-body
-              (ignore-errors
-                ,@(cond
-                   ((stringp diminish-var)
-                    `((diminish (quote ,(intern (concat name-string "-mode")))
-                                ,diminish-var)))
-                   ((symbolp diminish-var)
-                    `((diminish (quote ,diminish-var))))
-                   ((and (consp diminish-var) (stringp (cdr diminish-var)))
-                    `((diminish (quote ,(car diminish-var))
-                                ,(cdr diminish-var))))
-                   (t           ; list of symbols or (symbol . "string") pairs
-                    (mapcar #'(lambda (var)
-                                (if (listp var)
-                                    `(diminish (quote ,(car var)) ,(cdr var))
-                                  `(diminish (quote ,var))))
-                            diminish-var)))))))
-
-      (if (and commands (symbolp commands))
-          (setq commands (list commands)))
-
-      (setq
-       init-body
-       (append
-        (mapcar #'(lambda (mode)
-                    (push (cdr mode) commands)
-                    `(add-to-list 'auto-mode-alist ',mode))
-                (use-package-maybe-list mode-alist))
-
-        (mapcar #'(lambda (interpreter)
-                    (push (cdr interpreter) commands)
-                    `(add-to-list 'interpreter-mode-alist ',interpreter))
-                (use-package-maybe-list interpreter-alist))
-
-        (mapcar #'(lambda (binding)
-                    (push (cdr binding) commands)
-                    `(bind-key ,(car binding) #',(cdr binding)))
-                (use-package-maybe-list keybindings-alist))
-
-        (mapcar #'(lambda (binding)
-                    (push (cdr binding) commands)
-                    `(bind-key* ,(car binding) #',(cdr binding)))
-                (use-package-maybe-list overriding-keybindings-alist))
-
-        (mapcar #'(lambda (binding)
-                    `(bind-key ,(car binding)
-                               #'(lambda () (interactive)
-                                   (use-package-autoload-keymap
-                                    ',(cdr binding) ,name-symbol nil))))
-                (use-package-maybe-list keymap-alist))
-
-        (mapcar #'(lambda (binding)
-                    `(bind-key ,(car binding)
-                               #'(lambda () (interactive)
-                                   (use-package-autoload-keymap
-                                    ',(cdr binding) ,name-symbol t))))
-                (use-package-maybe-list overriding-keymap-alist))
-
-        ;; First, execute the user's initializations
-        (list (use-package-plist-get args :init))
-
-        (when idle-body
-          (when (null idle-priority)
-            (setq idle-priority 5))
-          (list
-           `(progn
-              (require 'use-package)
-              (use-package-init-on-idle #'(lambda () ,idle-body)
-                                        ,idle-priority))))))
-
-      `(progn
-         ,pre-load-body
-         ,@(mapcar
-            #'(lambda (path)
-                `(add-to-list 'load-path
-                              ,(if (file-name-absolute-p path)
-                                   path
-                                 (expand-file-name path user-emacs-directory))))
-            (cond ((stringp pkg-load-path)
-                   (list pkg-load-path))
-                  ((functionp pkg-load-path)
-                   (funcall pkg-load-path))
-                  (t pkg-load-path)))
-
-         (eval-when-compile
-           (when (bound-and-true-p byte-compile-current-file)
-             ,@defines-eval
-             (with-demoted-errors
-                 ,(format "Error in %s: %%S" name)
-               (require ',name-symbol nil t))))
-
-         ,(if (and (or commands (use-package-plist-get args :defer))
-                   (not (use-package-plist-get args :demand)))
-              `(when ,(or predicate t)
-                 ,pre-init-body
-                 ,@(mapcar #'(lambda (command)
-                               `(autoload #',command ,name-string nil t))
-                           commands)
-                 ,@init-body
-                 ,(if (and config-body requires-test)
-                    `(eval-after-load ,name-string
-                       '(use-package-with-elapsed-timer
-                            ,(format "Configuring package %s" name-string)
-                          ,config-body)))
-                 t)
-            `(when (and ,(or predicate t) ,requires-test)
-               (use-package-with-elapsed-timer
-                   ,(format "Loading package %s" name-string)
-                 (if (not (require ',name-symbol nil t))
-                     (message "Could not load package %s" ,name-string)
-                   ,pre-init-body
-                   ,@init-body
-                   ,config-body
-                   t))))))))
-
-(defun use-package-autoload-keymap (keymap-symbol package override)
-  "Loads PACKAGE and then binds the key sequence used to invoke
-this function to KEYMAP-SYMBOL.  It then simulates pressing the
-same key sequence a again, so that the next key pressed is routed
-to the newly loaded keymap.
-
-This function supports use-package's :bind-keymap keyword.  It
-works by binding the given key sequence to an invocation of this
-function for a particular keymap.  The keymap is expected to be
-defined by the package.  In this way, loading the package is
-deferred until the prefix key sequence is pressed."
-  (if (not (require package nil t))
-      (error "Could not load package %s" package)
-    (if (and (boundp keymap-symbol)
-             (keymapp (symbol-value keymap-symbol)))
-        (let ((key (key-description (this-command-keys-vector)))
-              (keymap (symbol-value keymap-symbol)))
-          (if override
-              ;; eval form is necessary to avoid compiler error
-              `(eval `(bind-key* ,key ,keymap))
-            (bind-key key keymap))
-          (setq unread-command-events
-                (listify-key-sequence (this-command-keys-vector))))
-      (error "use-package: package %s failed to define keymap %s"
-             package keymap-symbol))))
-
 (put 'use-package 'lisp-indent-function 'defun)
-
-(defconst use-package-font-lock-keywords
-  '(("(\\(use-package\\(?:-with-elapsed-timer\\)?\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
-     (1 font-lock-keyword-face)
-     (2 font-lock-constant-face nil t))))
-
-(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
+(put 'use-package-expand 'lisp-indent-function 'defun)
+(put 'use-package-only-one 'lisp-indent-function 'defun)
+(put 'use-package-as-one 'lisp-indent-function 'defun)
+(put 'use-package-with-elapsed-timer 'lisp-indent-function 'defun)
 
 (provide 'use-package)