28d8587de00cecfca91b09182d937c2ab5f5b55b
[emacs.git] / .emacs.d / elisp / local / use-package.el
1 ;;; use-package.el --- A use-package declaration for simplifying your .emacs
2
3 ;; Copyright (C) 2012 John Wiegley
4
5 ;; Author: John Wiegley <jwiegley@gmail.com>
6 ;; Created: 17 Jun 2012
7 ;; Version: 1.0
8 ;; Package-Requires: ((bind-key "1.0") (diminish "0.44"))
9 ;; Keywords: dotemacs startup speed config package
10 ;; X-URL: https://github.com/jwiegley/use-package
11
12 ;; This program is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 2, or (at
15 ;; your option) any later version.
16
17 ;; This program is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
26 \f
27 ;;; Commentary:
28
29 ;; The `use-package' declaration macro allows you to isolate package
30 ;; configuration in your ".emacs" in a way that is performance-oriented and,
31 ;; well, just tidy. I created it because I have over 80 packages that I use
32 ;; in Emacs, and things were getting difficult to manage. Yet with this
33 ;; utility my total load time is just under 1 second, with no loss of
34 ;; functionality!
35 ;;
36 ;; Please see README.md from the same repository for documentation.
37 \f
38 ;;; Code:
39
40 (require 'bind-key)
41 (require 'bytecomp)
42 (require 'diminish nil t)
43
44 (declare-function package-installed-p 'package)
45
46 (defgroup use-package nil
47 "A use-package declaration for simplifying your `.emacs'."
48 :group 'startup)
49
50 (defcustom use-package-verbose nil
51 "Whether to report about loading and configuration details.
52
53 If you customize this, then you should require the `use-package'
54 feature in files that use one of the macros `use-package' or
55 `use-package-with-elapsed-timer', even if these files only
56 contain compiled expansions of the macros. If you don't do so,
57 then the expanded macros do their job silently."
58 :type 'boolean
59 :group 'use-package)
60
61 (defcustom use-package-minimum-reported-time 0.01
62 "Minimal load time that will be reported.
63
64 Note that `use-package-verbose' has to be set to t, for anything
65 to be reported at all.
66
67 If you customize this, then you should require the `use-package'
68 feature in files that use one of the macros `use-package' or
69 `use-package-with-elapsed-timer', even if these files only
70 contain compiled expansions of the macros. If you don't do so,
71 then the expanded macros do their job silently."
72 :type 'number
73 :group 'use-package)
74
75 (defcustom use-package-idle-interval 3
76 "Time to wait when using :idle in a `use-package' specification."
77 :type 'number
78 :group 'use-package)
79
80 (defmacro use-package-with-elapsed-timer (text &rest body)
81 (declare (indent 1))
82 (let ((nowvar (make-symbol "now")))
83 `(if (bound-and-true-p use-package-verbose)
84 (let ((,nowvar (current-time)))
85 (message "%s..." ,text)
86 (prog1 (progn ,@body)
87 (let ((elapsed
88 (float-time (time-subtract (current-time) ,nowvar))))
89 (if (> elapsed
90 (or (bound-and-true-p use-package-minimum-reported-time)
91 "0.01"))
92 (message "%s...done (%.3fs)" ,text elapsed)
93 (message "%s...done" ,text)))))
94 ,@body)))
95
96 (put 'use-package-with-elapsed-timer 'lisp-indent-function 1)
97
98 (defvar use-package-idle-timer nil)
99 (defvar use-package-idle-forms (make-hash-table))
100
101 (defun use-package-start-idle-timer ()
102 "Ensure that the idle timer is running."
103 (unless use-package-idle-timer
104 (setq use-package-idle-timer
105 (run-with-idle-timer
106 use-package-idle-interval t
107 'use-package-idle-eval))))
108
109 (defun use-package-init-on-idle (form priority)
110 "Add a new form to the idle queue."
111 (use-package-start-idle-timer)
112 (puthash priority
113 (append (gethash priority use-package-idle-forms)
114 (list form))
115 use-package-idle-forms))
116
117 (defun use-package-idle-priorities ()
118 "Get a list of all priorities in the idle queue.
119 The list is sorted in the order forms should be run."
120 (let ((priorities nil))
121 (maphash (lambda (priority forms)
122 (setq priorities (cons priority priorities)))
123 use-package-idle-forms)
124 (sort priorities '<)))
125
126 (defun use-package-idle-pop ()
127 "Pop the top-priority task from the idle queue.
128 Return nil when the queue is empty."
129 (let* ((priority (car (use-package-idle-priorities)))
130 (forms (gethash priority use-package-idle-forms))
131 (first-form (car forms))
132 (forms-remaining (cdr forms)))
133 (if forms-remaining
134 (puthash priority forms-remaining use-package-idle-forms)
135 (remhash priority use-package-idle-forms))
136 first-form))
137
138 (defun use-package-idle-eval()
139 "Start to eval idle-commands from the idle queue."
140 (let ((next (use-package-idle-pop)))
141 (if next
142 (progn
143 (when use-package-verbose
144 (message "use-package idle:%s" next))
145
146 (condition-case e
147 (funcall next)
148 (error
149 (message
150 "Failure on use-package idle. Form: %s, Error: %s"
151 next e)))
152 ;; recurse after a bit
153 (when (sit-for use-package-idle-interval)
154 (use-package-idle-eval)))
155 ;; finished (so far!)
156 (cancel-timer use-package-idle-timer)
157 (setq use-package-idle-timer nil))))
158
159 (defun use-package-pin-package (package archive)
160 "Pin PACKAGE to ARCHIVE."
161 (unless (boundp 'package-pinned-packages)
162 (setq package-pinned-packages ()))
163 (let ((archive-symbol (if (symbolp archive) archive (intern archive)))
164 (archive-name (if (stringp archive) archive (symbol-name archive))))
165 (if (use-package--archive-exists-p archive-symbol)
166 (add-to-list 'package-pinned-packages (cons package archive-name))
167 (error (message "Archive '%s' requested for package '%s' is not available." archive-name package)))
168 (package-initialize t)))
169
170 (defun use-package--archive-exists-p (archive)
171 "Check if a given ARCHIVE is enabled.
172
173 ARCHIVE can be a string or a symbol or 'manual to indicate a manually updated package."
174 (if (member archive '(manual "manual"))
175 't
176 (let ((valid nil))
177 (dolist (pa package-archives)
178 (when (member archive (list (car pa) (intern (car pa))))
179 (setq valid 't)))
180 valid)))
181
182 (defun use-package-ensure-elpa (package)
183 (when (not (package-installed-p package))
184 (package-install package)))
185
186 (defvar use-package-keywords
187 '(
188 :bind
189 :bind*
190 :commands
191 :config
192 :defer
193 :defines
194 :demand
195 :diminish
196 :disabled
197 :ensure
198 :idle
199 :idle-priority
200 :if
201 :init
202 :interpreter
203 :load-path
204 :mode
205 :pin
206 :pre-init
207 :pre-load
208 :requires
209 :bind-keymap
210 :bind-keymap*
211 )
212 "Keywords recognized by `use-package'.")
213
214 (defun use-package-mplist-get (plist prop)
215 "Get the values associated to PROP in PLIST, a modified plist.
216
217 A modified plist is one where keys are keywords and values are
218 all non-keywords elements that follow it.
219
220 As a special case : if the first occurrence of the keyword PROP
221 is followed by another keyword or is the last element in the
222 list, the function returns t.
223
224 Currently this function infloops when the list is circular."
225 (let ((tail plist)
226 found
227 result)
228 (while (and
229 (consp tail)
230 (not
231 (eq prop (car tail))))
232 (pop tail))
233 (when (eq prop (pop tail))
234 (setq found t))
235 (while (and (consp tail)
236 (not (keywordp (car tail))))
237 (push (pop tail) result))
238 (or (nreverse result) found)))
239
240 (defun use-package-plist-get (plist prop &optional eval-backquote no-progn)
241 "Compatibility layer between classical and modified plists.
242
243 If `use-package-mplist-get' returns exactly one value, that is
244 returned ; otherwise the list is returned wrapped in a `progn'
245 unless NO-PROGN is non-nil.
246
247 When EVAL-BACKQUOTE is non-nil, the value is first evaluated as
248 if it were backquoted."
249 (let ((values (use-package-mplist-get plist prop)))
250 (when eval-backquote
251 (setq values (eval (list 'backquote values))))
252 (when values
253 (cond ((not (listp values))
254 values)
255 ((eq 1 (length values))
256 (car values))
257 (t (if no-progn
258 values
259 (cons 'progn values)))))))
260
261 (defun use-package-mplist-keys (plist)
262 "Get the keys in PLIST, a modified plist.
263
264 A modified plist is one where properties are keywords and values
265 are all non-keywords elements that follow it."
266 (let ((result))
267 (mapc (lambda (elt)
268 (when (keywordp elt)
269 (push elt result)))
270 plist)
271 (nreverse result)))
272
273 (defun use-package-validate-keywords (args)
274 "Error if any keyword given in ARGS is not recognized.
275 Return the list of recognized keywords."
276 (mapc
277 (function
278 (lambda (keyword)
279 (unless (memq keyword use-package-keywords)
280 (error "Unrecognized keyword: %s" keyword))))
281 (use-package-mplist-keys args)))
282
283 (defmacro use-package (name &rest args)
284 "Use a package with configuration options.
285
286 For full documentation. please see commentary.
287
288 (use-package package-name
289 :keyword option)
290
291 :init Code to run when `use-package' form evals.
292 :bind Perform key bindings, and define autoload for bound
293 commands.
294 :bind* Perform key bindings, and define autoload for bound
295 commands, overriding all minor mode bindings.
296 :bind-keymap Bind key prefix to an auto-loaded keymap that
297 is defined in the package. Like bind but for keymaps
298 instead of commands.
299 :bind-keymap* like bind-keymap, but overrides all minor mode bindings
300 :commands Define autoloads for given commands.
301 :pre-load Code to run when `use-package' form evals and before
302 anything else. Unlike :init this form runs before the
303 package is required or autoloads added.
304 :mode Form to be added to `auto-mode-alist'.
305 :interpreter Form to be added to `interpreter-mode-alist'.
306 :defer Defer loading of package -- automatic
307 if :commands, :bind, :bind*, :mode or :interpreter are used.
308 :demand Prevent deferred loading in all cases.
309 :config Runs if and when package loads.
310 :if Conditional loading.
311 :disabled Ignore everything.
312 :defines Define vars to silence byte-compiler.
313 :load-path Add to `load-path' before loading.
314 :diminish Support for diminish package (if it's installed).
315 :idle adds a form to run on an idle timer
316 :idle-priority schedules the :idle form to run with the given
317 priority (lower priorities run first). Default priority
318 is 5; forms with the same priority are run in the order in
319 which they are evaluated.
320 :ensure loads package using package.el if necessary.
321 :pin pin package to archive."
322 (use-package-validate-keywords args) ; error if any bad keyword, ignore result
323 (let* ((commands (use-package-plist-get args :commands t t))
324 (pre-init-body (use-package-plist-get args :pre-init))
325 (pre-load-body (use-package-plist-get args :pre-load))
326 (init-body (use-package-plist-get args :init))
327 (config-body (use-package-plist-get args :config))
328 (diminish-var (use-package-plist-get args :diminish t))
329 (defines (use-package-plist-get args :defines t t))
330 (idle-body (use-package-plist-get args :idle))
331 (idle-priority (use-package-plist-get args :idle-priority))
332 (keybindings-alist (use-package-plist-get args :bind t t))
333 (overriding-keybindings-alist (use-package-plist-get args :bind* t t))
334 (keymap-alist (use-package-plist-get args :bind-keymap t t))
335 (overriding-keymap-alist (use-package-plist-get args :bind-keymap* t t))
336 (mode (use-package-plist-get args :mode t t))
337 (mode-alist
338 (if (stringp mode) (cons mode name) mode))
339 (interpreter (use-package-plist-get args :interpreter t t))
340 (interpreter-alist
341 (if (stringp interpreter) (cons interpreter name) interpreter))
342 (predicate (use-package-plist-get args :if))
343 (pkg-load-path (use-package-plist-get args :load-path t t))
344 (archive-name (use-package-plist-get args :pin))
345 (defines-eval (if (null defines)
346 nil
347 (if (listp defines)
348 (mapcar (lambda (var) `(defvar ,var)) defines)
349 `((defvar ,defines)))))
350 (requires (use-package-plist-get args :requires t))
351 (requires-test (if (null requires)
352 t
353 (if (listp requires)
354 `(not (member nil (mapcar #'featurep
355 (quote ,requires))))
356 `(featurep (quote ,requires)))))
357 (name-string (if (stringp name) name (symbol-name name)))
358 (name-symbol (if (stringp name) (intern name) name)))
359
360 ;; force this immediately -- one off cost
361 (unless (use-package-plist-get args :disabled)
362
363 (when archive-name
364 (use-package-pin-package name archive-name))
365
366 (let* ((ensure (use-package-plist-get args :ensure))
367 (package-name
368 (or (and (eq ensure t)
369 name)
370 ensure)))
371
372 (when package-name
373 (require 'package)
374 (use-package-ensure-elpa package-name)))
375
376
377 (if diminish-var
378 (setq config-body
379 `(progn
380 ,config-body
381 (ignore-errors
382 ,@(cond
383 ((stringp diminish-var)
384 `((diminish (quote ,(intern (concat name-string "-mode")))
385 ,diminish-var)))
386 ((symbolp diminish-var)
387 `((diminish (quote ,diminish-var))))
388 ((and (consp diminish-var) (stringp (cdr diminish-var)))
389 `((diminish (quote ,(car diminish-var)) ,(cdr diminish-var))))
390 (t ; list of symbols or (symbol . "string") pairs
391 (mapcar (lambda (var)
392 (if (listp var)
393 `(diminish (quote ,(car var)) ,(cdr var))
394 `(diminish (quote ,var))))
395 diminish-var)))))))
396
397 (if (and commands (symbolp commands))
398 (setq commands (list commands)))
399
400
401 (when idle-body
402 (when (null idle-priority)
403 (setq idle-priority 5))
404 (setq init-body
405 `(progn
406 (require 'use-package)
407 (use-package-init-on-idle (lambda () ,idle-body) ,idle-priority)
408 ,init-body)))
409
410 (let ((init-for-commands-or-keymaps
411 (lambda (func sym-or-list &optional keymap)
412 (let ((cons-list (if (and (consp sym-or-list)
413 (stringp (car sym-or-list)))
414 (list sym-or-list)
415 sym-or-list)))
416 (if cons-list
417 (setq init-body
418 `(progn
419 ,init-body
420 ,@(mapcar (lambda (elem)
421 (when (not keymap)
422 (push (cdr elem) commands))
423 (funcall func elem))
424 cons-list))))))))
425
426 (funcall init-for-commands-or-keymaps
427 (lambda (binding)
428 `(bind-key ,(car binding)
429 (lambda () (interactive)
430 (use-package-autoload-keymap
431 (quote ,(cdr binding))
432 ,(if (stringp name) name `',name)
433 nil))))
434 keymap-alist
435 t)
436
437 (funcall init-for-commands-or-keymaps
438 (lambda (binding)
439 `(bind-key ,(car binding)
440 (lambda () (interactive)
441 (use-package-autoload-keymap
442 (quote ,(cdr binding))
443 ,(if (stringp name) name `',name)
444 t))))
445 overriding-keymap-alist
446 t)
447
448 (funcall init-for-commands-or-keymaps
449 (lambda (binding)
450 `(bind-key ,(car binding)
451 (quote ,(cdr binding))))
452 keybindings-alist)
453
454 (funcall init-for-commands-or-keymaps
455 (lambda (binding)
456 `(bind-key* ,(car binding)
457 (quote ,(cdr binding))))
458 overriding-keybindings-alist)
459
460 (funcall init-for-commands-or-keymaps
461 (lambda (mode)
462 `(add-to-list 'auto-mode-alist
463 (quote ,mode)))
464 mode-alist)
465
466 (funcall init-for-commands-or-keymaps
467 (lambda (interpreter)
468 `(add-to-list 'interpreter-mode-alist
469 (quote ,interpreter)))
470 interpreter-alist))
471
472 `(progn
473 ,pre-load-body
474 ,@(mapcar
475 (lambda (path)
476 `(add-to-list 'load-path
477 ,(if (file-name-absolute-p path)
478 path
479 (expand-file-name path user-emacs-directory))))
480 (cond ((stringp pkg-load-path)
481 (list pkg-load-path))
482 ((functionp pkg-load-path)
483 (funcall pkg-load-path))
484 (t
485 pkg-load-path)))
486
487 (eval-when-compile
488 (when (bound-and-true-p byte-compile-current-file)
489 ,@defines-eval
490 (condition-case err
491 ,(if (stringp name)
492 `(load ,name t)
493 `(require ',name nil t))
494 (error (message "Error requiring %s: %s" ',name err) nil))))
495
496 ,(if (and (or commands (use-package-plist-get args :defer)
497 (use-package-plist-get args :bind-keymap)
498 (use-package-plist-get args :bind-keymap*))
499 (not (use-package-plist-get args :demand)))
500 (let (form)
501 (mapc (lambda (command)
502 (push `(unless (fboundp (quote ,command))
503 (autoload (function ,command)
504 ,name-string nil t))
505 form))
506 commands)
507
508 `(when ,(or predicate t)
509 ,pre-init-body
510 ,@form
511 ,init-body
512 ,(unless (null config-body)
513 `(eval-after-load ,(if (stringp name) name `',name)
514 `(,(lambda ()
515 (if ,requires-test
516 (use-package-with-elapsed-timer
517 ,(format "Configuring package %s" name-string)
518 ,config-body))))))
519 t))
520 `(if (and ,(or predicate t)
521 ,requires-test)
522 (use-package-with-elapsed-timer
523 ,(format "Loading package %s" name-string)
524 (if (not ,(if (stringp name)
525 `(load ,name t)
526 `(require ',name nil t)))
527 (message "Could not load package %s" ,name-string)
528 ,pre-init-body
529 ,init-body
530 ,config-body
531 t))))))))
532
533 (defun use-package-autoload-keymap (keymap-symbol package override)
534 "Loads PACKAGE and then binds the key sequence used to invoke this function to
535 KEYMAP-SYMBOL. It then simulates pressing the same key sequence a again, so
536 that the next key pressed is routed to the newly loaded keymap.
537
538 This function supports use-package's :bind-keymap keyword. It works
539 by binding the given key sequence to an invocation of this function for a
540 particular keymap. The keymap is expected to be defined by the package. In
541 this way, loading the package is deferred until the prefix key sequence is
542 pressed."
543 (if (if (stringp package) (load package t) (require package nil t))
544 (if (and (boundp keymap-symbol) (keymapp (symbol-value keymap-symbol)))
545 (let ((key (key-description (this-command-keys-vector)))
546 (keymap (symbol-value keymap-symbol)))
547 (progn
548 (if override
549 `(eval `(bind-key* ,key ,keymap)) ; eval form is necessary to avoid compiler error
550 (bind-key key keymap))
551 (setq unread-command-events
552 (listify-key-sequence (this-command-keys-vector)))))
553 (error
554 "use-package: package %s failed to define keymap %s"
555 package keymap-symbol))
556 (error "Could not load package %s" package)))
557
558 (put 'use-package 'lisp-indent-function 'defun)
559
560 (defconst use-package-font-lock-keywords
561 '(("(\\(use-package\\(?:-with-elapsed-timer\\)?\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
562 (1 font-lock-keyword-face)
563 (2 font-lock-constant-face nil t))))
564
565 (font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
566
567 (provide 'use-package)
568 ;; Local Variables:
569 ;; indent-tabs-mode: nil
570 ;; End:
571 ;;; use-package.el ends here