]> git.eshelyaron.com Git - emacs.git/commitdiff
Move functions around for better logical grouping
authorJohn Wiegley <johnw@newartisans.com>
Sun, 3 Dec 2017 19:43:16 +0000 (11:43 -0800)
committerJohn Wiegley <johnw@newartisans.com>
Sun, 3 Dec 2017 19:43:16 +0000 (11:43 -0800)
lisp/use-package/use-package.el

index fe307235c99ea4599d8982f780a7499293371ac4..16a1df6dc3fd0b320b7a340b9e98683a46ae7345 100644 (file)
 (require 'bind-key)
 (require 'bytecomp)
 (require 'cl-lib)
+
 (eval-when-compile
   (require 'cl)
-  (require 'regexp-opt))
-
-(declare-function package-installed-p "package")
-(declare-function package-read-all-archive-contents "package" ())
+  (require 'regexp-opt)
 
-(defconst use-package-version "2.4"
-  "This version of use-package.")
+  (declare-function package-installed-p "package")
+  (declare-function package-read-all-archive-contents "package" ()))
 
 (defgroup use-package nil
   "A use-package declaration for simplifying your `.emacs'."
   :group 'startup)
 
+(defconst use-package-version "2.4"
+  "This version of use-package.")
+
 (defcustom use-package-verbose nil
   "Whether to report about loading and configuration details.
 
 If you customize this, then you should require the `use-package'
 feature in files that use `use-package', even if these files only
-contain compiled expansions of the macros.  If you don't do so,
+contain compiled expansions of the macros. If you don't do so,
 then the expanded macros do their job silently."
-  :type '(choice (const :tag "Quiet" nil) (const :tag "Verbose" t)
+  :type '(choice (const :tag "Quiet" nil)
+                 (const :tag "Verbose" t)
                  (const :tag "Debug" debug))
   :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'."
+This check is performed by calling `locate-library'."
   :type 'boolean
   :group 'use-package)
 
 (defcustom use-package-always-defer nil
-  "If non-nil, assume `:defer t` unless `:demand t` is given."
+  "If non-nil, assume `:defer t' unless `:demand' is used.
+See also `use-package-defaults', which uses this value."
   :type 'boolean
   :group 'use-package)
 
 (defcustom use-package-always-demand nil
-  "If non-nil, assume `:demand t` unless `:defer t` is given."
+  "If non-nil, assume `:demand t' unless `:defer' is used.
+See also `use-package-defaults', which uses this value."
   :type 'boolean
   :group 'use-package)
 
 (defcustom use-package-always-ensure nil
-  "Treat every package as though it had specified `:ensure SEXP`."
+  "Treat every package as though it had specified using `:ensure SEXP'.
+See also `use-package-defaults', which uses this value."
   :type 'sexp
   :group 'use-package)
 
 (defcustom use-package-always-pin nil
-  "Treat every package as though it had specified `:pin SYM`."
+  "Treat every package as though it had specified using `:pin SYM'.
+See also `use-package-defaults', which uses this value."
   :type 'symbol
   :group 'use-package)
 
+(defcustom use-package-defaults
+  '(;; this '(t) has special meaning; see `use-package-handler/:config'
+    (:config '(t) t)
+    (: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
+element is the `use-package' keyword and the second is a form
+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. 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)
+
 (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
-to be reported at all.
-
-If you customize this, then you should require the `use-package'
-feature in files that use `use-package', even if these files only
-contain compiled expansions of the macros.  If you don't do so,
-then the expanded macros do their job silently."
+Note that `use-package-verbose' has to be set to a non-nil value
+for anything to be reported at all."
   :type 'number
   :group 'use-package)
 
@@ -120,10 +158,15 @@ This way, you can add to these hooks before evaluation of a
 `use-package` declaration, and exercise some control over what
 happens.
 
-Note that if either `pre-init' hooks returns a nil value, that
-block's user-supplied configuration is not evaluated, so be
-certain to return `t' if you only wish to add behavior to what
-the user specified."
+NOTE: These hooks are run even if the user does not specify an
+`:init' or `:config' block, and they will happen at the regular
+time when initialization and configuration would have been
+performed.
+
+NOTE: If the `pre-init' hook return a nil value, that block's
+user-supplied configuration is not evaluated, so be certain to
+return `t' if you only wish to add behavior to what the user
+had specified."
   :type 'boolean
   :group 'use-package)
 
@@ -160,30 +203,64 @@ the user specified."
     :config
     :diminish
     :delight)
-  "Establish which keywords are valid, and the order they are processed in.
-
-Note that `:disabled' is special, in that it causes nothing at all to happen,
-even if the rest of the use-package declaration is incorrect."
+  "The set of valid keywords, in the order they are processed in.
+The order of this list is *very important*, so it is only
+advisable to insert new keywords, never to delete or reorder
+them. Further, attention should be paid to the NEWS.md if the
+default order ever changes, as they may have subtle effects on
+the semantics of use-package declarations and may necessitate
+changing where you had inserted a new keyword earlier.
+
+Note that `:disabled' is special in this list, as it causes
+nothing at all to happen, even if the rest of the use-package
+declaration is incorrect."
   :type '(repeat symbol)
   :group 'use-package)
 
 (defcustom use-package-expand-minimally nil
   "If non-nil, make the expanded code as minimal as possible.
 This disables:
+
   - Printing to the *Messages* buffer of slowly-evaluating forms
-  - Capture of load errors (normally redisplayed as warnings)
+  - Capturing of load errors (normally redisplayed as warnings)
   - Conditional loading of packages (load failures become errors)
-The only advantage is that, if you know your configuration works,
-then your byte-compiled init file is as minimal as possible."
+
+The main advantage to this variable is that, if you know your
+configuration works, it will make the byte-compiled file as
+minimal as possible. It can also help with reading macro-expanded
+definitions, to understand the main intent of what's happening."
   :type 'boolean
   :group 'use-package)
 
+(defcustom use-package-form-regexp-eval
+  `(concat ,(eval-when-compile
+              (concat "^\\s-*("
+                      (regexp-opt '("use-package" "require") t)
+                      "\\s-+\\("))
+           (or (bound-and-true-p lisp-mode-symbol-regexp)
+               "\\(?:\\sw\\|\\s_\\|\\\\.\\)+") "\\)")
+  "Sexp providing regexp for finding use-package forms in user files.
+This is used by `use-package-jump-to-package-form' and
+`use-package-enable-imenu-support'."
+  :type 'sexp
+  :group 'use-package)
+
 (defcustom use-package-enable-imenu-support nil
   "If non-nil, adjust `lisp-imenu-generic-expression' to include
 support for finding `use-package' and `require' forms.
 
 Must be set before loading use-package."
   :type 'boolean
+  :set
+  #'(lambda (sym value)
+      (if value
+          (eval-after-load 'lisp-mode
+            `(add-to-list 'lisp-imenu-generic-expression
+                          (list "Packages" ,use-package-form-regexp-eval 2)))
+        (eval-after-load 'lisp-mode
+          `(setq lisp-imenu-generic-expression
+                 (remove (list "Packages" ,use-package-form-regexp-eval 2)
+                         lisp-imenu-generic-expression)))))
   :group 'use-package)
 
 (defcustom use-package-ensure-function 'use-package-ensure-elpa
@@ -204,125 +281,71 @@ The default value uses package.el to install the package."
                  (function :tag "Custom"))
   :group 'use-package)
 
-(defcustom use-package-defaults
-  '((: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
-element is the `use-package' keyword and the second is a form
-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. 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)
-                           "\\(?:\\sw\\|\\s_\\|\\\\.\\)+")))
-       (add-to-list
-        'lisp-imenu-generic-expression
-        (list "Packages"
-              (concat "^\\s-*("
-                      ,(eval-when-compile
-                         (regexp-opt '("use-package" "require") t))
-                      "\\s-+\\(" sym-regexp "\\)")
-              2)))))
-
-(defvar use-package-form-regexp "^\\s-*(\\s-*use-package\\s-+\\_<%s\\_>"
-  "Regexp used in `use-package-jump-to-package-form' to find use
-package forms in user files.")
-
-(defun use-package-find-require (package)
-  "Find file that required PACKAGE by searching
-`load-history'. Returns an absolute file path or nil if none is
-found."
-  (catch 'suspect
-    (dolist (filespec load-history)
-      (dolist (entry (cdr filespec))
-        (when (equal entry (cons 'require package))
-          (throw 'suspect (car filespec)))))))
+(defconst use-package-font-lock-keywords
+  '(("(\\(use-package\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
+     (1 font-lock-keyword-face)
+     (2 font-lock-constant-face nil t))))
 
-(defun use-package-jump-to-package-form (package)
-  "Attempt to find and jump to the `use-package' form that loaded
-PACKAGE. This will only find the form if that form actually
-required PACKAGE. If PACKAGE was previously required then this
-function will jump to the file that originally required PACKAGE
-instead."
-  (interactive (list (completing-read "Package: " features)))
-  (let* ((package (if (stringp package) (intern package) package))
-         (requiring-file (use-package-find-require package))
-         file location)
-    (if (null requiring-file)
-        (user-error "Can't find file that requires this feature.")
-      (setq file (if (string= (file-name-extension requiring-file) "elc")
-                     (concat (file-name-sans-extension requiring-file) ".el")
-                   requiring-file))
-      (when (file-exists-p file)
-        (find-file-other-window file)
-        (save-excursion
-          (goto-char (point-min))
-          (setq location
-                (re-search-forward
-                 (format use-package-form-regexp package) nil t)))
-        (if (null location)
-            (message "No use-package form found.")
-          (goto-char location)
-          (beginning-of-line))))))
+(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
 ;;; Utility functions
 ;;
 
-(defun use-package-as-symbol (string-or-symbol)
+(defsubst use-package-error (msg)
+  "Report MSG as an error, so the user knows it came from this package."
+  (error "use-package: %s" msg))
+
+(defsubst use-package-concat (&rest elems)
+  "Delete all empty lists from ELEMS (nil or (list nil)), and append them."
+  (apply #'append (delete nil (delete (list nil) elems))))
+
+(defsubst use-package-non-nil-symbolp (sym)
+  (and sym (symbolp sym)))
+
+(defsubst use-package-as-symbol (string-or-symbol)
   "If STRING-OR-SYMBOL is already a symbol, return it.  Otherwise
 convert it to a symbol and return that."
   (if (symbolp string-or-symbol) string-or-symbol
     (intern string-or-symbol)))
 
-(defun use-package-as-string (string-or-symbol)
+(defsubst use-package-as-string (string-or-symbol)
   "If STRING-OR-SYMBOL is already a string, return it.  Otherwise
 convert it to a string and return that."
   (if (stringp string-or-symbol) string-or-symbol
     (symbol-name string-or-symbol)))
 
+(defsubst use-package-regex-p (re)
+  "Return t if RE is some regexp-like thing."
+  (or (and (listp re) (eq (car re) 'rx))
+      (stringp re)))
+
+(defun use-package-normalize-regex (re)
+  "Given some regexp-like thing, resolve it down to a regular expression."
+  (cond
+   ((and (listp re) (eq (car re) 'rx)) (eval re))
+   ((stringp re) re)
+   (t (error "Not recognized as regular expression: %s" re))))
+
+(defsubst use-package-is-pair (x car-pred cdr-pred)
+  "Return non-nil if X is a cons satisfying the given predicates.
+CAR-PRED and CDR-PRED are applied to X's `car' and `cdr',
+respectively."
+  (and (consp x)
+       (funcall car-pred (car x))
+       (funcall cdr-pred (cdr x))))
+
 (defun use-package-as-mode (string-or-symbol)
   "If STRING-OR-SYMBOL ends in `-mode' (or its name does), return
 it as a symbol.  Otherwise, return it as a symbol with `-mode'
 appended."
   (let ((string (use-package-as-string string-or-symbol)))
-    (intern (if (string-match "-mode\\'" string) string
+    (intern (if (string-match "-mode\\'" string)
+                string
               (concat string "-mode")))))
 
-(defun use-package-load-name (name &optional noerror)
+(defsubst use-package-load-name (name &optional noerror)
   "Return a form which will load or require NAME depending on
 whether it's a string or symbol."
   (if (stringp name)
@@ -372,31 +395,18 @@ ARGS is a list of forms, so `((foo))' if only `foo' is being called."
     (if no-require
         body
       (use-package-with-elapsed-timer
-       (format "Loading package %s" name)
-       `((if (not ,(use-package-load-name name t))
-             (ignore
-              (display-warning 'use-package
-                               (format "Cannot load %s" ',name)
-                               :error))
-           ,@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))
-
-(defsubst use-package-plist-maybe-put (plist property value)
-  "Add a VALUE for PROPERTY to PLIST, if it does not already exist."
-  (if (plist-member plist property)
-      plist
-    (plist-put plist property value)))
-
-(defsubst use-package-plist-cons (plist property value)
-  "Cons VALUE onto the head of the list at PROPERTY in PLIST."
-  (plist-put plist property (cons value (plist-get plist property))))
+          (format "Loading package %s" name)
+        `((if (not ,(use-package-load-name name t))
+              (ignore
+               (display-warning 'use-package
+                                (format "Cannot load %s" ',name)
+                                :error))
+            ,@body))))))
 
-(defsubst use-package-plist-append (plist property value)
-  "Append VALUE onto the front of the list at PROPERTY in PLIST."
-  (plist-put plist property (append value (plist-get plist property))))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Property lists
+;;
 
 (defun use-package-plist-delete (plist property)
   "Delete PROPERTY from PLIST.
@@ -420,6 +430,20 @@ This is in contrast to merely setting it to 0."
               plist (cddr plist))))
     p))
 
+(defsubst use-package-plist-maybe-put (plist property value)
+  "Add a VALUE for PROPERTY to PLIST, if it does not already exist."
+  (if (plist-member plist property)
+      plist
+    (plist-put plist property value)))
+
+(defsubst use-package-plist-cons (plist property value)
+  "Cons VALUE onto the head of the list at PROPERTY in PLIST."
+  (plist-put plist property (cons value (plist-get plist property))))
+
+(defsubst use-package-plist-append (plist property value)
+  "Append VALUE onto the front of the list at PROPERTY in PLIST."
+  (plist-put plist property (append value (plist-get plist property))))
+
 (defun use-package-split-list (pred xs)
   (let ((ys (list nil)) (zs (list nil)) flip)
     (dolist (x xs)
@@ -432,6 +456,11 @@ This is in contrast to merely setting it to 0."
           (nconc ys (list x)))))
     (cons (cdr ys) (cdr zs))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Keywords
+;;
+
 (defun use-package-keyword-index (keyword)
   (loop named outer
         with index = 0
@@ -455,25 +484,6 @@ This is in contrast to merely setting it to 0."
         (setq result (cons (car x) (cons (cdr x) result))))
       result)))
 
-(defsubst use-package-concat (&rest elems)
-  "Delete all empty lists from ELEMS (nil or (list nil)), and append them."
-  (apply #'append (delete nil (delete (list nil) elems))))
-
-(defsubst use-package-non-nil-symbolp (sym)
-  (and sym (symbolp sym)))
-
-(defconst use-package-font-lock-keywords
-  '(("(\\(use-package\\)\\_>[ \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)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; Keyword processing
-;;
-
 (defun use-package-unalias-keywords (name args)
   (setq args (cl-nsubstitute :if :when args))
   (let (temp)
@@ -554,28 +564,6 @@ This is in contrast to merely setting it to 0."
     ;; Sort the list of keywords based on the order of `use-package-keywords'.
     (use-package-sort-keywords args)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; Normalization functions
-;;
-
-(defsubst use-package-regex-p (re)
-  "Return t if RE is some regexp-like thing."
-  (or (and (listp re)
-           (eq (car re) 'rx))
-      (stringp re)))
-
-(defun use-package-normalize-regex (re)
-  "Given some regexp-like thing, resolve it down to a regular expression."
-  (cond
-   ((and (listp re)
-         (eq (car re) 'rx))
-    (eval re))
-   ((stringp re)
-    re)
-   (t
-    (error "Not recognized as regular expression: %s" re))))
-
 (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,
@@ -638,17 +626,7 @@ next value for the STATE."
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
-;;; :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
+;;; Arguments
 ;;
 
 (defun use-package-only-one (label args f)
@@ -664,15 +642,280 @@ next value for the STATE."
 
 (put 'use-package-only-one 'lisp-indent-function 'defun)
 
-(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)"))))))
+(defun use-package-as-one (label args f &optional allow-empty)
+  "Call F on the first element of ARGS if it has one element, or all of ARGS.
+If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list."
+  (declare (indent 1))
+  (if (if args
+          (and (listp args) (listp (cdr args)))
+        allow-empty)
+      (if (= (length args) 1)
+          (funcall f label (car args))
+        (funcall f label args))
+    (use-package-error
+     (concat label " wants a non-empty list"))))
+
+(put 'use-package-as-one 'lisp-indent-function 'defun)
+
+(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)))))))
+
+(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)
+         `(funcall #',arg))
+        (t arg)))
+
+(defun use-package-normalize-symbols (label arg &optional recursed)
+  "Normalize a list of symbols."
+  (cond
+   ((use-package-non-nil-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-symlist (name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'use-package-normalize-symbols))
+
+(defun use-package-normalize-recursive-symbols (label arg)
+  "Normalize a list of symbols."
+  (cond
+   ((use-package-non-nil-symbolp arg)
+    arg)
+   ((and (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (use-package-normalize-recursive-symbols label x))
+            arg))
+   (t
+    (use-package-error
+     (concat label " wants a symbol, or nested list of symbols")))))
+
+(defun use-package-normalize-recursive-symlist (name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'use-package-normalize-recursive-symbols))
+
+(defun use-package-normalize-paths (label arg &optional recursed)
+  "Normalize a list of filesystem paths."
+  (cond
+   ((and arg (or (use-package-non-nil-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))))
+      (list path)))
+   ((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-normalize-predicate (name keyword args)
+  (if (null args)
+      t
+    (use-package-only-one (symbol-name keyword) args
+      #'use-package-normalize-value)))
+
+(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")))
+  (mapcar #'(lambda (form)
+              (if (and (consp form)
+                       (eq (car form) 'use-package))
+                  (macroexpand form)
+                form)) args))
+
+(defun use-package-normalize-forms (name keyword args)
+  (use-package-normalize-form (symbol-name keyword) args))
+
+(defun use-package-normalize-pairs
+    (key-pred val-pred name label arg &optional recursed)
+  "Normalize a list of pairs.
+KEY-PRED and VAL-PRED are predicates recognizing valid keys and
+values, respectively.
+If RECURSED is non-nil, recurse into sublists."
+  (cond
+   ((funcall key-pred arg)
+    (list (cons arg (use-package-as-symbol name))))
+   ((use-package-is-pair arg key-pred val-pred)
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (let (last-item)
+      (mapcar
+       #'(lambda (x)
+           (prog1
+               (let ((ret (use-package-normalize-pairs
+                           key-pred val-pred name label x t)))
+                 ;; Currently, the handling of keyword arguments by
+                 ;; `use-package' and `bind-key' is non-uniform and
+                 ;; undocumented. As a result, `use-package-normalize-pairs'
+                 ;; (as it is currently implemented) does not correctly handle
+                 ;; the keyword-argument syntax of `bind-keys'. A permanent
+                 ;; solution to this problem will require a careful
+                 ;; consideration of the desired keyword-argument interface
+                 ;; for `use-package' and `bind-key'. However, in the
+                 ;; meantime, we have a quick patch to fix a serious bug in
+                 ;; the handling of keyword arguments. Namely, the code below
+                 ;; would normally unwrap lists that were passed as keyword
+                 ;; arguments (for example, the `:filter' argument in `:bind')
+                 ;; without the (not (keywordp last-item)) clause. See #447
+                 ;; for further discussion.
+                 (if (and (listp ret)
+                          (not (keywordp last-item)))
+                     (car ret)
+                   ret))
+             (setq last-item x))) arg)))
+   (t arg)))
+
+(defun use-package-recognize-function (v &optional binding additional-pred)
+  "A predicate that recognizes functional constructions:
+  nil
+  sym
+  'sym
+  (quote sym)
+  #'sym
+  (function sym)
+  (lambda () ...)
+  '(lambda () ...)
+  (quote (lambda () ...))
+  #'(lambda () ...)
+  (function (lambda () ...))"
+  (pcase v
+    ((and x (guard (if binding
+                       (symbolp x)
+                     (use-package-non-nil-symbolp x)))) t)
+    (`(,(or `quote `function)
+       ,(pred use-package-non-nil-symbolp)) t)
+    ((and x (guard (if binding (commandp x) (functionp x)))) t)
+    (_ (and additional-pred
+            (funcall additional-pred v)))))
+
+(defun use-package-normalize-function (v)
+  "Reduce functional constructions to one of two normal forms:
+  sym
+  #'(lambda () ...)"
+  (pcase v
+    ((pred symbolp) v)
+    (`(,(or `quote `function)
+       ,(and sym (pred symbolp))) sym)
+    (`(lambda . ,_) v)
+    (`(quote ,(and lam `(lambda . ,_))) lam)
+    (`(function ,(and lam `(lambda . ,_))) lam)
+    (_ v)))
+
+(defun use-package-normalize-commands (args)
+  "Map over ARGS of the form ((_ . F) ...).
+Normalizing functional F's and returning a list of F's
+representing symbols (that may need to be autloaded)."
+  (let ((nargs (mapcar
+                #'(lambda (x)
+                    (if (consp x)
+                        (cons (car x)
+                              (use-package-normalize-function (cdr x)))
+                      x)) args)))
+    (cons nargs
+          (delete
+           nil (mapcar
+                #'(lambda (x)
+                    (and (consp x)
+                         (use-package-non-nil-symbolp (cdr x))
+                         (cdr x))) nargs)))))
+
+(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 (<string or vector> . <symbol, string or function>)"
+                   " 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))))
+
+;;;###autoload
+(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))
+      (use-package-error (format "Cannot load package.el: %s" package))
+    (if (and (boundp keymap-symbol)
+             (keymapp (symbol-value keymap-symbol)))
+        (let* ((kv (this-command-keys-vector))
+               (key (key-description kv))
+               (keymap (symbol-value keymap-symbol)))
+          (if override
+              (bind-key* key keymap)
+            (bind-key key keymap))
+          (setq unread-command-events
+                (listify-key-sequence kv)))
+      (use-package-error
+       (format "use-package: package.el %s failed to define keymap %s"
+               package keymap-symbol)))))
+
+(defun use-package-normalize-mode (name keyword args)
+  "Normalize arguments for keywords which add regexp/mode pairs to an alist."
+  (use-package-as-one (symbol-name keyword) args
+    (apply-partially #'use-package-normalize-pairs
+                     #'use-package-regex-p
+                     #'use-package-recognize-function
+                     name)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Handlers
+;;
+
+;;;; :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
+
+(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)"))))))
 
 (eval-when-compile
   (defvar package-pinned-packages)
@@ -716,11 +959,10 @@ manually updated package."
       (push pin-form body))          ; or else wait until runtime.
     body))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :ensure
-;;
+;;;; :ensure
+
 (defvar package-archive-contents)
+
 (defun use-package-normalize/:ensure (name keyword args)
   (if (null args)
       t
@@ -773,89 +1015,29 @@ manually updated package."
             body))
     body))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :if, :when and :unless
-;;
-
-(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)
-         `(funcall #',arg))
-        (t arg)))
+;;;; :if, :when and :unless
 
 (defun use-package-normalize-test (name keyword args)
   (use-package-only-one (symbol-name keyword) args
     #'use-package-normalize-value))
 
 (defalias 'use-package-normalize/:if 'use-package-normalize-test)
-(defalias 'use-package-normalize/:when 'use-package-normalize-test)
-(defalias 'use-package-normalize/:unless 'use-package-normalize-test)
 
 (defun use-package-handler/:if (name keyword pred rest state)
   (let ((body (use-package-process-keywords name rest state)))
     `((when ,pred ,@body))))
 
+(defalias 'use-package-normalize/:when 'use-package-normalize-test)
+
 (defalias 'use-package-handler/:when 'use-package-handler/:if)
 
+(defalias 'use-package-normalize/:unless 'use-package-normalize-test)
+
 (defun use-package-handler/:unless (name keyword pred rest state)
   (let ((body (use-package-process-keywords name rest state)))
     `((unless ,pred ,@body))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :requires
-;;
-
-(defun use-package-as-one (label args f &optional allow-empty)
-  "Call F on the first element of ARGS if it has one element, or all of ARGS.
-If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list."
-  (declare (indent 1))
-  (if (if args
-          (and (listp args) (listp (cdr args)))
-        allow-empty)
-      (if (= (length args) 1)
-          (funcall f label (car args))
-        (funcall f label args))
-    (use-package-error
-     (concat label " wants a non-empty list"))))
-
-(put 'use-package-as-one 'lisp-indent-function 'defun)
-
-(defun use-package-normalize-symbols (label arg &optional recursed)
-  "Normalize a list of symbols."
-  (cond
-   ((use-package-non-nil-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-symlist (name keyword args)
-  (use-package-as-one (symbol-name keyword) args
-    #'use-package-normalize-symbols))
-
-(defun use-package-normalize-recursive-symbols (label arg)
-  "Normalize a list of symbols."
-  (cond
-   ((use-package-non-nil-symbolp arg)
-    arg)
-   ((and (listp arg) (listp (cdr arg)))
-    (mapcar #'(lambda (x) (use-package-normalize-recursive-symbols label x))
-            arg))
-   (t
-    (use-package-error
-     (concat label " wants a symbol, or nested list of symbols")))))
-
-(defun use-package-normalize-recursive-symlist (name keyword args)
-  (use-package-as-one (symbol-name keyword) args
-    #'use-package-normalize-recursive-symbols))
+;;;; :requires
 
 (defalias 'use-package-normalize/:requires 'use-package-normalize-symlist)
 
@@ -868,28 +1050,7 @@ If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list."
                  `(featurep ',(car requires)))
           ,@body)))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :load-path
-;;
-
-(defun use-package-normalize-paths (label arg &optional recursed)
-  "Normalize a list of filesystem paths."
-  (cond
-   ((and arg (or (use-package-non-nil-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))))
-      (list path)))
-   ((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")))))
+;;;; :load-path
 
 (defun use-package-normalize/:load-path (name keyword args)
   (use-package-as-one (symbol-name keyword) args
@@ -902,39 +1063,14 @@ If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list."
                  `(eval-and-compile (add-to-list 'load-path ,path))) arg)
      body)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :no-require
-;;
-
-(defun use-package-normalize-predicate (name keyword args)
-  (if (null args)
-      t
-    (use-package-only-one (symbol-name keyword) args
-      #'use-package-normalize-value)))
+;;;; :no-require
 
 (defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate)
 
 (defun use-package-handler/:no-require (name keyword arg rest state)
   (use-package-process-keywords name rest state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :preface
-;;
-
-(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")))
-  (mapcar #'(lambda (form)
-              (if (and (consp form)
-                       (eq (car form) 'use-package))
-                  (macroexpand form)
-                form)) args))
-
-(defun use-package-normalize-forms (name keyword args)
-  (use-package-normalize-form (symbol-name keyword) args))
+;;;; :preface
 
 (defalias 'use-package-normalize/:preface 'use-package-normalize-forms)
 
@@ -945,146 +1081,21 @@ 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*
-;;
+;;;; :defines
 
-(defsubst use-package-is-pair (x car-pred cdr-pred)
-  "Return non-nil if X is a cons satisfying the given predicates.
-CAR-PRED and CDR-PRED are applied to X's `car' and `cdr',
-respectively."
-  (and (consp x)
-       (funcall car-pred (car x))
-       (funcall cdr-pred (cdr x))))
+(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist)
 
-(defun use-package-normalize-pairs
-    (key-pred val-pred name label arg &optional recursed)
-  "Normalize a list of pairs.
-KEY-PRED and VAL-PRED are predicates recognizing valid keys and
-values, respectively.
-If RECURSED is non-nil, recurse into sublists."
-  (cond
-   ((funcall key-pred arg)
-    (list (cons arg (use-package-as-symbol name))))
-   ((use-package-is-pair arg key-pred val-pred)
-    (list arg))
-   ((and (not recursed) (listp arg) (listp (cdr arg)))
-    (let (last-item)
-      (mapcar
-       #'(lambda (x)
-           (prog1
-               (let ((ret (use-package-normalize-pairs
-                           key-pred val-pred name label x t)))
-                 ;; Currently, the handling of keyword arguments by
-                 ;; `use-package' and `bind-key' is non-uniform and
-                 ;; undocumented. As a result, `use-package-normalize-pairs'
-                 ;; (as it is currently implemented) does not correctly handle
-                 ;; the keyword-argument syntax of `bind-keys'. A permanent
-                 ;; solution to this problem will require a careful
-                 ;; consideration of the desired keyword-argument interface
-                 ;; for `use-package' and `bind-key'. However, in the
-                 ;; meantime, we have a quick patch to fix a serious bug in
-                 ;; the handling of keyword arguments. Namely, the code below
-                 ;; would normally unwrap lists that were passed as keyword
-                 ;; arguments (for example, the `:filter' argument in `:bind')
-                 ;; without the (not (keywordp last-item)) clause. See #447
-                 ;; for further discussion.
-                 (if (and (listp ret)
-                          (not (keywordp last-item)))
-                     (car ret)
-                   ret))
-             (setq last-item x))) arg)))
-   (t arg)))
+(defun use-package-handler/:defines (name keyword arg rest state)
+  (use-package-process-keywords name rest state))
 
-(defun use-package-recognize-function (v &optional binding additional-pred)
-  "A predicate that recognizes functional constructions:
-  nil
-  sym
-  'sym
-  (quote sym)
-  #'sym
-  (function sym)
-  (lambda () ...)
-  '(lambda () ...)
-  (quote (lambda () ...))
-  #'(lambda () ...)
-  (function (lambda () ...))"
-  (pcase v
-    ((and x (guard (if binding
-                       (symbolp x)
-                     (use-package-non-nil-symbolp x)))) t)
-    (`(,(or `quote `function)
-       ,(pred use-package-non-nil-symbolp)) t)
-    ((and x (guard (if binding (commandp x) (functionp x)))) t)
-    (_ (and additional-pred
-            (funcall additional-pred v)))))
+;;;; :functions
 
-(defun use-package-normalize-function (v)
-  "Reduce functional constructions to one of two normal forms:
-  sym
-  #'(lambda () ...)"
-  (pcase v
-    ((pred symbolp) v)
-    (`(,(or `quote `function)
-       ,(and sym (pred symbolp))) sym)
-    (`(lambda . ,_) v)
-    (`(quote ,(and lam `(lambda . ,_))) lam)
-    (`(function ,(and lam `(lambda . ,_))) lam)
-    (_ v)))
+(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist)
 
-(defun use-package-normalize-commands (args)
-  "Map over ARGS of the form ((_ . F) ...).
-Normalizing functional F's and returning a list of F's
-representing symbols (that may need to be autloaded)."
-  (let ((nargs (mapcar
-                #'(lambda (x)
-                    (if (consp x)
-                        (cons (car x)
-                              (use-package-normalize-function (cdr x)))
-                      x)) args)))
-    (cons nargs
-          (delete
-           nil (mapcar
-                #'(lambda (x)
-                    (and (consp x)
-                         (use-package-non-nil-symbolp (cdr x))
-                         (cdr x))) nargs)))))
+(defun use-package-handler/:functions (name keyword arg rest state)
+  (use-package-process-keywords name rest state))
 
-(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 (<string or vector> . <symbol, string or function>)"
-                   " 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))))
+;;;; :bind, :bind*
 
 (defalias 'use-package-normalize/:bind 'use-package-normalize-binder)
 (defalias 'use-package-normalize/:bind* 'use-package-normalize-binder)
@@ -1105,42 +1116,11 @@ representing symbols (that may need to be autloaded)."
 (defun use-package-handler/:bind* (name keyword arg rest state)
   (use-package-handler/:bind name keyword arg rest state 'bind-keys*))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :bind-keymap, :bind-keymap*
-;;
+;;;; :bind-keymap, :bind-keymap*
 
 (defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder)
 (defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder)
 
-;;;###autoload
-(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))
-      (use-package-error (format "Cannot load package.el: %s" package))
-    (if (and (boundp keymap-symbol)
-             (keymapp (symbol-value keymap-symbol)))
-        (let* ((kv (this-command-keys-vector))
-               (key (key-description kv))
-               (keymap (symbol-value keymap-symbol)))
-          (if override
-              (bind-key* key keymap)
-            (bind-key key keymap))
-          (setq unread-command-events
-                (listify-key-sequence kv)))
-      (use-package-error
-       (format "use-package: package.el %s failed to define keymap %s"
-               package keymap-symbol)))))
-
 (defun use-package-handler/:bind-keymap
     (name keyword arg rest state &optional override)
   (let ((form
@@ -1162,18 +1142,7 @@ deferred until the prefix key sequence is pressed."
 (defun use-package-handler/:bind-keymap* (name keyword arg rest state)
   (use-package-handler/:bind-keymap name keyword arg rest state t))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :interpreter
-;;
-
-(defun use-package-normalize-mode (name keyword args)
-  "Normalize arguments for keywords which add regexp/mode pairs to an alist."
-  (use-package-as-one (symbol-name keyword) args
-    (apply-partially #'use-package-normalize-pairs
-                     #'use-package-regex-p
-                     #'use-package-recognize-function
-                     name)))
+;;;; :interpreter
 
 (defun use-package-handle-mode (name alist args rest state)
   "Handle keywords which add regexp/mode pairs to an alist."
@@ -1197,40 +1166,28 @@ deferred until the prefix key sequence is pressed."
 (defun use-package-handler/:interpreter (name keyword arg rest state)
   (use-package-handle-mode name 'interpreter-mode-alist arg rest state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :mode
-;;
+;;;; :mode
 
 (defalias 'use-package-normalize/:mode 'use-package-normalize-mode)
 
 (defun use-package-handler/:mode (name keyword arg rest state)
   (use-package-handle-mode name 'auto-mode-alist arg rest state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :magic
-;;
+;;;; :magic
 
 (defalias 'use-package-normalize/:magic 'use-package-normalize-mode)
 
 (defun use-package-handler/:magic (name keyword arg rest state)
   (use-package-handle-mode name 'magic-mode-alist arg rest state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :magic-fallback
-;;
+;;;; :magic-fallback
 
 (defalias 'use-package-normalize/:magic-fallback 'use-package-normalize-mode)
 
 (defun use-package-handler/:magic-fallback (name keyword arg rest state)
   (use-package-handle-mode name 'magic-fallback-mode-alist arg rest state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :hook
-;;
+;;;; :hook
 
 (defun use-package-normalize/:hook (name keyword args)
   (use-package-as-one (symbol-name keyword) args
@@ -1273,10 +1230,7 @@ deferred until the prefix key sequence is pressed."
         (use-package-plist-append rest :commands commands))
        state))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :commands
-;;
+;;;; :commands
 
 (defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
 
@@ -1298,10 +1252,7 @@ deferred until the prefix key sequence is pressed."
         (delete-dups arg))))
    (use-package-process-keywords name rest state)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :defer
-;;
+;;;; :defer
 
 (defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
 
@@ -1318,10 +1269,7 @@ deferred until the prefix key sequence is pressed."
        (list (use-package-require-after-load
               name (macroexp-progn body)))))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :after
-;;
+;;;; :after
 
 (defun use-package-normalize/:after (name keyword args)
   (setq args (use-package-normalize-recursive-symlist name keyword args))
@@ -1364,20 +1312,6 @@ no keyword implies `:all'."
     (`(,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 state))
         (uses (use-package-after-count-uses arg)))
@@ -1390,20 +1324,14 @@ no more than once."
          (apply-partially #'use-package-require-after-load arg)
          (macroexp-progn body))))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :demand
-;;
+;;;; :demand
 
 (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 state))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :custom
-;;
+;;;; :custom
 
 (defun use-package-normalize/:custom (name keyword args)
   "Normalize use-package custom keyword."
@@ -1420,24 +1348,24 @@ no more than once."
 (defun use-package-handler/:custom (name keyword args rest state)
   "Generate use-package custom keyword code."
   (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)
+   (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)
    (use-package-process-keywords name rest state)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :custom-face
-;;
+;;;; :custom-face
 
 (defun use-package-normalize/:custom-face (name-symbol keyword arg)
   "Normalize use-package custom-face keyword."
-  (let ((error-msg (format "%s wants a (<symbol> <face-spec>) or list of these" name-symbol)))
+  (let ((error-msg
+         (format "%s wants a (<symbol> <face-spec>) or list of these"
+                 name-symbol)))
     (unless (listp arg)
       (use-package-error error-msg))
     (dolist (def arg arg)
@@ -1456,16 +1384,12 @@ no more than once."
    (mapcar #'(lambda (def) `(custom-set-faces (quote ,def))) args)
    (use-package-process-keywords name rest state)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :init
-;;
+;;;; :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)))
@@ -1475,10 +1399,7 @@ no more than once."
        init-body))
    (use-package-process-keywords name rest state)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :load
-;;
+;;;; :load
 
 (defun use-package-normalize/:load (name keyword args)
   (setq args (use-package-normalize-recursive-symlist name keyword args))
@@ -1492,10 +1413,7 @@ no more than once."
       (setq body (use-package-require pkg nil body)))
     body))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :config
-;;
+;;;; :config
 
 (defalias 'use-package-normalize/:config 'use-package-normalize-forms)
 
@@ -1513,10 +1431,7 @@ no more than once."
          body
          (list t))))))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :diminish
-;;
+;;;; :diminish
 
 (defun use-package-normalize-diminish (name label arg &optional recursed)
   "Normalize the arguments to diminish down to a list of one of two forms:
@@ -1554,10 +1469,7 @@ no more than once."
              arg)
      body)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :delight
-;;
+;;;; :delight
 
 (defun use-package-normalize-delight (name args)
   "Normalize ARGS for a single call to `delight'."
@@ -1712,6 +1624,47 @@ this file.  Usage:
 
 (put 'use-package 'lisp-indent-function 'defun)
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Jump to declaration
+;;
+
+(defun use-package-find-require (package)
+  "Find file that required PACKAGE by searching `load-history'.
+Returns an absolute file path or nil if none is found."
+  (catch 'suspect
+    (dolist (filespec load-history)
+      (dolist (entry (cdr filespec))
+        (when (equal entry (cons 'require package))
+          (throw 'suspect (car filespec)))))))
+
+(defun use-package-jump-to-package-form (package)
+  "Attempt to find and jump to the `use-package' form that loaded
+PACKAGE. This will only find the form if that form actually
+required PACKAGE. If PACKAGE was previously required then this
+function will jump to the file that originally required PACKAGE
+instead."
+  (interactive (list (completing-read "Package: " features)))
+  (let* ((package (if (stringp package) (intern package) package))
+         (requiring-file (use-package-find-require package))
+         file location)
+    (if (null requiring-file)
+        (user-error "Can't find file requiring file; may have been autoloaded")
+      (setq file (if (string= (file-name-extension requiring-file) "elc")
+                     (concat (file-name-sans-extension requiring-file) ".el")
+                   requiring-file))
+      (when (file-exists-p file)
+        (find-file-other-window file)
+        (save-excursion
+          (goto-char (point-min))
+          (setq location
+                (re-search-forward
+                 (format (eval use-package-form-regexp-eval) package) nil t)))
+        (if (null location)
+            (message "No use-package form found.")
+          (goto-char location)
+          (beginning-of-line))))))
+
 (provide 'use-package)
 
 ;; Local Variables: