summaryrefslogtreecommitdiff
path: root/.emacs.d/site-lisp/use-package.el
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d/site-lisp/use-package.el')
-rw-r--r--.emacs.d/site-lisp/use-package.el1359
1 files changed, 982 insertions, 377 deletions
diff --git a/.emacs.d/site-lisp/use-package.el b/.emacs.d/site-lisp/use-package.el
index 36e7e0b7..6feb0d84 100644
--- a/.emacs.d/site-lisp/use-package.el
+++ b/.emacs.d/site-lisp/use-package.el
@@ -3,11 +3,12 @@
;; Copyright (C) 2012 John Wiegley
;; Author: John Wiegley <jwiegley@gmail.com>
+;; Maintainer: 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
+;; URL: https://github.com/jwiegley/use-package
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
@@ -23,7 +24,7 @@
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
-
+
;;; Commentary:
;; The `use-package' declaration macro allows you to isolate package
@@ -34,418 +35,1022 @@
;; functionality!
;;
;; Please see README.md from the same repository for documentation.
-
+
;;; Code:
(require 'bind-key)
(require 'bytecomp)
(require 'diminish nil t)
+(require 'bytecomp)
+(eval-when-compile (require 'cl))
-(when (fboundp 'declare-function)
- (declare-function package-installed-p 'package))
+(declare-function package-installed-p 'package)
(defgroup use-package nil
"A use-package declaration for simplifying your `.emacs'."
:group 'startup)
(defcustom use-package-verbose nil
- "Whether to report about loading and configuration details."
+ "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,
+then the expanded macros do their job silently."
:type 'boolean
:group 'use-package)
-(defcustom use-package-minimum-reported-time 0.01
- "Minimal load time that will be reported"
- :type 'number
+(defcustom use-package-debug nil
+ "Whether to display use-package expansions in a *use-package* buffer."
+ :type 'boolean
:group 'use-package)
-(defcustom use-package-idle-interval 3
- "Time to wait when using :idle in a `use-package' specification."
+(defcustom use-package-always-ensure nil
+ "Treat every package as though it had specified `:ensure SEXP`."
+ :type 'sexp
+ :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."
:type 'number
:group 'use-package)
-(defmacro use-package-with-elapsed-timer (text &rest body)
+(defcustom use-package-inject-hooks nil
+ "If non-nil, add hooks to the `:init' and `:config' sections.
+In particular, for a given package `foo', the following hooks
+become available:
+
+ `use-package--foo--pre-init-hook'
+ `use-package--foo--post-init-hook'
+ `use-package--foo--pre-config-hook'
+ `use-package--foo--post-config-hook'
+
+This way, you can add to these hooks before evalaution of a
+`use-package` declaration, and exercise some control over what
+happens.
+
+Note that if either `pre-init' hooks returns a nil value, that
+block's user-supplied configuration is not evaluated, so be
+certain to return `t' if you only wish to add behavior to what
+the user specified."
+ :type 'boolean
+ :group 'use-package)
+
+(defcustom use-package-keywords
+ '(:disabled
+ :pin
+ :ensure
+ :if
+ :when
+ :unless
+ :requires
+ :load-path
+ :preface
+ :no-require
+ :bind
+ :bind*
+ :bind-keymap
+ :bind-keymap*
+ :interpreter
+ :mode
+ :commands
+ :defines
+ :functions
+ :defer
+ :demand
+ :init
+ :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."
+ :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)
+ - 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."
+ :type 'boolean
+ :group 'use-package)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Utility functions
+;;
+
+(defun use-package-expand (name label form)
+ "FORM is a list of forms, so `((foo))' if only `foo' is being called."
(declare (indent 1))
- (let ((nowvar (make-symbol "now")))
- `(if use-package-verbose
- (let ((,nowvar (current-time)))
- (message "%s..." ,text)
- (prog1 (progn ,@body)
- (let ((elapsed
- (float-time (time-subtract (current-time) ,nowvar))))
- (if (> elapsed ,use-package-minimum-reported-time)
- (message "%s...done (%.3fs)" ,text elapsed)
- (message "%s...done" ,text)))))
- ,@body)))
-
-(put 'use-package-with-elapsed-timer 'lisp-indent-function 1)
-
-(defvar use-package-idle-timer nil)
-(defvar use-package-idle-forms (make-hash-table))
-
-(defun use-package-start-idle-timer ()
- "Ensure that the idle timer is running."
- (unless use-package-idle-timer
- (setq use-package-idle-timer
- (run-with-idle-timer
- use-package-idle-interval t
- 'use-package-idle-eval))))
-
-(defun use-package-init-on-idle (form priority)
- "Add a new form to the idle queue."
- (use-package-start-idle-timer)
- (puthash priority
- (append (gethash priority use-package-idle-forms)
- (list form))
- use-package-idle-forms))
-
-(defun use-package-idle-priorities ()
- "Get a list of all priorities in the idle queue.
-The list is sorted in the order forms should be run."
- (let ((priorities nil))
- (maphash (lambda (priority forms)
- (setq priorities (cons priority priorities)))
- use-package-idle-forms)
- (sort priorities '<)))
-
-(defun use-package-idle-pop ()
- "Pop the top-priority task from the idle queue.
-Return nil when the queue is empty."
- (let* ((priority (car (use-package-idle-priorities)))
- (forms (gethash priority use-package-idle-forms))
- (first-form (car forms))
- (forms-remaining (cdr forms)))
- (if forms-remaining
- (puthash priority forms-remaining use-package-idle-forms)
- (remhash priority use-package-idle-forms))
- first-form))
-
-(defun use-package-idle-eval()
- "Start to eval idle-commands from the idle queue."
- (let ((next (use-package-idle-pop)))
- (if next
- (progn
- (when use-package-verbose
- (message "use-package idle:%s" next))
-
- (condition-case e
- (funcall next)
+ (when form
+ (if use-package-expand-minimally
+ form
+ (let ((err (make-symbol "err")))
+ (list
+ `(condition-case-unless-debug ,err
+ ,(macroexp-progn form)
(error
- (message
- "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)))
- ;; finished (so far!)
- (cancel-timer use-package-idle-timer)
- (setq use-package-idle-timer nil))))
+ (ignore
+ (display-warning 'use-package
+ (format "%s %s: %s"
+ ,name ,label (error-message-string ,err))
+ :error)))))))))
+
+(put 'use-package-expand 'lisp-indent-function 'defun)
+
+(defun use-package-hook-injector (name-string keyword body)
+ "Wrap pre/post hook injections around a given keyword form.
+ARGS is a list of forms, so `((foo))' if only `foo' is being called."
+ (if (not use-package-inject-hooks)
+ (use-package-expand name-string (format "%s" keyword) body)
+ (let ((keyword-name (substring (format "%s" keyword) 1)))
+ (when body
+ `((when ,(macroexp-progn
+ (use-package-expand name-string (format "pre-%s hook" keyword)
+ `(run-hook-with-args-until-failure
+ ',(intern (concat "use-package--" name-string
+ "--pre-" keyword-name "-hook")))))
+ ,(macroexp-progn
+ (use-package-expand name-string (format "%s" keyword) body))
+ ,(macroexp-progn
+ (use-package-expand name-string (format "post-%s hook" keyword)
+ `(run-hooks
+ ',(intern (concat "use-package--" name-string
+ "--post-" keyword-name "-hook")))))))))))
+
+(defun use-package--with-elapsed-timer (text body)
+ "BODY is a list of forms, so `((foo))' if only `foo' is being called."
+ (declare (indent 1))
+ (if use-package-expand-minimally
+ body
+ (let ((nowvar (make-symbol "now")))
+ (if (bound-and-true-p use-package-verbose)
+ `((let ((,nowvar (current-time)))
+ (message "%s..." ,text)
+ (prog1
+ ,(macroexp-progn body)
+ (let ((elapsed
+ (float-time (time-subtract (current-time) ,nowvar))))
+ (if (> elapsed ,use-package-minimum-reported-time)
+ (message "%s...done (%.3fs)" ,text elapsed)
+ (message "%s...done" ,text))))))
+ 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))
+
+(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-plist-delete (plist property)
+ "Delete PROPERTY from PLIST.
+This is in contrast to merely setting it to 0."
+ (let (p)
+ (while plist
+ (if (not (eq property (car plist)))
+ (setq p (plist-put p (car plist) (nth 1 plist))))
+ (setq plist (cddr plist)))
+ p))
+
+(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-keyword-index (keyword)
+ (loop named outer
+ with index = 0
+ for k in use-package-keywords do
+ (if (eq k keyword)
+ (return-from outer index))
+ (incf index)))
+
+(defun use-package-sort-keywords (plist)
+ (let (plist-grouped)
+ (while plist
+ (push (cons (car plist) (cadr plist))
+ plist-grouped)
+ (setq plist (cddr plist)))
+ (let (result)
+ (dolist (x
+ (nreverse
+ (sort plist-grouped
+ #'(lambda (l r) (< (use-package-keyword-index (car l))
+ (use-package-keyword-index (car r)))))))
+ (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 #'nconc (delete nil (delete (list nil) elems))))
+
+(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
+;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Normalization functions
+;;
+
+(defun use-package-normalize-plist (name-symbol input)
+ "Given a pseudo-plist, normalize it to a regular plist."
+ (unless (null input)
+ (let* ((keyword (car input))
+ (xs (use-package-split-list #'keywordp (cdr input)))
+ (args (car xs))
+ (tail (cdr xs))
+ (normalizer (intern (concat "use-package-normalize/"
+ (symbol-name keyword))))
+ (arg
+ (cond
+ ((eq keyword :disabled)
+ (use-package-normalize-plist name-symbol tail))
+ ((functionp normalizer)
+ (funcall normalizer name-symbol keyword args))
+ ((= (length args) 1)
+ (car args))
+ (t
+ args))))
+ (if (memq keyword use-package-keywords)
+ (cons keyword
+ (cons arg (use-package-normalize-plist name-symbol tail)))
+ (use-package-error (format "Unrecognized keyword: %s" keyword))))))
+
+(defun use-package-process-keywords (name-symbol plist &optional state)
+ "Process the next keyword in the free-form property list PLIST.
+The values in the PLIST have each been normalized by the function
+use-package-normalize/KEYWORD (minus the colon).
+
+STATE is a property list that the function may modify and/or
+query. This is useful if a package defines multiple keywords and
+wishes them to have some kind of stateful interaction.
+
+Unless the KEYWORD being processed intends to ignore remaining
+keywords, it must call this function recursively, passing in the
+plist with its keyword and argument removed, and passing in the
+next value for the STATE."
+ (unless (null plist)
+ (let* ((keyword (car plist))
+ (arg (cadr plist))
+ (rest (cddr plist)))
+ (unless (keywordp keyword)
+ (use-package-error (format "%s is not a keyword" keyword)))
+ (let* ((handler (concat "use-package-handler/" (symbol-name keyword)))
+ (handler-sym (intern handler)))
+ (if (functionp handler-sym)
+ (funcall handler-sym name-symbol keyword arg rest state)
+ (use-package-error
+ (format "Keyword handler not defined: %s" handler)))))))
+
+(put 'use-package-process-keywords 'lisp-indent-function 'defun)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :pin
+;;
+
+(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")))))
+
+(put 'use-package-only-one 'lisp-indent-function 'defun)
+
+(defun use-package-normalize/:pin (name-symbol keyword args)
+ (use-package-only-one (symbol-name keyword) args
+ (lambda (label arg)
+ (cond
+ ((stringp arg) arg)
+ ((symbolp arg) (symbol-name arg))
+ (t
+ (use-package-error
+ ":pin wants an archive name (a string)"))))))
+
+(eval-when-compile
+ (defvar package-pinned-packages)
+ (defvar package-archives))
+
+(defun use-package--archive-exists-p (archive)
+ "Check if a given ARCHIVE is enabled.
+
+ARCHIVE can be a string or a symbol or 'manual to indicate a
+manually updated package."
+ (if (member archive '(manual "manual"))
+ 't
+ (let ((valid nil))
+ (dolist (pa package-archives)
+ (when (member archive (list (car pa) (intern (car pa))))
+ (setq valid 't)))
+ valid)))
+
+(defun use-package-pin-package (package archive)
+ "Pin PACKAGE to ARCHIVE."
+ (unless (boundp 'package-pinned-packages)
+ (setq package-pinned-packages ()))
+ (let ((archive-symbol (if (symbolp archive) archive (intern archive)))
+ (archive-name (if (stringp archive) archive (symbol-name archive))))
+ (if (use-package--archive-exists-p archive-symbol)
+ (push (cons package archive-name) package-pinned-packages)
+ (error "Archive '%s' requested for package '%s' is not available."
+ archive-name package))
+ (package-initialize t)))
+
+(defun use-package-handler/:pin (name-symbol keyword archive-name rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ ;; This happens at macro expansion time, not when the expanded code is
+ ;; compiled or evaluated.
+ (if (null archive-name)
+ body
+ (use-package-pin-package name-symbol archive-name)
+ (use-package-concat
+ body
+ `((push '(,name-symbol . ,archive-name)
+ package-pinned-packages)
+ t)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :ensure
+;;
+
+(defun use-package-normalize/:ensure (name-symbol keyword args)
+ (if (null args)
+ t
+ (use-package-only-one (symbol-name keyword) args
+ (lambda (label arg)
+ (if (symbolp arg)
+ arg
+ (use-package-error
+ (concat ":ensure wants an optional package name "
+ "(an unquoted symbol name)")))))))
(defun use-package-ensure-elpa (package)
(when (not (package-installed-p package))
(package-install package)))
-(defvar use-package-keywords
- '(
- :bind
- :commands
- :config
- :defer
- :defines
- :demand
- :diminish
- :disabled
- :ensure
- :idle
- :idle-priority
- :if
- :init
- :interpreter
- :load-path
- :mode
- :pre-init
- :pre-load
- :requires
- )
- "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)
- "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'."
- (let ((values (use-package-mplist-get plist prop)))
- (when values
- (cond ((not (listp values))
- values)
- ((eq 1 (length values))
- (car values))
- (t (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
- (function
- (lambda (keyword)
- (unless (memq keyword use-package-keywords)
- (error "Unrecognized keyword: %s" keyword))))
- (use-package-mplist-keys args)))
-
-(defun use-package-plist-get-value (plist prop)
- "Return the value of PROP in PLIST as if it was backquoted."
- (eval (list '\` (use-package-plist-get plist prop))))
+(defun use-package-handler/:ensure (name-symbol keyword ensure rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ ;; This happens at macro expansion time, not when the expanded code is
+ ;; compiled or evaluated.
+ (let ((package-name (or (and (eq ensure t) name-symbol) ensure)))
+ (when package-name
+ (require 'package)
+ (use-package-ensure-elpa package-name)))
+ body))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :if, :when and :unless
+;;
+
+(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-test (name-symbol 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)
+
+(defun use-package-normalize/:unless (name-symbol keyword args)
+ (not (use-package-only-one (symbol-name keyword) args
+ #'use-package-normalize-value)))
+
+(defun use-package-handler/:if (name-symbol keyword pred rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ `((when ,pred ,@body))))
+
+(defalias 'use-package-handler/:when 'use-package-handler/:if)
+
+(defun use-package-handler/:unless (name-symbol keyword pred rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ `((unless ,pred ,@body))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :requires
+;;
+
+(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"))))
+
+(put 'use-package-as-one 'lisp-indent-function 'defun)
+
+(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-symlist (name-symbol keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ #'use-package-normalize-symbols))
+
+(defalias 'use-package-normalize/:requires 'use-package-normalize-symlist)
+
+(defun use-package-handler/:requires (name-symbol keyword requires rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (if (null requires)
+ body
+ `((when ,(if (listp requires)
+ `(not (member nil (mapcar #'featurep ',requires)))
+ `(featurep ',requires))
+ ,@body)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :load-path
+;;
+
+(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))))
+ (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/:load-path (name-symbol keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ #'use-package-normalize-paths))
+
+(defun use-package-handler/:load-path (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (use-package-concat
+ (mapcar #'(lambda (path)
+ `(eval-and-compile (push ,path load-path))) arg)
+ body)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :no-require
+;;
+
+(defun use-package-normalize-predicate (name-symbol keyword args)
+ (if (null args)
+ t
+ (use-package-only-one (symbol-name keyword) args
+ #'use-package-normalize-value)))
+
+(defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate)
+
+(defun use-package-handler/:no-require (name-symbol keyword arg rest state)
+ ;; This keyword has no functional meaning.
+ (use-package-process-keywords name-symbol 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-symbol keyword args)
+ (use-package-normalize-form (symbol-name keyword) args))
+
+(defalias 'use-package-normalize/:preface 'use-package-normalize-forms)
+
+(defun use-package-handler/:preface (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (use-package-concat
+ (unless (null arg)
+ `((eval-and-compile ,@arg)))
+ body)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :bind, :bind*
+;;
+
+(defsubst use-package-is-sympair (x &optional allow-vector)
+ "Return t if X has the type (STRING . SYMBOL)."
+ (and (consp x)
+ (or (stringp (car x))
+ (and allow-vector (vectorp (car x))))
+ (symbolp (cdr x))))
+
+(defun use-package-normalize-pairs
+ (name-symbol label arg &optional recursed allow-vector)
+ "Normalize a list of string/symbol pairs."
+ (cond
+ ((or (stringp arg) (and allow-vector (vectorp arg)))
+ (list (cons arg name-symbol)))
+ ((use-package-is-sympair arg allow-vector)
+ (list arg))
+ ((and (not recursed) (listp arg) (listp (cdr arg)))
+ (mapcar #'(lambda (x) (car (use-package-normalize-pairs
+ name-symbol label x t allow-vector))) arg))
+ (t
+ (use-package-error
+ (concat label " wants a string, (string . symbol) or list of these")))))
+
+(defun use-package-normalize-binder (name-symbol keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ (lambda (label arg)
+ (use-package-normalize-pairs name-symbol label arg nil t))))
+
+(defalias 'use-package-normalize/:bind 'use-package-normalize-binder)
+(defalias 'use-package-normalize/:bind* 'use-package-normalize-binder)
+
+(defun use-package-handler/:bind
+ (name-symbol keyword arg rest state &optional override)
+ (let ((commands (mapcar #'cdr arg)))
+ (use-package-concat
+ (use-package-process-keywords name-symbol
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands commands))
+ `((ignore (,(if override 'bind-keys* 'bind-keys) ,@arg))))))
+
+(defun use-package-handler/:bind* (name-symbol keyword arg rest state)
+ (use-package-handler/:bind name-symbol keyword arg rest state t))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :bind-keymap, :bind-keymap*
+;;
+
+(defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder)
+(defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder)
+
+(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 "Could not load package.el: %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))))
+ (use-package-error
+ (format "use-package: package.el %s failed to define keymap %s"
+ package keymap-symbol)))))
+
+(defun use-package-handler/:bind-keymap
+ (name-symbol keyword arg rest state &optional override)
+ (let* (commands
+ (form (mapcar
+ #'(lambda (binding)
+ (push (cdr binding) commands)
+ `(,(if override
+ 'bind-key*
+ 'bind-key)
+ ,(car binding)
+ #'(lambda ()
+ (interactive)
+ (use-package-autoload-keymap
+ ',(cdr binding) ',name-symbol nil)))) arg)))
+ (use-package-concat
+ (use-package-process-keywords name-symbol
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands commands))
+ `((ignore ,@form)))))
+
+(defun use-package-handler/:bind-keymap* (name-symbol keyword arg rest state)
+ (use-package-handler/:bind-keymap name-symbol keyword arg rest state t))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :interpreter
+;;
+
+(defun use-package-normalize-mode (name-symbol keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ (apply-partially #'use-package-normalize-pairs name-symbol)))
+
+(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode)
+
+(defun use-package-handler/:interpreter (name-symbol keyword arg rest state)
+ (let* (commands
+ (form (mapcar #'(lambda (interpreter)
+ (push (cdr interpreter) commands)
+ `(push ',interpreter interpreter-mode-alist)) arg)))
+ (use-package-concat
+ (use-package-process-keywords name-symbol
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands commands))
+ `((ignore ,@form)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :mode
+;;
+
+(defalias 'use-package-normalize/:mode 'use-package-normalize-mode)
+
+(defun use-package-handler/:mode (name-symbol keyword arg rest state)
+ (let* (commands
+ (form (mapcar #'(lambda (mode)
+ (push (cdr mode) commands)
+ `(push ',mode auto-mode-alist)) arg)))
+ (use-package-concat
+ (use-package-process-keywords name-symbol
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands commands))
+ `((ignore ,@form)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :commands
+;;
+
+(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
+
+(defun use-package-handler/:commands (name-symbol keyword arg rest state)
+ ;; The actual processing for commands is done in :defer
+ (use-package-process-keywords name-symbol
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands arg)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :defines
+;;
+
+(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist)
+
+(defun use-package-handler/:defines (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ body))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :functions
+;;
+
+(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist)
+
+(defun use-package-handler/:functions (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (if (not (bound-and-true-p byte-compile-current-file))
+ body
+ (use-package-concat
+ (unless (null arg)
+ `((eval-when-compile
+ ,@(mapcar
+ #'(lambda (fn)
+ `(declare-function ,fn ,(symbol-name name-symbol))) arg))))
+ body))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :defer
+;;
+
+(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
+
+(defun use-package-handler/:defer (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest
+ (plist-put state :deferred t)))
+ (name-string (symbol-name name-symbol)))
+ (use-package-concat
+ ;; Load the package after a set amount of idle time, if the argument to
+ ;; `:defer' was a number.
+ (when (numberp arg)
+ `((run-with-idle-timer ,arg nil #'require ',name-symbol nil t)))
+
+ ;; Since we deferring load, establish any necessary autoloads, and also
+ ;; keep the byte-compiler happy.
+ (apply
+ #'nconc
+ (mapcar #'(lambda (command)
+ (append
+ `((unless (fboundp ',command)
+ (autoload #',command ,name-string nil t)))
+ (when (bound-and-true-p byte-compile-current-file)
+ `((eval-when-compile
+ (declare-function ,command ,name-string))))))
+ (delete-dups (plist-get state :commands))))
+
+ body)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :demand
+;;
+
+(defalias 'use-package-normalize/:demand 'use-package-normalize-predicate)
+
+(defun use-package-handler/:demand (name-symbol keyword arg rest state)
+ (use-package-process-keywords name-symbol rest
+ (use-package-plist-delete state :deferred)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :init
+;;
+
+(defalias 'use-package-normalize/:init 'use-package-normalize-forms)
+
+(defun use-package-handler/:init (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (use-package-concat
+ ;; The user's initializations
+ (use-package-hook-injector (symbol-name name-symbol) :init arg)
+ body)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :config
+;;
+
+(defalias 'use-package-normalize/:config 'use-package-normalize-forms)
+
+(defun use-package-handler/:config (name-symbol keyword arg rest state)
+ (let* ((body (use-package-process-keywords name-symbol rest state))
+ (config-body
+ (if (equal arg '(t))
+ body
+ (use-package--with-elapsed-timer
+ (format "Configuring package %s" name-symbol)
+ (use-package-concat
+ (use-package-hook-injector (symbol-name name-symbol)
+ :config arg)
+ body
+ (list t))))))
+ (if (plist-get state :deferred)
+ (unless (or (null config-body) (equal config-body '(t)))
+ `((eval-after-load ',name-symbol
+ ',(macroexp-progn config-body))))
+ (use-package--with-elapsed-timer
+ (format "Loading package %s" name-symbol)
+ (if use-package-expand-minimally
+ (use-package-concat
+ (list `(require ',name-symbol))
+ config-body)
+ `((if (not (require ',name-symbol nil t))
+ (ignore
+ (message (format "Could not load %s" ',name-symbol)))
+ ,@config-body)))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :diminish
+
+(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-normalize/:diminish (name-symbol keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ (apply-partially #'use-package-normalize-diminish name-symbol)))
+
+(defun use-package-handler/:diminish (name-symbol keyword arg rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (use-package-concat
+ (mapcar #'(lambda (var)
+ `(if (fboundp 'diminish)
+ ,(if (consp var)
+ `(diminish ',(car var) ,(cdr var))
+ `(diminish ',var))))
+ arg)
+ body)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :delight
+;;
+
+(defun use-package-normalize/:delight (name-symbol keyword args)
+ "Normalize arguments to delight."
+ (cond
+ ((and (= (length args) 1)
+ (symbolp (car args)))
+ (list (car args) nil name-symbol))
+ ((and (= (length args) 2)
+ (symbolp (car args)))
+ (list (car args) (cadr args) name-symbol))
+ ((and (= (length args) 3)
+ (symbolp (car args)))
+ args)
+ (t
+ (use-package-error ":delight expects same args as delight function"))))
+
+(defun use-package-handler/:delight (name-symbol keyword args rest state)
+ (let ((body (use-package-process-keywords name-symbol rest state)))
+ (use-package-concat
+ body
+ `((delight (quote ,(nth 0 args)) ,(nth 1 args) (quote ,(nth 2 args))) t))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; The main macro
+;;
(defmacro use-package (name &rest args)
- "Use a package with configuration options.
+ "Declare an Emacs package by specifying a group of configuration options.
-For full documentation. please see commentary.
+For full documentation, please see the README file that came with
+this file. Usage:
(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.
-: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, :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."
- (use-package-validate-keywords args) ; error if any bad keyword, ignore result
- (let* ((commands (use-package-plist-get args :commands))
- (pre-init-body (use-package-plist-get args :pre-init))
- (pre-load-body (use-package-plist-get args :pre-load))
- (init-body (use-package-plist-get args :init))
- (config-body (use-package-plist-get args :config))
- (diminish-var (use-package-plist-get-value args :diminish))
- (defines (use-package-plist-get-value args :defines))
- (idle-body (use-package-plist-get args :idle))
- (idle-priority (use-package-plist-get args :idle-priority))
- (keybindings-alist (use-package-plist-get-value args :bind))
- (mode (use-package-plist-get-value args :mode))
- (mode-alist
- (if (stringp mode) (cons mode name) mode))
- (interpreter (use-package-plist-get-value args :interpreter))
- (interpreter-alist
- (if (stringp interpreter) (cons interpreter name) interpreter))
- (predicate (use-package-plist-get args :if))
- (pkg-load-path (use-package-plist-get-value args :load-path))
- (defines-eval (if (null defines)
- nil
- (if (listp defines)
- (mapcar (lambda (var) `(defvar ,var)) defines)
- `((defvar ,defines)))))
- (requires (use-package-plist-get-value args :requires))
- (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)))
-
- ;; force this immediately -- one off cost
- (unless (use-package-plist-get args :disabled)
-
- (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)))
-
-
- (when idle-body
- (when (null idle-priority)
- (setq idle-priority 5))
- (setq init-body
- `(progn
- (require 'use-package)
- (use-package-init-on-idle (lambda () ,idle-body) ,idle-priority)
- ,init-body)))
-
-
- (let ((init-for-commands
- (lambda (func sym-or-list)
- (let ((cons-list (if (and (consp sym-or-list)
- (stringp (car sym-or-list)))
- (list sym-or-list)
- sym-or-list)))
- (if cons-list
- (setq init-body
- `(progn
- ,init-body
- ,@(mapcar #'(lambda (elem)
- (push (cdr elem) commands)
- (funcall func elem))
- cons-list))))))))
-
- (funcall init-for-commands
- #'(lambda (binding)
- `(bind-key ,(car binding)
- (quote ,(cdr binding))))
- keybindings-alist)
-
- (funcall init-for-commands
- #'(lambda (mode)
- `(add-to-list 'auto-mode-alist
- (quote ,mode)))
- mode-alist)
-
- (funcall init-for-commands
- #'(lambda (interpreter)
- `(add-to-list 'interpreter-mode-alist
- (quote ,interpreter)))
- interpreter-alist))
-
- `(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
- ,(if (stringp name)
- `(load ,name t)
- `(require ',name nil t))))
-
- ,(if (and (or commands (use-package-plist-get args :defer))
- (not (use-package-plist-get args :demand)))
- (let (form)
- (mapc #'(lambda (command)
- (push `(autoload (function ,command)
- ,name-string nil t) form))
- commands)
-
- `(when ,(or predicate t)
- ,pre-init-body
- ,@form
- ,init-body
- ,(unless (null config-body)
- `(eval-after-load ,(if (stringp name) name `',name)
- `(,(lambda ()
- (if ,requires-test
- (use-package-with-elapsed-timer
- ,(format "Configuring package %s" name-string)
- ,config-body))))))
- t))
- `(if (and ,(or predicate t)
- ,requires-test)
- (use-package-with-elapsed-timer
- ,(format "Loading package %s" name-string)
- (if (not ,(if (stringp name)
- `(load ,name t)
- `(require ',name nil t)))
- (message "Could not load package %s" ,name-string)
- ,pre-init-body
- ,init-body
- ,config-body
- t))))))))
+ [:keyword [option]]...)
-(put 'use-package 'lisp-indent-function 'defun)
+: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.
+:preface Code to be run before everything except `:disabled'; this can
+ be used to define functions for use in `:if', or that should be
+ seen by the byte-compiler.
-(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))))
+:mode Form to be added to `auto-mode-alist'.
+:interpreter Form to be added to `interpreter-mode-alist'.
-(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
+: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'.
+ This can be an integer, to force loading after N seconds of
+ idle time, if the package has not already been loaded.
+: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 if this keyword is present.
+: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).
+: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-symbol (if (stringp name) (intern name) name))
+ (args0 (use-package-plist-maybe-put
+ (use-package-normalize-plist name-symbol args)
+ :config '(t)))
+ (args* (use-package-sort-keywords
+ (if use-package-always-ensure
+ (use-package-plist-maybe-put
+ args0 :ensure use-package-always-ensure)
+ args0))))
+
+ ;; When byte-compiling, pre-load the package so all its symbols are in
+ ;; scope.
+ (if (bound-and-true-p byte-compile-current-file)
+ (setq args*
+ (use-package-plist-cons
+ args* :preface
+ `(eval-when-compile
+ ,@(mapcar #'(lambda (var) `(defvar ,var))
+ (plist-get args* :defines))
+ (with-demoted-errors
+ ,(format "Cannot load %s: %%S" name-symbol)
+ ,(if use-package-verbose
+ `(message "Compiling package %s" ',name-symbol))
+ ,(unless (plist-get args* :no-require)
+ `(require ',name-symbol)))))))
+
+ (let ((body
+ (macroexp-progn
+ (use-package-process-keywords name-symbol args*))))
+ (if use-package-debug
+ (display-buffer
+ (save-current-buffer
+ (let ((buf (get-buffer-create "*use-package*")))
+ (with-current-buffer buf
+ (delete-region (point-min) (point-max))
+ (emacs-lisp-mode)
+ (insert (pp-to-string body)))
+ buf))))
+ body))))
+
+
+(put 'use-package 'lisp-indent-function 'defun)
(provide 'use-package)
+
;; Local Variables:
;; indent-tabs-mode: nil
;; End:
+
;;; use-package.el ends here