Commit 7ca62fb8f974
Changed files (2)
.emacs.d
lisp
use-package
.emacs.d/lisp/use-package/bind-key.el
@@ -35,22 +35,22 @@
;;
;; (require 'bind-key)
;;
-;; (bind-key "c-c x" 'my-ctrl-c-x-command)
+;; (bind-key "C-c x" 'my-ctrl-c-x-command)
;;
;; If you want the keybinding to override all minor modes that may also bind
;; the same key, use the `bind-key*' form:
;;
-;; (bind-key* "<c-return>" 'other-window)
+;; (bind-key* "<C-return>" 'other-window)
;;
;; If you want to rebind a key only in a particular keymap, use:
;;
-;; (bind-key "c-c x" 'my-ctrl-c-x-command some-other-mode-map)
+;; (bind-key "C-c x" 'my-ctrl-c-x-command some-other-mode-map)
;;
;; To unbind a key within a keymap (for example, to stop your favorite major
;; mode from changing a binding that you don't want to override everywhere),
;; use `unbind-key':
;;
-;; (unbind-key "c-c x" some-other-mode-map)
+;; (unbind-key "C-c x" some-other-mode-map)
;;
;; To bind multiple keys at once, or set up a prefix map, a `bind-keys' macro
;; is provided. It accepts keyword arguments, please see its documentation
@@ -135,13 +135,19 @@
Elements have the form ((KEY . [MAP]) CMD ORIGINAL-CMD)")
;;;###autoload
-(defmacro bind-key (key-name command &optional keymap)
+(defmacro bind-key (key-name command &optional keymap predicate)
"Bind KEY-NAME to COMMAND in KEYMAP (`global-map' if not passed).
KEY-NAME may be a vector, in which case it is passed straight to
`define-key'. Or it may be a string to be interpreted as
spelled-out keystrokes, e.g., \"C-c C-z\". See documentation of
-`edmacro-mode' for details."
+`edmacro-mode' for details.
+
+If PREDICATE is non-nil, it is a form evaluated to determine when
+a key should be bound. It must return non-nil in such cases.
+Emacs can evaluate this form at any time that it does redisplay
+or operates on menu data structures, so you should write it so it
+can safely be called at any time."
(let ((namevar (make-symbol "name"))
(keyvar (make-symbol "key"))
(kdescvar (make-symbol "kdesc"))
@@ -152,15 +158,21 @@ spelled-out keystrokes, e.g., \"C-c C-z\". See documentation of
(,kdescvar (cons (if (stringp ,namevar) ,namevar
(key-description ,namevar))
(quote ,keymap)))
- (,bindingvar (lookup-key (or ,keymap global-map)
- ,keyvar)))
+ (,bindingvar (lookup-key (or ,keymap global-map) ,keyvar)))
(add-to-list 'personal-keybindings
(list ,kdescvar ,command
(unless (numberp ,bindingvar) ,bindingvar)))
- (define-key (or ,keymap global-map) ,keyvar ,command))))
+ ,(if predicate
+ `(define-key (or ,keymap global-map) ,keyvar
+ '(menu-item "" nil :filter (lambda (&optional _)
+ (when ,predicate
+ ,command))))
+ `(define-key (or ,keymap global-map) ,keyvar ,command)))))
;;;###autoload
(defmacro unbind-key (key-name &optional keymap)
+ "Unbind the given KEY-NAME, within the KEYMAP (if specified).
+See `bind-key' for more details."
`(progn
(bind-key ,key-name nil ,keymap)
(setq personal-keybindings
@@ -174,29 +186,37 @@ spelled-out keystrokes, e.g., \"C-c C-z\". See documentation of
personal-keybindings))))
;;;###autoload
-(defmacro bind-key* (key-name command)
- `(bind-key ,key-name ,command override-global-map))
+(defmacro bind-key* (key-name command &optional predicate)
+ "Similar to `bind-key', but overrides any mode-specific bindings."
+ `(bind-key ,key-name ,command override-global-map ,predicate))
-;;;###autoload
-(defmacro bind-keys (&rest args)
+(defun bind-keys-form (args)
"Bind multiple keys at once.
Accepts keyword arguments:
-:map - a keymap into which the keybindings should be added
-:prefix-map - name of the prefix map that should be created for
- these bindings
-:prefix - prefix key for these bindings
-:prefix-docstring - docstring for the prefix-map variable
-:menu-name - optional menu string for prefix map
+:map MAP - a keymap into which the keybindings should be
+ added
+:prefix KEY - prefix key for these bindings
+:prefix-map MAP - name of the prefix map that should be created
+ for these bindings
+:prefix-docstring STR - docstring for the prefix-map variable
+:menu-name NAME - optional menu string for prefix map
+:filter FORM - optional form to determine when bindings apply
The rest of the arguments are conses of keybinding string and a
function symbol (unquoted)."
+ ;; jww (2016-02-26): This is a hack; this whole function needs to be
+ ;; rewritten to normalize arguments the way that use-package.el does.
+ (if (and (eq (car args) :package)
+ (not (eq (car (cdr (cdr args))) :map)))
+ (setq args (cons :map (cons 'global-map args))))
(let* ((map (plist-get args :map))
- (maps (if (listp map) map (list map)))
(doc (plist-get args :prefix-docstring))
(prefix-map (plist-get args :prefix-map))
(prefix (plist-get args :prefix))
+ (filter (plist-get args :filter))
(menu-name (plist-get args :menu-name))
+ (pkg (plist-get args :package))
(key-bindings (progn
(while (keywordp (car args))
(pop args)
@@ -207,34 +227,73 @@ function symbol (unquoted)."
(error "Both :prefix-map and :prefix must be supplied"))
(when (and menu-name (not prefix))
(error "If :menu-name is supplied, :prefix must be too"))
- (macroexp-progn
- (append
- (when prefix-map
- `((defvar ,prefix-map)
- ,@(when doc `((put ',prefix-map 'variable-documentation ,doc)))
- ,@(if menu-name
- `((define-prefix-command ',prefix-map nil ,menu-name))
- `((define-prefix-command ',prefix-map)))
- ,@(if maps
- (mapcar
- #'(lambda (m)
- `(bind-key ,prefix ',prefix-map ,m)) maps)
- `((bind-key ,prefix ',prefix-map)))))
- (apply
- #'nconc
- (mapcar (lambda (form)
- (if prefix-map
- `((bind-key ,(car form) ',(cdr form) ,prefix-map))
- (if maps
- (mapcar
- #'(lambda (m)
- `(bind-key ,(car form) ',(cdr form) ,m)) maps)
- `((bind-key ,(car form) ',(cdr form))))))
- key-bindings))))))
+ (let ((args key-bindings)
+ saw-map first next)
+ (while args
+ (if (keywordp (car args))
+ (progn
+ (setq next args)
+ (setq args nil))
+ (if first
+ (nconc first (list (car args)))
+ (setq first (list (car args))))
+ (setq args (cdr args))))
+ (cl-flet
+ ((wrap (map bindings)
+ (if (and map pkg (not (eq map 'global-map)))
+ (if (boundp map)
+ bindings
+ `((eval-after-load
+ ,(if (symbolp pkg) `',pkg pkg)
+ '(progn ,@bindings))))
+ bindings)))
+ (append
+ (when prefix-map
+ `((defvar ,prefix-map)
+ ,@(when doc `((put ',prefix-map 'variable-documentation ,doc)))
+ ,@(if menu-name
+ `((define-prefix-command ',prefix-map nil ,menu-name))
+ `((define-prefix-command ',prefix-map)))
+ ,@(if (and map (not (eq map 'global-map)))
+ (wrap map `((bind-key ,prefix ',prefix-map ,map ,filter)))
+ `((bind-key ,prefix ',prefix-map nil ,filter)))))
+ (wrap map
+ (cl-mapcan
+ (lambda (form)
+ (if prefix-map
+ `((bind-key ,(car form) ',(cdr form) ,prefix-map ,filter))
+ (if (and map (not (eq map 'global-map)))
+ `((bind-key ,(car form) ',(cdr form) ,map ,filter))
+ `((bind-key ,(car form) ',(cdr form) nil ,filter)))))
+ first))
+ (when next
+ (bind-keys-form
+ (if pkg
+ (cons :package (cons pkg next))
+ next))))))))
+
+;;;###autoload
+(defmacro bind-keys (&rest args)
+ "Bind multiple keys at once.
+
+Accepts keyword arguments:
+:map MAP - a keymap into which the keybindings should be
+ added
+:prefix KEY - prefix key for these bindings
+:prefix-map MAP - name of the prefix map that should be created
+ for these bindings
+:prefix-docstring STR - docstring for the prefix-map variable
+:menu-name NAME - optional menu string for prefix map
+:filter FORM - optional form to determine when bindings apply
+
+The rest of the arguments are conses of keybinding string and a
+function symbol (unquoted)."
+ (macroexp-progn (bind-keys-form args)))
;;;###autoload
(defmacro bind-keys* (&rest args)
- `(bind-keys :map override-global-map ,@args))
+ (macroexp-progn
+ (bind-keys-form `(:map override-global-map ,@args))))
(defun get-binding-description (elem)
(cond
@@ -256,7 +315,8 @@ function symbol (unquoted)."
elem)))
;; must be a symbol, non-symbol keymap case covered above
((and bind-key-describe-special-forms (keymapp elem))
- (get elem 'variable-documentation))
+ (let ((doc (get elem 'variable-documentation)))
+ (if (stringp doc) doc elem)))
((symbolp elem)
elem)
(t
.emacs.d/lisp/use-package/use-package.el
@@ -5,7 +5,8 @@
;; Author: John Wiegley <jwiegley@gmail.com>
;; Maintainer: John Wiegley <jwiegley@gmail.com>
;; Created: 17 Jun 2012
-;; Version: 2.0
+;; Modified: 26 Sep 2015
+;; Version: 2.1
;; Package-Requires: ((bind-key "1.0") (diminish "0.44"))
;; Keywords: dotemacs startup speed config package
;; URL: https://github.com/jwiegley/use-package
@@ -57,7 +58,8 @@ 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
+ :type '(choice (const :tag "Quiet" nil) (const :tag "Verbose" t)
+ (const :tag "Debug" debug))
:group 'use-package)
(defcustom use-package-debug nil
@@ -65,11 +67,27 @@ then the expanded macros do their job silently."
:type 'boolean
:group 'use-package)
+(defcustom use-package-check-before-init nil
+ "If non-nil, check that package exists before executing its `:init' block.
+The check is performed by looking for the module using `locate-library'."
+ :type 'boolean
+ :group 'use-package)
+
+(defcustom use-package-always-defer nil
+ "If non-nil, assume `:defer t` unless `:demand t` is given."
+ :type 'boolean
+ :group 'use-package)
+
(defcustom use-package-always-ensure nil
"Treat every package as though it had specified `:ensure SEXP`."
:type 'sexp
:group 'use-package)
+(defcustom use-package-always-pin nil
+ "Treat every package as though it had specified `:pin SYM."
+ :type 'symbol
+ :group 'use-package)
+
(defcustom use-package-minimum-reported-time 0.1
"Minimal load time that will be reported.
@@ -125,6 +143,7 @@ the user specified."
:defines
:functions
:defer
+ :after
:demand
:init
:config
@@ -153,6 +172,25 @@ then your byte-compiled init file is as minimal as possible."
;; Utility functions
;;
+(defun use-package-as-symbol (string-or-symbol)
+ "If STRING-OR-SYMBOL is already a symbol, return it. Otherwise
+convert it to a symbol and return that."
+ (if (symbolp string-or-symbol) string-or-symbol
+ (intern string-or-symbol)))
+
+(defun use-package-as-string (string-or-symbol)
+ "If STRING-OR-SYMBOL is already a string, return it. Otherwise
+convert it to a string and return that."
+ (if (stringp string-or-symbol) string-or-symbol
+ (symbol-name string-or-symbol)))
+
+(defun use-package-load-name (name &optional noerror)
+ "Return a form which will load or require NAME depending on
+whether it's a string or symbol."
+ (if (stringp name)
+ `(load ,name 'noerror)
+ `(require ',name nil 'noerror)))
+
(defun use-package-expand (name label form)
"FORM is a list of forms, so `((foo))' if only `foo' is being called."
(declare (indent 1))
@@ -181,16 +219,16 @@ ARGS is a list of forms, so `((foo))' if only `foo' is being called."
(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")))))
+ `((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")))))))))))
+ `((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."
@@ -296,7 +334,7 @@ This is in contrast to merely setting it to 0."
;; Normalization functions
;;
-(defun use-package-normalize-plist (name-symbol input)
+(defun use-package-normalize-plist (name input)
"Given a pseudo-plist, normalize it to a regular plist."
(unless (null input)
(let* ((keyword (car input))
@@ -308,19 +346,19 @@ This is in contrast to merely setting it to 0."
(arg
(cond
((eq keyword :disabled)
- (use-package-normalize-plist name-symbol tail))
+ (use-package-normalize-plist name tail))
((functionp normalizer)
- (funcall normalizer name-symbol keyword args))
+ (funcall normalizer name 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)))
+ (cons arg (use-package-normalize-plist name tail)))
(use-package-error (format "Unrecognized keyword: %s" keyword))))))
-(defun use-package-process-keywords (name-symbol plist &optional state)
+(defun use-package-process-keywords (name 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).
@@ -333,6 +371,7 @@ 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."
+ (declare (indent 1))
(unless (null plist)
(let* ((keyword (car plist))
(arg (cadr plist))
@@ -342,7 +381,7 @@ next value for the STATE."
(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)
+ (funcall handler-sym name keyword arg rest state)
(use-package-error
(format "Keyword handler not defined: %s" handler)))))))
@@ -366,7 +405,7 @@ next value for the STATE."
(put 'use-package-only-one 'lisp-indent-function 'defun)
-(defun use-package-normalize/:pin (name-symbol keyword args)
+(defun use-package-normalize/:pin (name keyword args)
(use-package-only-one (symbol-name keyword) args
(lambda (label arg)
(cond
@@ -400,30 +439,30 @@ manually updated package."
(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)
+ (add-to-list 'package-pinned-packages (cons package archive-name))
(error "Archive '%s' requested for package '%s' is not available."
archive-name package))
- (package-initialize t)))
+ (unless (bound-and-true-p package--initialized)
+ (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)))))
+(defun use-package-handler/:pin (name keyword archive-name rest state)
+ (let ((body (use-package-process-keywords name rest state))
+ (pin-form (if archive-name
+ `(use-package-pin-package ',(use-package-as-symbol name)
+ ,archive-name))))
+ ;; Pinning should occur just before ensuring
+ ;; See `use-package-handler/:ensure'.
+ (if (bound-and-true-p byte-compile-current-file)
+ (eval pin-form) ; Eval when byte-compiling,
+ (push pin-form body)) ; or else wait until runtime.
+ body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; :ensure
;;
-
-(defun use-package-normalize/:ensure (name-symbol keyword args)
+(defvar package-archive-contents)
+(defun use-package-normalize/:ensure (name keyword args)
(if (null args)
t
(use-package-only-one (symbol-name keyword) args
@@ -434,18 +473,30 @@ manually updated package."
(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)))
+(defun use-package-ensure-elpa (package &optional no-refresh)
+ (if (package-installed-p package)
+ t
+ (if (or (assoc package package-archive-contents) no-refresh)
+ (if (boundp 'package-selected-packages)
+ (package-install package t)
+ (package-install package))
+ (progn
+ (package-refresh-contents)
+ (use-package-ensure-elpa package t)))))
-(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)))
+(defun use-package-handler/:ensure (name keyword ensure rest state)
+ (let* ((body (use-package-process-keywords name rest state))
+ (package-name (or (and (eq ensure t) (use-package-as-symbol name)) ensure))
+ (ensure-form (if package-name
+ `(progn (require 'package)
+ (use-package-ensure-elpa ',package-name)))))
+ ;; We want to avoid installing packages when the `use-package'
+ ;; macro is being macro-expanded by elisp completion (see
+ ;; `lisp--local-variables'), but still do install packages when
+ ;; byte-compiling to avoid requiring `package' at runtime.
+ (if (bound-and-true-p byte-compile-current-file)
+ (eval ensure-form) ; Eval when byte-compiling,
+ (push ensure-form body)) ; or else wait until runtime.
body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -461,25 +512,22 @@ manually updated package."
`(funcall #',arg))
(t arg)))
-(defun use-package-normalize-test (name-symbol keyword args)
+(defun use-package-normalize-test (name keyword args)
(use-package-only-one (symbol-name keyword) args
#'use-package-normalize-value))
(defalias 'use-package-normalize/:if 'use-package-normalize-test)
(defalias 'use-package-normalize/:when 'use-package-normalize-test)
+(defalias 'use-package-normalize/:unless 'use-package-normalize-test)
-(defun use-package-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)))
+(defun use-package-handler/:if (name keyword pred rest state)
+ (let ((body (use-package-process-keywords name rest state)))
`((when ,pred ,@body))))
(defalias 'use-package-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)))
+(defun use-package-handler/:unless (name keyword pred rest state)
+ (let ((body (use-package-process-keywords name rest state)))
`((unless ,pred ,@body))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -510,14 +558,14 @@ manually updated package."
(use-package-error
(concat label " wants a symbol, or list of symbols")))))
-(defun use-package-normalize-symlist (name-symbol keyword args)
+(defun use-package-normalize-symlist (name 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)))
+(defun use-package-handler/:requires (name keyword requires rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(if (null requires)
body
`((when ,(if (listp requires)
@@ -533,7 +581,7 @@ manually updated package."
(defun use-package-normalize-paths (label arg &optional recursed)
"Normalize a list of filesystem paths."
(cond
- ((or (symbolp arg) (functionp arg))
+ ((and arg (or (symbolp arg) (functionp arg)))
(let ((value (use-package-normalize-value label arg)))
(use-package-normalize-paths label (eval value))))
((stringp arg)
@@ -548,15 +596,15 @@ manually updated package."
(use-package-error
(concat label " wants a directory path, or list of paths")))))
-(defun use-package-normalize/:load-path (name-symbol keyword args)
+(defun use-package-normalize/:load-path (name 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)))
+(defun use-package-handler/:load-path (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(use-package-concat
(mapcar #'(lambda (path)
- `(eval-and-compile (push ,path load-path))) arg)
+ `(eval-and-compile (add-to-list 'load-path ,path))) arg)
body)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -564,7 +612,7 @@ manually updated package."
;; :no-require
;;
-(defun use-package-normalize-predicate (name-symbol keyword args)
+(defun use-package-normalize-predicate (name keyword args)
(if (null args)
t
(use-package-only-one (symbol-name keyword) args
@@ -572,9 +620,9 @@ manually updated package."
(defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate)
-(defun use-package-handler/:no-require (name-symbol keyword arg rest state)
+(defun use-package-handler/:no-require (name keyword arg rest state)
;; This keyword has no functional meaning.
- (use-package-process-keywords name-symbol rest state))
+ (use-package-process-keywords name rest state))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -591,13 +639,13 @@ manually updated package."
(macroexpand form)
form)) args))
-(defun use-package-normalize-forms (name-symbol keyword args)
+(defun use-package-normalize-forms (name 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)))
+(defun use-package-handler/:preface (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(use-package-concat
(unless (null arg)
`((eval-and-compile ,@arg)))
@@ -615,41 +663,62 @@ manually updated package."
(and allow-vector (vectorp (car x))))
(symbolp (cdr x))))
+(defsubst use-package-is-string-pair (x)
+ "Return t if X has the type (STRING . STRING)."
+ (and (consp x)
+ (stringp (car x))
+ (stringp (cdr x))))
+
(defun use-package-normalize-pairs
- (name-symbol label arg &optional recursed allow-vector)
- "Normalize a list of string/symbol pairs."
+ (name label arg &optional recursed allow-vector allow-string-cdrs)
+ "Normalize a list of string/symbol pairs.
+If RECURSED is non-nil, recurse into sublists.
+If ALLOW-VECTOR is non-nil, then the key to bind may specify a
+vector of keys, as accepted by `define-key'.
+If ALLOW-STRING-CDRS is non-nil, then the command name to bind to
+may also be a string, as accepted by `define-key'."
(cond
((or (stringp arg) (and allow-vector (vectorp arg)))
- (list (cons arg name-symbol)))
+ (list (cons arg (use-package-as-symbol name))))
((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")))))
+ (mapcar #'(lambda (x)
+ (let ((ret (use-package-normalize-pairs
+ name label x t allow-vector allow-string-cdrs)))
+ (if (listp ret)
+ (car ret)
+ ret))) arg))
+ ((and allow-string-cdrs (use-package-is-string-pair arg))
+ (list arg))
+ (t arg)))
-(defun use-package-normalize-binder (name-symbol keyword args)
+(defun use-package-normalize-binder (name keyword args)
(use-package-as-one (symbol-name keyword) args
(lambda (label arg)
- (use-package-normalize-pairs name-symbol label arg nil t))))
+ (use-package-normalize-pairs name label arg nil t 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)))
+ (name keyword arg rest state &optional bind-macro)
+ (let ((commands (remq nil (mapcar #'(lambda (arg)
+ (if (listp arg)
+ (cdr arg)
+ nil)) arg))))
(use-package-concat
- (use-package-process-keywords name-symbol
+ (use-package-process-keywords name
(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))))))
+ `((ignore
+ ,(macroexpand
+ `(,(if bind-macro bind-macro 'bind-keys)
+ :package ,name ,@arg)))))))
-(defun use-package-handler/:bind* (name-symbol keyword arg rest state)
- (use-package-handler/:bind name-symbol keyword arg rest state t))
+(defun use-package-handler/:bind* (name keyword arg rest state)
+ (use-package-handler/:bind name keyword arg rest state 'bind-keys*))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -671,63 +740,61 @@ 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))
+ (use-package-error (format "Cannot 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)))
+ (let* ((kv (this-command-keys-vector))
+ (key (key-description kv))
+ (keymap (symbol-value keymap-symbol)))
(if override
- ;; eval form is necessary to avoid compiler error
- `(eval `(bind-key* ,key ,keymap))
+ (bind-key* key keymap)
(bind-key key keymap))
(setq unread-command-events
- (listify-key-sequence (this-command-keys-vector))))
+ (listify-key-sequence kv)))
(use-package-error
(format "use-package: package.el %s failed to define keymap %s"
package keymap-symbol)))))
(defun use-package-handler/:bind-keymap
- (name-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)))
+ (name keyword arg rest state &optional override)
+ (let ((form (mapcar
+ #'(lambda (binding)
+ `(,(if override
+ 'bind-key*
+ 'bind-key)
+ ,(car binding)
+ #'(lambda ()
+ (interactive)
+ (use-package-autoload-keymap
+ ',(cdr binding) ',(use-package-as-symbol name) ,override)))) arg)))
(use-package-concat
- (use-package-process-keywords name-symbol
+ (use-package-process-keywords name
(use-package-sort-keywords
(use-package-plist-maybe-put rest :defer t))
- (use-package-plist-append state :commands commands))
+ state)
`((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))
+(defun use-package-handler/:bind-keymap* (name keyword arg rest state)
+ (use-package-handler/:bind-keymap name keyword arg rest state t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; :interpreter
;;
-(defun use-package-normalize-mode (name-symbol keyword args)
+(defun use-package-normalize-mode (name keyword args)
(use-package-as-one (symbol-name keyword) args
- (apply-partially #'use-package-normalize-pairs name-symbol)))
+ (apply-partially #'use-package-normalize-pairs name)))
(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode)
-(defun use-package-handler/:interpreter (name-symbol keyword arg rest state)
+(defun use-package-handler/:interpreter (name keyword arg rest state)
(let* (commands
(form (mapcar #'(lambda (interpreter)
(push (cdr interpreter) commands)
- `(push ',interpreter interpreter-mode-alist)) arg)))
+ `(add-to-list 'interpreter-mode-alist ',interpreter)) arg)))
(use-package-concat
- (use-package-process-keywords name-symbol
+ (use-package-process-keywords name
(use-package-sort-keywords
(use-package-plist-maybe-put rest :defer t))
(use-package-plist-append state :commands commands))
@@ -740,13 +807,13 @@ deferred until the prefix key sequence is pressed."
(defalias 'use-package-normalize/:mode 'use-package-normalize-mode)
-(defun use-package-handler/:mode (name-symbol keyword arg rest state)
+(defun use-package-handler/:mode (name keyword arg rest state)
(let* (commands
(form (mapcar #'(lambda (mode)
(push (cdr mode) commands)
- `(push ',mode auto-mode-alist)) arg)))
+ `(add-to-list 'auto-mode-alist ',mode)) arg)))
(use-package-concat
- (use-package-process-keywords name-symbol
+ (use-package-process-keywords name
(use-package-sort-keywords
(use-package-plist-maybe-put rest :defer t))
(use-package-plist-append state :commands commands))
@@ -759,9 +826,9 @@ deferred until the prefix key sequence is pressed."
(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
-(defun use-package-handler/:commands (name-symbol keyword arg rest state)
+(defun use-package-handler/:commands (name keyword arg rest state)
;; The actual processing for commands is done in :defer
- (use-package-process-keywords name-symbol
+ (use-package-process-keywords name
(use-package-sort-keywords
(use-package-plist-maybe-put rest :defer t))
(use-package-plist-append state :commands arg)))
@@ -773,8 +840,8 @@ deferred until the prefix key sequence is pressed."
(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)))
+(defun use-package-handler/:defines (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -784,8 +851,8 @@ deferred until the prefix key sequence is pressed."
(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)))
+(defun use-package-handler/:functions (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(if (not (bound-and-true-p byte-compile-current-file))
body
(use-package-concat
@@ -793,7 +860,7 @@ deferred until the prefix key sequence is pressed."
`((eval-when-compile
,@(mapcar
#'(lambda (fn)
- `(declare-function ,fn ,(symbol-name name-symbol))) arg))))
+ `(declare-function ,fn ,(use-package-as-string name))) arg))))
body))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -803,31 +870,59 @@ deferred until the prefix key sequence is pressed."
(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
+(defun use-package-handler/:defer (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest
(plist-put state :deferred t)))
- (name-string (symbol-name name-symbol)))
+ (name-string (use-package-as-string name)))
(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)))
+ `((run-with-idle-timer ,arg nil #'require ',(use-package-as-symbol name) 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))))))
+ (when (not (stringp 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)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; :after
+;;
+
+(defalias 'use-package-normalize/:after 'use-package-normalize-symlist)
+
+(defun use-package-require-after-load (features name)
+ "Return form for after any of FEATURES require NAME."
+ `(progn
+ ,@(mapcar
+ (lambda (feat)
+ `(eval-after-load
+ (quote ,feat)
+ (quote (require (quote ,name)))))
+ features)))
+
+(defun use-package-handler/:after (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest
+ (plist-put state :deferred t)))
+ (name-string (use-package-as-string name)))
+ (use-package-concat
+ (when arg
+ (list (use-package-require-after-load arg name)))
+ body)))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; :demand
@@ -835,8 +930,8 @@ deferred until the prefix key sequence is pressed."
(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
+(defun use-package-handler/:demand (name keyword arg rest state)
+ (use-package-process-keywords name rest
(use-package-plist-delete state :deferred)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -846,11 +941,17 @@ deferred until the prefix key sequence is pressed."
(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)))
+(defun use-package-handler/:init (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(use-package-concat
;; The user's initializations
- (use-package-hook-injector (symbol-name name-symbol) :init arg)
+ (let ((init-body
+ (use-package-hook-injector (use-package-as-string name)
+ :init arg)))
+ (if use-package-check-before-init
+ `((if (locate-library ,(use-package-as-string name))
+ ,(macroexp-progn init-body)))
+ init-body))
body)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -860,8 +961,9 @@ deferred until the prefix key sequence is pressed."
(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))
+(defun use-package-handler/:config (name keyword arg rest state)
+ (let* ((body (use-package-process-keywords name rest state))
+ (name-symbol (use-package-as-symbol name))
(config-body
(if (equal arg '(t))
body
@@ -874,24 +976,24 @@ deferred until the prefix key sequence is pressed."
(list t))))))
(if (plist-get state :deferred)
(unless (or (null config-body) (equal config-body '(t)))
- `((eval-after-load ',name-symbol
+ `((eval-after-load ,(if (symbolp name) `',name name)
',(macroexp-progn config-body))))
(use-package--with-elapsed-timer
- (format "Loading package %s" name-symbol)
+ (format "Loading package %s" name)
(if use-package-expand-minimally
(use-package-concat
- (list `(require ',name-symbol))
+ (list (use-package-load-name name))
config-body)
- `((if (not (require ',name-symbol nil t))
+ `((if (not ,(use-package-load-name name t))
(ignore
- (message (format "Could not load %s" ',name-symbol)))
+ (message (format "Cannot load %s" ',name)))
,@config-body)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; :diminish
-(defun use-package-normalize-diminish (name-symbol label arg &optional recursed)
+(defun use-package-normalize-diminish (name label arg &optional recursed)
"Normalize the arguments to diminish down to a list of one of two forms:
SYMBOL
(SYMBOL . STRING)"
@@ -899,23 +1001,23 @@ deferred until the prefix key sequence is pressed."
((symbolp arg)
(list arg))
((stringp arg)
- (list (cons (intern (concat (symbol-name name-symbol) "-mode")) arg)))
+ (list (cons (intern (concat (use-package-as-string name) "-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))
+ name 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)
+(defun use-package-normalize/:diminish (name keyword args)
(use-package-as-one (symbol-name keyword) args
- (apply-partially #'use-package-normalize-diminish name-symbol)))
+ (apply-partially #'use-package-normalize-diminish name)))
-(defun use-package-handler/:diminish (name-symbol keyword arg rest state)
- (let ((body (use-package-process-keywords name-symbol rest state)))
+(defun use-package-handler/:diminish (name keyword arg rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(use-package-concat
(mapcar #'(lambda (var)
`(if (fboundp 'diminish)
@@ -930,23 +1032,23 @@ deferred until the prefix key sequence is pressed."
;; :delight
;;
-(defun use-package-normalize/:delight (name-symbol keyword args)
+(defun use-package-normalize/:delight (name keyword args)
"Normalize arguments to delight."
(cond
((and (= (length args) 1)
(symbolp (car args)))
- (list (car args) nil name-symbol))
+ (list (car args) nil name))
((and (= (length args) 2)
(symbolp (car args)))
- (list (car args) (cadr args) name-symbol))
+ (list (car args) (cadr args) (use-package-as-symbol name)))
((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)))
+(defun use-package-handler/:delight (name keyword args rest state)
+ (let ((body (use-package-process-keywords name rest state)))
(use-package-concat
body
`((delight (quote ,(nth 0 args)) ,(nth 1 args) (quote ,(nth 2 args))) t))))
@@ -956,6 +1058,7 @@ deferred until the prefix key sequence is pressed."
;; The main macro
;;
+;;;###autoload
(defmacro use-package (name &rest args)
"Declare an Emacs package by specifying a group of configuration options.
@@ -992,6 +1095,10 @@ this file. Usage:
`: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.
+
+:after Defer loading of a package until after any of the named
+ features are loaded.
+
:demand Prevent deferred loading in all cases.
:if EXPR Initialize and load only if EXPR evaluates to a non-nil value.
@@ -1006,13 +1113,18 @@ this file. Usage:
(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)
+ (use-package-normalize-plist name 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))))
+ args0)))
+ (args* (use-package-sort-keywords
+ (if use-package-always-pin
+ (use-package-plist-maybe-put
+ args* :pin use-package-always-pin)
+ args*))))
;; When byte-compiling, pre-load the package so all its symbols are in
;; scope.
@@ -1024,15 +1136,16 @@ this file. Usage:
,@(mapcar #'(lambda (var) `(defvar ,var))
(plist-get args* :defines))
(with-demoted-errors
- ,(format "Cannot load %s: %%S" name-symbol)
- ,(if use-package-verbose
+ ,(format "Cannot load %s: %%S" name)
+ ,(if (eq use-package-verbose 'debug)
`(message "Compiling package %s" ',name-symbol))
,(unless (plist-get args* :no-require)
- `(require ',name-symbol)))))))
+ (use-package-load-name name)))))))
(let ((body
(macroexp-progn
- (use-package-process-keywords name-symbol args*))))
+ (use-package-process-keywords name args*
+ (and use-package-always-defer '(:deferred t))))))
(if use-package-debug
(display-buffer
(save-current-buffer