1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-09 05:01:02 -08:00

Begin refactoring for 2.0; NOTE: BREAKING CHANGES

The major change is that :init is now always performed before loading a
file, whether loading is deferred or not.  This is a change from before,
where the semantics of :init varied between demand and defer.  The new
usage is now entirely consistent.

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

Lastly, an effort has been made to make your Emacs start even in the
presence of use-package configuration failures.  So after this change,
be sure to check your *Messages* buffer.  Most likely, you will have
several instances where you are using :init, but should be using :config
(this was the case for me in a number of places).
This commit is contained in:
John Wiegley 2015-03-14 05:22:43 -05:00
parent 0f76d766d9
commit 4ae584f3ff

View file

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