(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)
`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)
: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
(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)
(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.
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)
(nconc ys (list x)))))
(cons (cdr ys) (cdr zs))))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Keywords
+;;
+
(defun use-package-keyword-index (keyword)
(loop named outer
with index = 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)
;; 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,
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;;; :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)
(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)
(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
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)
`(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
`(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)
`((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)
(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
(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."
(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
(use-package-plist-append rest :commands commands))
state))))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :commands
-;;
+;;;; :commands
(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
(delete-dups arg))))
(use-package-process-keywords name rest state)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :defer
-;;
+;;;; :defer
(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
(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))
(`(,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)))
(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."
(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)
(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)))
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))
(setq body (use-package-require pkg nil body)))
body))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :config
-;;
+;;;; :config
(defalias 'use-package-normalize/:config 'use-package-normalize-forms)
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:
arg)
body)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; :delight
-;;
+;;;; :delight
(defun use-package-normalize-delight (name args)
"Normalize ARGS for a single call to `delight'."
(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: