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