Commit 1b961a9d170a
Changed files (4)
.emacs.d
lisp
use-package
.emacs.d/lisp/use-package/bind-key.el
@@ -91,6 +91,8 @@
;; what the default was. Also, it will tell you if the key was rebound after
;; your binding it with `bind-key', and what it was rebound it to.
+;;; Code:
+
(require 'cl-lib)
(require 'easy-mmode)
@@ -241,9 +243,9 @@ function symbol (unquoted)."
(cl-flet
((wrap (map bindings)
(if (and map pkg (not (eq map 'global-map)))
- (if (boundp map)
- bindings
- `((eval-after-load
+ `((if (boundp ',map)
+ (progn ,@bindings)
+ (eval-after-load
,(if (symbolp pkg) `',pkg pkg)
'(progn ,@bindings))))
bindings)))
@@ -407,6 +409,7 @@ function symbol (unquoted)."
(provide 'bind-key)
;; Local Variables:
+;; outline-regexp: ";;;\\(;* [^\s\t\n]\\|###autoload\\)\\|("
;; indent-tabs-mode: nil
;; End:
.emacs.d/lisp/use-package/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
.emacs.d/lisp/use-package/README.md
@@ -1,97 +1,15 @@
-# Note to users upgrading to 2.0
-
-## Semantics of :init is now consistent
-
-The meaning of `:init` has been changed: It now *always* happens before
-package load, whether `:config` has been deferred or not. This means that
-some uses of `:init` in your configuration may need to be changed to `:config`
-(in the non-deferred case). For the deferred case, the behavior is unchanged
-from before.
-
-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).
-
-## :idle has been removed
-
-I am removing this feature for now because it can result in a nasty
-inconsistency. Consider the following definition:
-
-``` elisp
-(use-package vkill
- :commands vkill
- :idle (some-important-configuration-here)
- :bind ("C-x L" . vkill-and-helm-occur)
- :init
- (defun vkill-and-helm-occur ()
- (interactive)
- (vkill)
- (call-interactively #'helm-occur))
-
- :config
- (setq vkill-show-all-processes t))
-```
-
-If I load my Emacs and wait until the idle timer fires, then this is the
-sequence of events:
-
- :init :idle <load> :config
-
-But if I load Emacs and immediately type C-x L without waiting for the idle
-timer to fire, this is the sequence of events:
-
- :init <load> :config :idle
-
-It's possible that the user could use `featurep` in their idle to test for
-this case, but that's a subtlety I'd rather avoid.
-
-## :defer now accepts an optional integer argument
-
-`:defer [N]` causes the package to be loaded -- if it has not already been --
-after `N` seconds of idle time.
-
-## Add :preface, occurring before everything except :disabled
-
-`:preface` can be used to establish function and variable definitions that
-will 1) make the byte-compiler happy (it won't complain about functions whose
-definitions are unknown because you have them within a guard block), and 2)
-allow you to define code that can be used in an `:if` test.
-
-Note that whatever is specified within `:preface` is evaluated both at load
-time and at byte-compilation time, in order to ensure that definitions are
-seen by both the Lisp evaluator and the byte-compiler, so you should avoid
-having any side-effects in your preface, and restrict it merely to symbol
-declarations and definitions.
-
-## Add :functions, for declaring functions to the byte-compiler
-
-What `:defines` does for variables, `:functions` does for functions.
-
-## use-package.el is no longer needed at runtime
-
-This means you should put the following at the top of your Emacs, to further
-reduce load time:
-
-``` elisp
-(eval-when-compile
- (require 'use-package))
-(require 'diminish) ;; if you use :diminish
-(require 'bind-key) ;; if you use any :bind variant
-```
-
# `use-package`
+[](https://travis-ci.org/jwiegley/use-package)
+
The `use-package` macro allows you to isolate package configuration in your
`.emacs` file in a way that is both performance-oriented and, well, tidy. I
created it because I have over 80 packages that I use in Emacs, and things
were getting difficult to manage. Yet with this utility my total load time is
around 2 seconds, with no loss of functionality!
+Notes for users upgrading to 2.x are located [at the bottom](#upgrading-to-2x).
+
## The basics
Here is the simplest `use-package` declaration:
@@ -106,7 +24,7 @@ succeeds, a message about `"Loading foo"` is logged, along with the time it
took to load, if it took over 0.1s.
Use the `:init` keyword to execute code before a package is loaded. It
-accepts one or more form, up until the next keyword:
+accepts one or more forms, up until the next keyword:
``` elisp
(use-package foo
@@ -131,10 +49,12 @@ As you might expect, you can use `:init` and `:config` together:
``` elisp
(use-package color-moccur
:commands (isearch-moccur isearch-all)
- :bind ("M-s O" . moccur)
+ :bind (("M-s O" . moccur)
+ :map isearch-mode-map
+ ("M-o" . isearch-moccur)
+ ("M-O" . isearch-moccur-all))
:init
- (bind-key "M-o" 'isearch-moccur isearch-mode-map)
- (bind-key "M-O" 'isearch-moccur-all isearch-mode-map)
+ (setq isearch-lazy-highlight t)
:config
(use-package moccur-edit))
```
@@ -142,7 +62,7 @@ As you might expect, you can use `:init` and `:config` together:
In this case, I want to autoload the commands `isearch-moccur` and
`isearch-all` from `color-moccur.el`, and bind keys both at the global level
and within the `isearch-mode-map` (see next section). When the package is
-actually loaded (by using one of these commands), `moccur-edit` is also be
+actually loaded (by using one of these commands), `moccur-edit` is also
loaded, to allow editing of the `moccur` buffer.
## Key-binding
@@ -186,6 +106,67 @@ The `:bind` keyword takes either a cons or a list of conses:
The `:commands` keyword likewise takes either a symbol or a list of symbols.
+NOTE: Special keys like `tab` or `F1`-`Fn` can be written in square brackets,
+i.e. `[tab]` instead of `"tab"`. The syntax for the keybindings is similar to
+the "kbd" syntax: see [https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-Rebinding.html](https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-Rebinding.html)
+for more information.
+
+Examples:
+
+``` elisp
+(use-package helm
+ :bind (("M-x" . helm-M-x)
+ ("M-<f5>" . helm-find-files)
+ ([f10] . helm-buffers-list)
+ ([S-f10] . helm-recentf)))
+```
+
+
+### Binding to keymaps
+
+Normally `:bind` expects that commands are functions that will be autoloaded
+from the given package. However, this does not work if one of those commands
+is actually a keymap, since keymaps are not functions, and cannot be
+autoloaded using Emacs' `autoload` mechanism.
+
+To handle this case, `use-package` offers a special, limited variant of
+`:bind` called `:bind-keymap`. The only difference is that the "commands"
+bound to by `:bind-keymap` must be keymaps defined in the package, rather than
+command functions. This is handled behind the scenes by generating custom code
+that loads the package containing the keymap, and then re-executes your
+keypress after the first load, to reinterpret that keypress as a prefix key.
+
+### Binding within local keymaps
+
+Slightly different from binding a key to a keymap, is binding a key *within* a
+local keymap that only exists after the package is loaded. `use-package`
+supports this with a `:map` modifier, taking the local keymap to bind to:
+
+``` elisp
+(use-package helm
+ :bind (:map helm-command-map
+ ("C-c h" . helm-execute-persistent-action)))
+```
+
+The effect of this statement is to wait until `helm` has loaded, and then to
+bind the key `C-c h` to `helm-execute-persistent-action` within Helm's local
+keymap, `helm-mode-map`.
+
+Multiple uses of `:map` may be specified. Any binding occurring before the
+first use of `:map` are applied to the global keymap:
+
+``` elisp
+(use-package term
+ :bind (("C-c t" . term)
+ :map term-mode-map
+ ("M-p" . term-send-up)
+ ("M-n" . term-send-down)
+ :map term-raw-map
+ ("M-o" . other-window)
+ ("M-p" . term-send-up)
+ ("M-n" . term-send-down)))
+```
+
## Modes and interpreters
Similar to `:bind`, you can use `:mode` and `:interpreter` to establish a
@@ -217,7 +198,12 @@ still defer loading with the `:defer` keyword:
(bind-key "C-." 'ace-jump-mode))
```
-This does exactly the same thing as the other two commands above.
+This does exactly the same thing as the following:
+
+``` elisp
+(use-package ace-jump-mode
+ :bind ("C-." . ace-jump-mode))
+```
## Notes about lazy loading
@@ -234,13 +220,14 @@ not establish an autoload for the bound key.
## Information about package loads
-When a package is loaded, and if you have `use-package-verbose` set t or if
-the package takes longer than 0.1s to load, you will see a message to indicate
-this loading activity in the `*Messages*` buffer. The same will happen for
-configuration, or `:config` blocks that take longer than 0.1s to execute. In
-general, you should keep `:init` forms as simple and quick as possible, and
-put as much as you can get away with into the `:config` block. This way,
-deferred loading can help your Emacs to start as quickly as possible.
+When a package is loaded, and if you have `use-package-verbose` set to `t`, or
+if the package takes longer than 0.1s to load, you will see a message to
+indicate this loading activity in the `*Messages*` buffer. The same will
+happen for configuration, or `:config` blocks that take longer than 0.1s to
+execute. In general, you should keep `:init` forms as simple and quick as
+possible, and put as much as you can get away with into the `:config` block.
+This way, deferred loading can help your Emacs to start as quickly as
+possible.
Additionally, if an error occurs while initializing or configuring a package,
this will not stop your Emacs from loading. Rather, the error will be
@@ -250,7 +237,9 @@ buffer, so that you can debug the situation in an otherwise functional Emacs.
## Conditional loading
You can use the `:if` keyword to predicate the loading and initialization of
-modules. For example, I only want `edit-server` running for my main,
+modules.
+
+For example, I only want `edit-server` running for my main,
graphical Emacs, not for other Emacsen I may start at the command line:
``` elisp
@@ -260,13 +249,22 @@ graphical Emacs, not for other Emacsen I may start at the command line:
(add-hook 'after-init-hook 'server-start t)
(add-hook 'after-init-hook 'edit-server-start t))
```
+In another example, we can load things conditional on the operating system:
+
+```
+(use-package exec-path-from-shell
+ :if (memq window-system '(mac ns))
+ :ensure t
+ :config
+ (exec-path-from-shell-initialize))
+```
The `:disabled` keyword can turn off a module you're having difficulties with,
-or to stop loading something you're not using at the present time:
+or stop loading something you're not using at the present time:
``` elisp
(use-package ess-site
- :disabled t
+ :disabled
:commands R)
```
@@ -352,15 +350,17 @@ looking up the same information again on each startup:
:commands R)
```
-## Diminishing minor modes
+## Diminishing and delighting minor modes
-`use-package` also provides built-in support for the diminish utility -- if
-you have that installed. Its purpose is to remove strings from your mode-line
-that provide no useful information. It is invoked with the `:diminish`
-keyword, which is passed either a minor mode symbol, a cons of the symbol and
-its replacement string, or just a replacement string, in which case the minor
-mode symbol is guessed to be the package name with "-mode" appended at the
-end:
+`use-package` also provides built-in support for the diminish and
+delight utilities -- if you have them installed. Their purpose is to
+remove or change minor mode strings in your mode-line.
+
+[diminish](https://github.com/myrjola/diminish.el) is invoked with
+the `:diminish` keyword, which is passed either a minor mode symbol, a
+cons of the symbol and its replacement string, or just a replacement
+string, in which case the minor mode symbol is guessed to be the
+package name with "-mode" appended at the end:
``` elisp
(use-package abbrev
@@ -370,13 +370,45 @@ end:
(quietly-read-abbrev-file)))
```
+[delight](https://elpa.gnu.org/packages/delight.html) is invoked with
+the `:delight` keyword, which is passed a minor mode symbol, a
+replacement string or
+quoted
+[mode-line data](https://www.gnu.org/software/emacs/manual/html_node/elisp/Mode-Line-Data.html) (in
+which case the minor mode symbol is guessed to be the package name
+with "-mode" appended at the end), both of these, or several lists of
+both. If no arguments are provided, the default mode name is hidden
+completely.
+
+``` elisp
+;; Don't show anything for rainbow-mode.
+(use-package rainbow-mode
+ :delight)
+
+;; Don't show anything for auto-revert-mode, which doesn't match
+;; its package name.
+(use-package autorevert
+ :delight auto-revert-mode)
+
+;; Remove the mode name for projectile-mode, but show the project name.
+(use-package projectile
+ :delight '(:eval (concat " " (projectile-project-name))))
+
+;; Completely hide visual-line-mode and change auto-fill-mode to " AF".
+(use-package emacs
+ :delight
+ (auto-fill-function " AF")
+ (visual-line-mode))
+```
+
## For `package.el` users
You can use `use-package` to load packages from ELPA with `package.el`. This
is particularly useful if you share your `.emacs` among several machines; the
-relevant packages are download automatically once declared in your `.emacs`.
+relevant packages are downloaded automatically once declared in your `.emacs`.
The `:ensure` keyword causes the package(s) to be installed automatically if
-not already present on your system:
+not already present on your system (set `(setq use-package-always-ensure t)`
+if you wish this behavior to be global for all packages):
``` elisp
(use-package magit
@@ -387,7 +419,7 @@ If you need to install a different package from the one named by
`use-package`, you can specify it like this:
``` elisp
-(use-package tex-site
+(use-package tex
:ensure auctex)
```
@@ -396,12 +428,13 @@ a specific archive, allowing you to mix and match packages from different
archives. The primary use-case for this is preferring packages from the
`melpa-stable` and `gnu` archives, but using specific packages from `melpa`
when you need to track newer versions than what is available in the `stable`
-archives.
+archives is also a valid use-case.
By default `package.el` prefers `melpa` over `melpa-stable` due to the
versioning `(> evil-20141208.623 evil-1.0.9)`, so even if you are tracking
only a single package from `melpa`, you will need to tag all the non-`melpa`
-packages with the appropriate archive.
+packages with the appropriate archive. If this really annoys you, then you can
+set `use-package-always-pin` to set a default.
If you want to manually keep a package updated and ignore upstream updates,
you can pin it to `manual`, which as long as there is no repository by that
@@ -441,12 +474,6 @@ Example:
**NOTE**: the `:pin` argument has no effect on emacs versions < 24.4.
-**NOTE**: if you pin a lot of packages, it will be slightly slower to start
-Emacs compared to manually adding all packages to the
-`package-pinned-packages` variable. However, should you do it this way, you
-need to keep track of when `(package-initialize)` is called, so letting
-`use-package` handle it for you is arguably worth the cost.
-
## Extending use-package with new or modified keywords
Starting with version 2.0, `use-package` is based on an extensible framework
@@ -499,7 +526,7 @@ Once you have a normalizer, you must create a handler for the keyword:
package-pinned-packages))))))
```
-Handlers can effect on the handling of keywords in two ways. First, it can
+Handlers can affect the handling of keywords in two ways. First, it can
modify the `state` plist before recursively processing the remaining keywords,
to influence keywords that pay attention to the state (one example is the
state keyword `:deferred`, not to be confused with the `use-package` keyword
@@ -541,3 +568,99 @@ time emacs -l init.elc -batch --eval '(message "Hello, world!")'
On the Mac I see an average of 0.36s for the same configuration, and on Linux
0.26s.
+
+# Upgrading to 2.x
+
+## Semantics of :init is now consistent
+
+The meaning of `:init` has been changed: It now *always* happens before
+package load, whether `:config` has been deferred or not. This means that
+some uses of `:init` in your configuration may need to be changed to `:config`
+(in the non-deferred case). For the deferred case, the behavior is unchanged
+from before.
+
+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).
+
+## :idle has been removed
+
+I am removing this feature for now because it can result in a nasty
+inconsistency. Consider the following definition:
+
+``` elisp
+(use-package vkill
+ :commands vkill
+ :idle (some-important-configuration-here)
+ :bind ("C-x L" . vkill-and-helm-occur)
+ :init
+ (defun vkill-and-helm-occur ()
+ (interactive)
+ (vkill)
+ (call-interactively #'helm-occur))
+
+ :config
+ (setq vkill-show-all-processes t))
+```
+
+If I load my Emacs and wait until the idle timer fires, then this is the
+sequence of events:
+
+ :init :idle <load> :config
+
+But if I load Emacs and immediately type C-x L without waiting for the idle
+timer to fire, this is the sequence of events:
+
+ :init <load> :config :idle
+
+It's possible that the user could use `featurep` in their idle to test for
+this case, but that's a subtlety I'd rather avoid.
+
+## :defer now accepts an optional integer argument
+
+`:defer [N]` causes the package to be loaded -- if it has not already been --
+after `N` seconds of idle time.
+
+```
+(use-package back-button
+ :commands (back-button-mode)
+ :defer 2
+ :init
+ (setq back-button-show-toolbar-buttons nil)
+ :config
+ (back-button-mode 1))
+```
+
+## Add :preface, occurring before everything except :disabled
+
+`:preface` can be used to establish function and variable definitions that
+will 1) make the byte-compiler happy (it won't complain about functions whose
+definitions are unknown because you have them within a guard block), and 2)
+allow you to define code that can be used in an `:if` test.
+
+Note that whatever is specified within `:preface` is evaluated both at load
+time and at byte-compilation time, in order to ensure that definitions are
+seen by both the Lisp evaluator and the byte-compiler, so you should avoid
+having any side-effects in your preface, and restrict it merely to symbol
+declarations and definitions.
+
+## Add :functions, for declaring functions to the byte-compiler
+
+What `:defines` does for variables, `:functions` does for functions.
+
+## use-package.el is no longer needed at runtime
+
+This means you should put the following at the top of your Emacs, to further
+reduce load time:
+
+``` elisp
+(eval-when-compile
+ (require 'use-package))
+(require 'diminish) ;; if you use :diminish
+(require 'bind-key) ;; if you use any :bind variant
+```
.emacs.d/lisp/use-package/use-package.el
@@ -5,8 +5,8 @@
;; Author: John Wiegley <jwiegley@gmail.com>
;; Maintainer: John Wiegley <jwiegley@gmail.com>
;; Created: 17 Jun 2012
-;; Modified: 26 Sep 2015
-;; Version: 2.1
+;; Modified: 17 Oct 2016
+;; Version: 2.3
;; Package-Requires: ((bind-key "1.0") (diminish "0.44"))
;; Keywords: dotemacs startup speed config package
;; URL: https://github.com/jwiegley/use-package
@@ -46,7 +46,8 @@
(eval-when-compile (require 'cl))
(eval-when-compile (require 'regexp-opt))
-(declare-function package-installed-p 'package)
+(declare-function package-installed-p "package")
+(declare-function package-read-all-archive-contents "package" ())
(defgroup use-package nil
"A use-package declaration for simplifying your `.emacs'."
@@ -79,13 +80,23 @@ The check is performed by looking for the module using `locate-library'."
:type 'boolean
:group 'use-package)
+(defcustom use-package-always-demand nil
+ "If non-nil, assume `:demand t` unless `:defer t` is given."
+ :type 'boolean
+ :group 'use-package)
+
+(defcustom use-package-always-defer-install nil
+ "If non-nil, assume `:defer-install t` unless `:defer-install nil` 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."
+ "Treat every package as though it had specified `:pin SYM`."
:type 'symbol
:group 'use-package)
@@ -125,14 +136,15 @@ the user specified."
(defcustom use-package-keywords
'(:disabled
+ :preface
:pin
+ :defer-install
:ensure
:if
:when
:unless
:requires
:load-path
- :preface
:no-require
:bind
:bind*
@@ -140,13 +152,15 @@ the user specified."
:bind-keymap*
:interpreter
:mode
+ :magic
+ :magic-fallback
:commands
:defines
:functions
:defer
+ :init
:after
:demand
- :init
:config
:diminish
:delight)
@@ -176,24 +190,132 @@ Must be set before loading use-package."
:type 'boolean
:group 'use-package)
+(defcustom use-package-ensure-function 'use-package-ensure-elpa
+ "Function that ensures a package is installed.
+This function is called with four arguments: the name of the
+package declared in the `use-package' form; the argument passed
+to `:ensure'; the current `state' plist created by previous
+handlers; and a keyword indicating the context in which the
+installation is occurring.
+
+Note that this function is called whenever `:ensure' is provided,
+even if it is nil. It is up to the function to decide on the
+semantics of the various values for `:ensure'.
+
+This function should return non-nil if the package is installed.
+
+The default value uses package.el to install the package.
+
+Possible values for the context keyword are:
+
+:byte-compile - package installed during byte-compilation
+:ensure - package installed normally by :ensure
+:autoload - deferred installation triggered by an autoloaded
+ function
+:after - deferred installation triggered by the loading of a
+ feature listed in the :after declaration
+:config - deferred installation was specified at the same time
+ as :demand, so the installation was triggered
+ immediately
+:unknown - context not provided
+
+Note that third-party code can provide other values for the
+context keyword by calling `use-package-install-deferred-package'
+with the appropriate value."
+ :type '(choice (const :tag "package.el" use-package-ensure-elpa)
+ (function :tag "Custom"))
+ :group 'use-package)
+
+(defcustom use-package-pre-ensure-function 'ignore
+ "Function that is called upon installation deferral.
+It is called immediately with the first three arguments that
+would be passed to `use-package-ensure-function' (the context
+keyword is omitted), but only if installation has been deferred.
+It is intended for package managers other than package.el which
+might want to activate the autoloads of a package immediately, if
+it's installed, but otherwise defer installation until later (if
+`:defer-install' is specified). The reason it is set to `ignore'
+by default is that package.el activates the autoloads for all
+known packages at initialization time, rather than one by one
+when the packages are actually requested."
+ :type '(choice (const :tag "None" ignore)
+ (function :tag "Custom"))
+ :group 'use-package)
+
+(defcustom use-package-defaults
+ '((:config '(t) t)
+ (:ensure use-package-always-ensure use-package-always-ensure)
+ (:defer-install
+ use-package-always-defer-install
+ use-package-always-defer-install)
+ (:pin use-package-always-pin use-package-always-pin))
+ "Alist of default values for `use-package' keywords.
+Each entry in the alist is a list of three elements. The first
+element is the `use-package' keyword and the second is a form
+that can be evaluated to get the default value. The third element
+is a form that can be evaluated to determine whether or not to
+assign a default value; if it evaluates to nil, then the default
+value is not assigned even if the keyword is not present in the
+`use-package' form."
+ :type '(repeat (list symbol sexp sexp)))
+
(when use-package-enable-imenu-support
- ;; Not defined in Emacs 24
- (defvar lisp-mode-symbol-regexp
- "\\(?:\\sw\\|\\s_\\|\\\\.\\)+")
- (add-to-list
- 'lisp-imenu-generic-expression
- (list "Package"
- (purecopy (concat "^\\s-*("
- (eval-when-compile
- (regexp-opt
- '("use-package" "require")
- t))
- "\\s-+\\(" lisp-mode-symbol-regexp "\\)"))
- 2)))
+ (eval-after-load 'lisp-mode
+ `(let ((sym-regexp (or (bound-and-true-p lisp-mode-symbol-regexp)
+ "\\(?:\\sw\\|\\s_\\|\\\\.\\)+")))
+ (add-to-list
+ 'lisp-imenu-generic-expression
+ (list "Packages"
+ (concat "^\\s-*("
+ ,(eval-when-compile
+ (regexp-opt '("use-package" "require") t))
+ "\\s-+\\(" sym-regexp "\\)")
+ 2)))))
+
+(defvar use-package-form-regexp "^\\s-*(\\s-*use-package\\s-+\\_<%s\\_>"
+ "Regexp used in `use-package-jump-to-package-form' to find use
+package forms in user files.")
+
+(defun use-package--find-require (package)
+ "Find file that required PACKAGE by searching
+`load-history'. Returns an absolute file path or nil if none is
+found."
+ (catch 'suspect
+ (dolist (filespec load-history)
+ (dolist (entry (cdr filespec))
+ (when (equal entry (cons 'require package))
+ (throw 'suspect (car filespec)))))))
+
+(defun use-package-jump-to-package-form (package)
+ "Attempt to find and jump to the `use-package' form that loaded
+PACKAGE. This will only find the form if that form actually
+required PACKAGE. If PACKAGE was previously required then this
+function will jump to the file that orginally required PACKAGE
+instead."
+ (interactive (list (completing-read "Package: " features)))
+ (let* ((package (if (stringp package) (intern package) package))
+ (requiring-file (use-package--find-require package))
+ file location)
+ (if (null requiring-file)
+ (user-error "Can't find file that requires this feature.")
+ (setq file (if (string= (file-name-extension requiring-file) "elc")
+ (concat (file-name-sans-extension requiring-file) ".el")
+ requiring-file))
+ (when (file-exists-p file)
+ (find-file-other-window file)
+ (save-excursion
+ (goto-char (point-min))
+ (setq location
+ (re-search-forward
+ (format use-package-form-regexp package) nil t)))
+ (if (null location)
+ (message "No use-package form found.")
+ (goto-char location)
+ (beginning-of-line))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Utility functions
+;;; Utility functions
;;
(defun use-package-as-symbol (string-or-symbol)
@@ -208,12 +330,20 @@ convert it to a string and return that."
(if (stringp string-or-symbol) string-or-symbol
(symbol-name string-or-symbol)))
+(defun use-package-as-mode (string-or-symbol)
+ "If STRING-OR-SYMBOL ends in `-mode' (or its name does), return
+it as a symbol. Otherwise, return it as a symbol with `-mode'
+appended."
+ (let ((string (use-package-as-string string-or-symbol)))
+ (intern (if (string-match "-mode\\'" string) string
+ (concat string "-mode")))))
+
(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)))
+ `(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."
@@ -298,7 +428,7 @@ 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 p (plist-put p (car plist) (nth 1 plist))))
(setq plist (cddr plist)))
p))
@@ -350,14 +480,36 @@ This is in contrast to merely setting it to 0."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Keyword processing
+;;; Keyword processing
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Normalization functions
+;;; Normalization functions
;;
+(defun use-package-regex-p (re)
+ "Return t if RE is some regexp-like thing."
+ (cond
+ ((and (listp re)
+ (eq (car re) 'rx))
+ t)
+ ((stringp re)
+ t)
+ (t
+ nil)))
+
+(defun use-package-normalize-regex (re)
+ "Given some regexp-like thing, resolve it down to a regular expression."
+ (cond
+ ((and (listp re)
+ (eq (car re) 'rx))
+ (eval re))
+ ((stringp re)
+ re)
+ (t
+ (error "Not recognized as regular expression: %s" re))))
+
(defun use-package-normalize-plist (name input)
"Given a pseudo-plist, normalize it to a regular plist."
(unless (null input)
@@ -413,7 +565,7 @@ next value for the STATE."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :pin
+;;; :pin
;;
(defun use-package-only-one (label args f)
@@ -483,7 +635,84 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :ensure
+;;; :defer-install
+;;
+
+(defvar use-package--deferred-packages (make-hash-table)
+ "Hash mapping packages to data about their installation.
+
+The keys are not actually symbols naming packages, but rather
+symbols naming the features which are the names of \"packages\"
+required by `use-package' forms. Since
+`use-package-ensure-function' could be set to anything, it is
+actually impossible for `use-package' to determine what package
+is supposed to provide the feature being ensured just based on
+the value of `:ensure'.
+
+Each value is a cons, with the car being the the value passed to
+`:ensure' and the cdr being the `state' plist. See
+`use-package-install-deferred-package' for information about how
+these values are used to call `use-package-ensure-function'.")
+
+(defun use-package-install-deferred-package (name &optional context)
+ "Install a package whose installation has been deferred.
+NAME should be a symbol naming a package (actually, a feature).
+This is done by calling `use-package-ensure-function' is called
+with four arguments: the key (NAME) and the two elements of the
+cons in `use-package--deferred-packages' (the value passed to
+`:ensure', and the `state' plist), and a keyword providing
+information about the context in which the installation is
+happening. (This defaults to `:unknown' but can be overridden by
+providing CONTEXT.)
+
+Return t if the package is installed, nil otherwise. (This is
+determined by the return value of `use-package-ensure-function'.)
+If the package is installed, its entry is removed from
+`use-package--deferred-packages'. If the package has no entry in
+`use-package--deferred-packages', do nothing and return t."
+ (interactive
+ (let ((packages nil))
+ (maphash (lambda (package info)
+ (push package packages))
+ use-package--deferred-packages)
+ (if packages
+ (list
+ (intern
+ (completing-read
+ "Select package: "
+ packages
+ nil
+ 'require-match))
+ :interactive)
+ (user-error "No packages with deferred installation"))))
+ (let ((spec (gethash name use-package--deferred-packages)))
+ (if spec
+ (when (funcall use-package-ensure-function
+ name (car spec) (cdr spec)
+ (or context :unknown))
+ (remhash name use-package--deferred-packages)
+ t)
+ t)))
+
+(defalias 'use-package-normalize/:defer-install 'use-package-normalize-test)
+
+(defun use-package-handler/:defer-install (name keyword defer rest state)
+ (use-package-process-keywords name rest
+ ;; Just specifying `:defer-install' does not do anything; this
+ ;; sets up a marker so that if `:ensure' is specified as well then
+ ;; it knows to set up deferred installation. But then later, when
+ ;; `:config' is processed, it might turn out that `:demand' was
+ ;; specified as well, and the deferred installation needs to be
+ ;; run immediately. For this we need to know if the deferred
+ ;; installation was actually set up or not, so we need to set one
+ ;; marker value in `:defer-install', and then change it to a
+ ;; different value in `:ensure', if the first one is present. (The
+ ;; first marker is `:defer-install', and the second is `:ensure'.)
+ (plist-put state :defer-install (when defer :defer-install))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; :ensure
;;
(defvar package-archive-contents)
(defun use-package-normalize/:ensure (name keyword args)
@@ -497,38 +726,71 @@ manually updated package."
(concat ":ensure wants an optional package name "
"(an unquoted symbol name)")))))))
-(defun use-package-ensure-elpa (package &optional no-refresh)
- (if (package-installed-p package)
- t
- (if (or (assoc package package-archive-contents) no-refresh)
- (package-install package)
- (progn
- (package-refresh-contents)
- (use-package-ensure-elpa package t)))))
+(defun use-package-ensure-elpa (name ensure state context &optional no-refresh)
+ (let ((package (or (when (eq ensure t) (use-package-as-symbol name))
+ ensure)))
+ (when package
+ (require 'package)
+ (or (package-installed-p package)
+ (not (or
+ ;; Contexts in which the confirmation prompt is
+ ;; bypassed.
+ (member context '(:byte-compile :ensure :config))
+ (y-or-n-p (format "Install package %S?" package))))
+ (with-demoted-errors (format "Cannot load %s: %%S" name)
+ (when (assoc package (bound-and-true-p package-pinned-packages))
+ (package-read-all-archive-contents))
+ (if (assoc package package-archive-contents)
+ (progn (package-install package) t)
+ (progn
+ (package-refresh-contents)
+ (when (assoc package (bound-and-true-p
+ package-pinned-packages))
+ (package-read-all-archive-contents))
+ (package-install package))))))))
(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)))))
+ (let* ((body (use-package-process-keywords name rest
+ ;; Here we are conditionally updating the marker
+ ;; value for deferred installation; this will be
+ ;; checked later by `:config'. For more information
+ ;; see `use-package-handler/:defer-install'.
+ (if (eq (plist-get state :defer-install)
+ :defer-install)
+ (plist-put state :defer-install :ensure)
+ state))))
;; 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.
+ (cond
+ ((plist-get state :defer-install)
+ (push
+ `(puthash ',name '(,ensure . ,state)
+ use-package--deferred-packages)
+ body)
+ (push `(,use-package-pre-ensure-function
+ ',name ',ensure ',state)
+ body))
+ ((bound-and-true-p byte-compile-current-file)
+ ;; Eval when byte-compiling,
+ (funcall use-package-ensure-function
+ name ensure state :byte-compile))
+ ;; or else wait until runtime.
+ (t (push `(,use-package-ensure-function
+ ',name ',ensure ',state :ensure)
+ body)))
body))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :if, :when and :unless
+;;; :if, :when and :unless
;;
(defsubst use-package-normalize-value (label arg)
"Normalize a value."
- (cond ((symbolp arg)
+ (cond ((null arg) nil)
+ ((symbolp arg)
`(symbol-value ',arg))
((functionp arg)
`(funcall #',arg))
@@ -554,7 +816,7 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :requires
+;;; :requires
;;
(defun use-package-as-one (label args f)
@@ -584,6 +846,22 @@ manually updated package."
(use-package-as-one (symbol-name keyword) args
#'use-package-normalize-symbols))
+(defun use-package-normalize-recursive-symbols (label arg)
+ "Normalize a list of symbols."
+ (cond
+ ((symbolp arg)
+ arg)
+ ((and (listp arg) (listp (cdr arg)))
+ (mapcar #'(lambda (x) (use-package-normalize-recursive-symbols label x))
+ arg))
+ (t
+ (use-package-error
+ (concat label " wants a symbol, or nested list of symbols")))))
+
+(defun use-package-normalize-recursive-symlist (name keyword args)
+ (use-package-as-one (symbol-name keyword) args
+ #'use-package-normalize-recursive-symbols))
+
(defalias 'use-package-normalize/:requires 'use-package-normalize-symlist)
(defun use-package-handler/:requires (name keyword requires rest state)
@@ -597,7 +875,7 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :load-path
+;;; :load-path
;;
(defun use-package-normalize-paths (label arg &optional recursed)
@@ -631,7 +909,7 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :no-require
+;;; :no-require
;;
(defun use-package-normalize-predicate (name keyword args)
@@ -648,7 +926,7 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :preface
+;;; :preface
;;
(defun use-package-normalize-form (label args)
@@ -675,50 +953,69 @@ manually updated package."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :bind, :bind*
+;;; :bind, :bind*
;;
-(defsubst use-package-is-sympair (x &optional allow-vector)
- "Return t if X has the type (STRING . SYMBOL)."
+(defsubst use-package-is-pair (x car-pred cdr-pred)
+ "Return non-nil if X is a cons satisfying the given predicates.
+CAR-PRED and CDR-PRED are applied to X's `car' and `cdr',
+respectively."
(and (consp x)
- (or (stringp (car x))
- (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))))
+ (funcall car-pred (car x))
+ (funcall cdr-pred (cdr x))))
(defun use-package-normalize-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'."
+ (key-pred val-pred name label arg &optional recursed)
+ "Normalize a list of pairs.
+KEY-PRED and VAL-PRED are predicates recognizing valid keys and
+values, respectively.
+If RECURSED is non-nil, recurse into sublists."
(cond
- ((or (stringp arg) (and allow-vector (vectorp arg)))
+ ((funcall key-pred arg)
(list (cons arg (use-package-as-symbol name))))
- ((use-package-is-sympair arg allow-vector)
+ ((use-package-is-pair arg key-pred val-pred)
(list arg))
((and (not recursed) (listp arg) (listp (cdr arg)))
- (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))
+ (let ((last-item nil))
+ (mapcar #'(lambda (x)
+ (prog1
+ (let ((ret (use-package-normalize-pairs
+ key-pred val-pred name label x t)))
+ ;; Currently, the handling of keyword
+ ;; arguments by `use-package' and `bind-key'
+ ;; is non-uniform and undocumented. As a
+ ;; result, `use-package-normalize-pairs' (as
+ ;; it is currently implemented) does not
+ ;; correctly handle the keyword-argument
+ ;; syntax of `bind-keys'. A permanent solution
+ ;; to this problem will require a careful
+ ;; consideration of the desired
+ ;; keyword-argument interface for
+ ;; `use-package' and `bind-key'. However, in
+ ;; the meantime, we have a quick patch to fix
+ ;; a serious bug in the handling of keyword
+ ;; arguments. Namely, the code below would
+ ;; normally unwrap lists that were passed as
+ ;; keyword arguments (for example, the
+ ;; `:filter' argument in `:bind') without
+ ;; the (not (keywordp last-item)) clause. See
+ ;; #447 for further discussion.
+ (if (and (listp ret) (not (keywordp last-item)))
+ (car ret)
+ ret))
+ (setq last-item x))) arg)))
(t arg)))
(defun use-package-normalize-binder (name keyword args)
(use-package-as-one (symbol-name keyword) args
(lambda (label arg)
- (use-package-normalize-pairs name label arg nil t t))))
+ (unless (consp arg)
+ (use-package-error
+ (concat label " a (<string or vector> . <symbol or string>)"
+ " or list of these")))
+ (use-package-normalize-pairs (lambda (k) (or (stringp k) (vectorp k)))
+ (lambda (b) (or (symbolp b) (stringp b)))
+ name label arg))))
(defalias 'use-package-normalize/:bind 'use-package-normalize-binder)
(defalias 'use-package-normalize/:bind* 'use-package-normalize-binder)
@@ -744,12 +1041,13 @@ may also be a string, as accepted by `define-key'."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :bind-keymap, :bind-keymap*
+;;; :bind-keymap, :bind-keymap*
;;
(defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder)
(defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder)
+;;;###autoload
(defun use-package-autoload-keymap (keymap-symbol package override)
"Loads PACKAGE and then binds the key sequence used to invoke
this function to KEYMAP-SYMBOL. It then simulates pressing the
@@ -801,20 +1099,25 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :interpreter
+;;; :interpreter
;;
(defun use-package-normalize-mode (name keyword args)
+ "Normalize arguments for keywords which add regexp/mode pairs to an alist."
(use-package-as-one (symbol-name keyword) args
- (apply-partially #'use-package-normalize-pairs name)))
+ (apply-partially #'use-package-normalize-pairs
+ #'use-package-regex-p
+ (lambda (m) (and (not (null m)) (symbolp m)))
+ name)))
-(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode)
-
-(defun use-package-handler/:interpreter (name keyword arg rest state)
+(defun use-package-handle-mode (name alist arg rest state)
+ "Handle keywords which add regexp/mode pairs to an alist."
(let* (commands
- (form (mapcar #'(lambda (interpreter)
- (push (cdr interpreter) commands)
- `(add-to-list 'interpreter-mode-alist ',interpreter)) arg)))
+ (form (mapcar #'(lambda (thing)
+ (push (cdr thing) commands)
+ (setcar thing
+ (use-package-normalize-regex (car thing)))
+ `(add-to-list ',alist ',thing)) arg)))
(use-package-concat
(use-package-process-keywords name
(use-package-sort-keywords
@@ -822,28 +1125,44 @@ deferred until the prefix key sequence is pressed."
(use-package-plist-append state :commands commands))
`((ignore ,@form)))))
+(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode)
+
+(defun use-package-handler/:interpreter (name keyword arg rest state)
+ (use-package-handle-mode name 'interpreter-mode-alist arg rest state))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :mode
+;;; :mode
;;
(defalias 'use-package-normalize/:mode 'use-package-normalize-mode)
(defun use-package-handler/:mode (name keyword arg rest state)
- (let* (commands
- (form (mapcar #'(lambda (mode)
- (push (cdr mode) commands)
- `(add-to-list 'auto-mode-alist ',mode)) arg)))
- (use-package-concat
- (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 ,@form)))))
+ (use-package-handle-mode name 'auto-mode-alist arg rest state))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :commands
+;;; :magic
+;;
+
+(defalias 'use-package-normalize/:magic 'use-package-normalize-mode)
+
+(defun use-package-handler/:magic (name keyword arg rest state)
+ (use-package-handle-mode name 'magic-mode-alist arg rest state))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; :magic-fallback
+;;
+
+(defalias 'use-package-normalize/:magic-fallback 'use-package-normalize-mode)
+
+(defun use-package-handler/:magic-fallback (name keyword arg rest state)
+ (use-package-handle-mode name 'magic-fallback-mode-alist arg rest state))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; :commands
;;
(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
@@ -857,7 +1176,7 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :defines
+;;; :defines
;;
(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist)
@@ -868,7 +1187,7 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :functions
+;;; :functions
;;
(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist)
@@ -887,11 +1206,40 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :defer
+;;; :defer
;;
(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
+(defun use-package--autoload-with-deferred-install
+ (command package-name)
+ "Return a form defining an autoload supporting deferred install."
+ `(let* ((load-list-item '(defun . ,command))
+ (already-loaded (member load-list-item current-load-list)))
+ (defun ,command (&rest args)
+ "[Arg list not available until function definition is loaded.]
+
+\(fn ...)"
+ (interactive)
+ (if (bound-and-true-p use-package--recursive-autoload)
+ (use-package-error
+ (format "Autoloading failed to define function %S"
+ ',command))
+ (when (use-package-install-deferred-package
+ ',package-name :autoload)
+ (require ',package-name)
+ (let ((use-package--recursive-autoload t))
+ (if (called-interactively-p 'any)
+ (call-interactively ',command)
+ (apply ',command args))))))
+ ;; This prevents the user's init-file from being recorded as the
+ ;; definition location for the function before it is actually
+ ;; loaded. (Our goal is to leave the `current-load-list'
+ ;; unchanged, so we only remove the entry for this function if it
+ ;; was not already present.)
+ (unless already-loaded
+ (setq current-load-list (remove load-list-item current-load-list)))))
+
(defun use-package-handler/:defer (name keyword arg rest state)
(let ((body (use-package-process-keywords name rest
(plist-put state :deferred t)))
@@ -906,48 +1254,84 @@ deferred until the prefix key sequence is pressed."
;; keep the byte-compiler happy.
(apply
#'nconc
- (mapcar #'(lambda (command)
- (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))))
+ (mapcar
+ #'(lambda (command)
+ (when (not (stringp command))
+ (append
+ `((unless (fboundp ',command)
+ ;; Here we are checking the marker value set in
+ ;; `use-package-handler/:ensure' to see if deferred
+ ;; installation is actually happening. See
+ ;; `use-package-handler/:defer-install' for more
+ ;; information.
+ ,(if (eq (plist-get state :defer-install) :ensure)
+ (use-package--autoload-with-deferred-install
+ command name)
+ `(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
+;;; :after
;;
-(defalias 'use-package-normalize/:after 'use-package-normalize-symlist)
+(defalias 'use-package-normalize/:after 'use-package-normalize-recursive-symlist)
-(defun use-package-require-after-load (features name)
+(defun use-package-require-after-load
+ (features)
"Return form for after any of FEATURES require NAME."
- `(progn
- ,@(mapcar
- (lambda (feat)
- `(eval-after-load
- (quote ,feat)
- (quote (require (quote ,name) nil t))))
- features)))
+ (pcase features
+ ((and (pred symbolp) feat)
+ `(lambda (body)
+ (list 'eval-after-load (list 'quote ',feat)
+ (list 'quote body))))
+ (`(,(or :or :any) . ,rest)
+ `(lambda (body)
+ (append (list 'progn)
+ (mapcar (lambda (form)
+ (funcall form body))
+ (list ,@(use-package-require-after-load rest))))))
+ (`(,(or :and :all) . ,rest)
+ `(lambda (body)
+ (let ((result body))
+ (dolist (form (list ,@(use-package-require-after-load rest)))
+ (setq result (funcall form result)))
+ result)))
+ (`(,feat . ,rest)
+ (if rest
+ (cons (use-package-require-after-load feat)
+ (use-package-require-after-load rest))
+ (list (use-package-require-after-load feat))))))
(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)))
+ (if (and (consp arg)
+ (not (memq (car arg) '(:or :any :and :all))))
+ (setq arg (cons :all arg)))
(use-package-concat
(when arg
- (list (use-package-require-after-load arg name)))
+ (list (funcall (use-package-require-after-load arg)
+ (macroexp-progn
+ ;; Here we are checking the marker value for deferred
+ ;; installation set in `use-package-handler/:ensure'.
+ ;; See also `use-package-handler/:defer-install'.
+ `(,@(when (eq (plist-get state :defer-install) :ensure)
+ `((use-package-install-deferred-package
+ 'name :after)))
+ (require (quote ,name) nil t))))))
body)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :demand
+;;; :demand
;;
(defalias 'use-package-normalize/:demand 'use-package-normalize-predicate)
@@ -958,7 +1342,7 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :init
+;;; :init
;;
(defalias 'use-package-normalize/:init 'use-package-normalize-forms)
@@ -978,7 +1362,7 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :config
+;;; :config
;;
(defalias 'use-package-normalize/:config 'use-package-normalize-forms)
@@ -1000,6 +1384,11 @@ deferred until the prefix key sequence is pressed."
(unless (or (null config-body) (equal config-body '(t)))
`((eval-after-load ,(if (symbolp name) `',name name)
',(macroexp-progn config-body))))
+ ;; Here we are checking the marker value for deferred
+ ;; installation set in `use-package-handler/:ensure'. See also
+ ;; `use-package-handler/:defer-install'.
+ (when (eq (plist-get state :defer-install) :ensure)
+ (use-package-install-deferred-package name :config))
(use-package--with-elapsed-timer
(format "Loading package %s" name)
(if use-package-expand-minimally
@@ -1013,7 +1402,8 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :diminish
+;;; :diminish
+;;
(defun use-package-normalize-diminish (name label arg &optional recursed)
"Normalize the arguments to diminish down to a list of one of two forms:
@@ -1051,33 +1441,55 @@ deferred until the prefix key sequence is pressed."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; :delight
+;;; :delight
;;
+(defun use-package--normalize-delight-1 (name args)
+ "Normalize ARGS for a single call to `delight'."
+ (when (eq :eval (car args))
+ ;; Handle likely common mistake.
+ (use-package-error ":delight mode line constructs must be quoted"))
+ (cond ((and (= (length args) 1) (symbolp (car args)))
+ `(,(nth 0 args) nil ,name))
+ ((= (length args) 2)
+ `(,(nth 0 args) ,(nth 1 args) ,name))
+ ((= (length args) 3)
+ args)
+ (t
+ (use-package-error
+ ":delight expects `delight' arguments or a list of them"))))
+
(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))
- ((and (= (length args) 2)
- (symbolp (car args)))
- (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"))))
+ (cond ((null args)
+ `((,(use-package-as-mode name) nil ,name)))
+ ((and (= (length args) 1)
+ (symbolp (car args)))
+ `((,(car args) nil ,name)))
+ ((and (= (length args) 1)
+ (stringp (car args)))
+ `((,(use-package-as-mode name) ,(car args) ,name)))
+ ((and (= (length args) 1)
+ (listp (car args))
+ (eq 'quote (caar args)))
+ `((,(use-package-as-mode name) ,@(cdar args) ,name)))
+ ((and (= (length args) 2)
+ (listp (nth 1 args))
+ (eq 'quote (car (nth 1 args))))
+ `((,(car args) ,@(cdr (nth 1 args)) ,name)))
+ (t (mapcar
+ (apply-partially #'use-package--normalize-delight-1 name)
+ (if (symbolp (car args)) (list args) args)))))
(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))))
+ `((delight '(,@args))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; The main macro
+;;; The main macro
;;
;;;###autoload
@@ -1090,84 +1502,86 @@ 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.
-: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.
+: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.
-:mode Form to be added to `auto-mode-alist'.
-:interpreter Form to be added to `interpreter-mode-alist'.
+:mode Form to be added to `auto-mode-alist'.
+:magic Form to be added to `magic-mode-alist'.
+:magic-fallback Form to be added to `magic-fallback-mode-alist'.
+: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.
+: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
+: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.
+:defer Defer loading of a package -- this is implied when using
+ `:commands', `:bind', `:bind*', `:mode', `:magic',
+ `:magic-fallback', 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.
+:after Defer loading of a package until after any of the named
+ features are loaded.
-:demand Prevent deferred loading in all cases.
+: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."
+: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).
+:delight Support for delight.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 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)))
- (args* (use-package-sort-keywords
- (if use-package-always-pin
- (use-package-plist-maybe-put
- args* :pin use-package-always-pin)
- args*))))
+ (let ((name-symbol (if (stringp name) (intern name) name))
+ (args (use-package-normalize-plist name args)))
+ (dolist (spec use-package-defaults)
+ (setq args (use-package-sort-keywords
+ (if (eval (nth 2 spec))
+ (use-package-plist-maybe-put
+ args (nth 0 spec) (eval (nth 1 spec)))
+ args))))
;; 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*
+ (setq args
(use-package-plist-cons
- args* :preface
+ args :preface
`(eval-when-compile
,@(mapcar #'(lambda (var) `(defvar ,var))
- (plist-get args* :defines))
+ (plist-get args :defines))
(with-demoted-errors
,(format "Cannot load %s: %%S" name)
,(if (eq use-package-verbose 'debug)
`(message "Compiling package %s" ',name-symbol))
- ,(unless (plist-get args* :no-require)
+ ,(unless (plist-get args :no-require)
(use-package-load-name name)))))))
(let ((body
(macroexp-progn
- (use-package-process-keywords name args*
- (and use-package-always-defer '(:deferred t))))))
+ (use-package-process-keywords name
+ (if use-package-always-demand
+ (append args '(:demand t))
+ args)
+ (and use-package-always-defer (list :deferred t))))))
(if use-package-debug
(display-buffer
(save-current-buffer
@@ -1185,6 +1599,7 @@ this file. Usage:
(provide 'use-package)
;; Local Variables:
+;; outline-regexp: ";;;\\(;* [^\s\t\n]\\|###autoload\\)\\|("
;; indent-tabs-mode: nil
;; End: