diff --git a/etc/USE-PACKAGE-NEWS b/etc/USE-PACKAGE-NEWS index de9de0e977d..3bdd623adeb 100644 --- a/etc/USE-PACKAGE-NEWS +++ b/etc/USE-PACKAGE-NEWS @@ -52,6 +52,12 @@ - New `:hook` keyword. +- New `:catch` keyword. If `t` or `nil`, it enables (the default, see + `use-package-defaults`) or disables catching errors at load time in + use-package expansions. It can also be a function taking two arguments: the + keyword being processed at the time the error was encountered, and the error + object (as generated by `condition-case`). + - New keywords `:custom (foo1 bar1) (foo2 bar2)` etc., and `:custom-face`. - New `:magic` and `:magic-fallback` keywords. @@ -60,6 +66,8 @@ - New customization variable `use-package-enable-imenu-support`. +- New customization variable `use-package-hook-name-suffix`. + - Allow `:diminish` to take no arguments. - Support multiple symbols passed to `:after`, and a mini-DSL using `:all` and diff --git a/lisp/use-package/bind-chord.el b/lisp/use-package/bind-chord.el new file mode 100644 index 00000000000..e5184bff60e --- /dev/null +++ b/lisp/use-package/bind-chord.el @@ -0,0 +1,62 @@ +;;; bind-chord.el --- key-chord binding helper for use-package-chords + +;; Copyright (C) 2015-2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-chords +;; Version: 0.2 +;; Package-Requires: ((bind-key "1.0") (key-chord "0.6")) +;; Filename: bind-chord.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; + +;;; Code: + +(require 'bind-key) +(require 'key-chord nil t) + +;;;###autoload +(defmacro bind-chord (chord command &optional keymap) + "Bind CHORD to COMMAND in KEYMAP (`global-map' if not passed)." + (let ((key1 (logand 255 (aref chord 0))) + (key2 (logand 255 (aref chord 1)))) + (if (eq key1 key2) + `(bind-key (vector 'key-chord ,key1 ,key2) ,command ,keymap) + `(progn + (bind-key (vector 'key-chord ,key1 ,key2) ,command ,keymap) + (bind-key (vector 'key-chord ,key2 ,key1) ,command ,keymap))))) + +;;;###autoload +(defmacro bind-chords (&rest args) + "Bind multiple chords at once. + +Accepts keyword argument: +:map - a keymap into which the keybindings should be added + +The rest of the arguments are conses of keybinding string and a +function symbol (unquoted)." + (let* ((map (plist-get args :map)) + (maps (if (listp map) map (list map))) + (key-bindings (progn + (while (keywordp (car args)) + (pop args) + (pop args)) + args))) + (macroexp-progn + (apply + #'nconc + (mapcar (lambda (form) + (if maps + (mapcar + #'(lambda (m) + `(bind-chord ,(car form) ',(cdr form) ,m)) maps) + `((bind-chord ,(car form) ',(cdr form))))) + key-bindings))))) + +(provide 'bind-chord) + +;;; bind-chord.el ends here diff --git a/lisp/use-package/use-package-chords.el b/lisp/use-package/use-package-chords.el new file mode 100644 index 00000000000..023a9c6b2ad --- /dev/null +++ b/lisp/use-package/use-package-chords.el @@ -0,0 +1,49 @@ +;;; use-package-chords.el --- key-chord keyword for use-package + +;; Copyright (C) 2015-2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-chords +;; Version: 0.2 +;; Package-Requires: ((use-package "2.1") (bind-key "1.0") (bind-chord "0.2") (key-chord "0.6")) +;; Filename: use-package-chords.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; +;; The `:chords' keyword allows you to define `key-chord' bindings for +;; `use-package' declarations in the same manner as the `:bind' +;; keyword. +;; + +;;; Code: + +(require 'use-package) +(require 'bind-chord) + +(defalias 'use-package-normalize/:chords 'use-package-normalize-binder) + +(defun use-package-handler/:chords (name keyword arg rest state) + "Handler for `:chords' keyword in `use-package'." + (let* ((commands (remq nil (mapcar #'(lambda (arg) + (if (listp arg) + (cdr arg) + nil)) arg))) + (chord-binder + (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 + ,(macroexpand + `(bind-chords :package ,name ,@arg))))))) + (use-package-handler/:preface name keyword chord-binder rest state))) + +(add-to-list 'use-package-keywords :chords t) + +(provide 'use-package-chords) + +;;; use-package-chords.el ends here diff --git a/lisp/use-package/use-package-ensure-system-package.el b/lisp/use-package/use-package-ensure-system-package.el new file mode 100644 index 00000000000..36a614d47c3 --- /dev/null +++ b/lisp/use-package/use-package-ensure-system-package.el @@ -0,0 +1,76 @@ +;;; use-package-ensure-system-package.el --- auto install system packages + +;; Copyright (C) 2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-ensure-system-package +;; Version: 0.1 +;; Package-Requires: ((use-package "2.1") (system-packages "0.1")) +;; Filename: use-package-ensure-system-package.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; +;; The `:ensure-system-package` keyword allows you to ensure system +;; binaries exist alongside your `use-package` declarations. +;; + +;;; Code: + +(require 'use-package) +(require 'system-packages nil t) + +(eval-when-compile + (defvar system-packages-packagemanager) + (defvar system-packages-supported-package-managers) + (defvar system-packages-usesudo)) + +(defun use-package-ensure-system-package-install-command (pack) + "Return the default install command for `pack'." + (let ((command + (cdr (assoc 'install (cdr (assoc system-packages-packagemanager + system-packages-supported-package-managers)))))) + (unless command + (error (format "%S not supported in %S" 'install system-packages-packagemanager))) + (unless (listp command) + (setq command (list command))) + (when system-packages-usesudo + (setq command (mapcar (lambda (part) (concat "sudo " part)) command))) + (setq command (mapconcat 'identity command " && ")) + (mapconcat 'identity (list command pack) " "))) + +(defun use-package-ensure-system-package-consify (arg) + "Turn `arg' into a cons of (`package-name' . `install-command')." + (cond + ((stringp arg) + (cons arg (use-package-ensure-system-package-install-command arg))) + ((symbolp arg) + (cons arg (use-package-ensure-system-package-install-command (symbol-name arg)))) + ((consp arg) arg))) + +(defun use-package-normalize/:ensure-system-package (name-symbol keyword args) + "Turn `arg' into a list of cons-es of (`package-name' . `install-command')." + (use-package-only-one (symbol-name keyword) args + (lambda (label arg) + (cond + ((and (listp arg) (listp (cdr arg))) + (mapcar #'use-package-ensure-system-package-consify arg)) + (t + (list (use-package-ensure-system-package-consify arg))))))) + +(defun use-package-handler/:ensure-system-package (name keyword arg rest state) + "Execute the handler for `:ensure-system-package' keyword in `use-package'." + (let ((body (use-package-process-keywords name rest state))) + (use-package-concat + (mapcar #'(lambda (cons) + `(unless (executable-find (symbol-name ',(car cons))) + (async-shell-command ,(cdr cons)))) arg) + body))) + +(add-to-list 'use-package-keywords :ensure-system-package t) + +(provide 'use-package-ensure-system-package) + +;;; use-package-ensure-system-package.el ends here diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el index ec459ab1662..c6ab7d742c6 100644 --- a/lisp/use-package/use-package.el +++ b/lisp/use-package/use-package.el @@ -45,6 +45,7 @@ (require 'up-diminish) (require 'up-delight) +(declare-function use-package-jump-to-package-form "up-jump") (autoload #'use-package-jump-to-package-form "up-jump" nil t) (provide 'use-package) diff --git a/up-core.el b/up-core.el index b78c619c003..fbaa862b066 100644 --- a/up-core.el +++ b/up-core.el @@ -63,6 +63,7 @@ :defines :functions :preface + :catch :after :custom :custom-face @@ -148,6 +149,8 @@ See also `use-package-defaults', which uses this value." '(;; this '(t) has special meaning; see `use-package-handler/:config' (:config '(t) t) (:init nil t) + (:catch t (lambda (args) + (not use-package-expand-minimally))) (:defer use-package-always-defer (lambda (args) (and use-package-always-defer @@ -177,6 +180,13 @@ be attempted." (choice :tag "Enable if non-nil" sexp function))) :group 'use-package) +(defcustom use-package-hook-name-suffix "-hook" + "Text append to the name of hooks mentioned by :hook. +Set to `nil' if you don't want this to happen; it's only a +convenience." + :type '(choice string (const :tag "No suffix" nil)) + :group 'use-package) + (defcustom use-package-minimum-reported-time 0.1 "Minimal load time that will be reported. Note that `use-package-verbose' has to be set to a non-nil value @@ -262,8 +272,6 @@ Must be set before loading use-package." (font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords) -(defvar use-package--hush-function) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Utility functions @@ -851,7 +859,7 @@ deferred until the prefix key sequence is pressed." (setq unread-command-events (listify-key-sequence kv))) (use-package-error - (format "use-package: package.el %s failed to define keymap %s" + (format "package.el %s failed to define keymap %s" package keymap-symbol))))) (defun use-package-normalize-mode (name keyword args) @@ -929,17 +937,6 @@ deferred until the prefix key sequence is pressed." (defun use-package-handler/:no-require (name keyword arg rest state) (use-package-process-keywords name rest state)) -;;;; :preface - -(defalias 'use-package-normalize/:preface 'use-package-normalize-forms) - -(defun use-package-handler/:preface (name keyword arg rest state) - (let ((body (use-package-process-keywords name rest state))) - (use-package-concat - (when arg - `((eval-and-compile ,@arg))) - body))) - ;;;; :defines (defalias 'use-package-normalize/:defines 'use-package-normalize-symlist) @@ -954,6 +951,67 @@ deferred until the prefix key sequence is pressed." (defun use-package-handler/:functions (name keyword arg rest state) (use-package-process-keywords name rest state)) +;;;; :preface + +(defalias 'use-package-normalize/:preface 'use-package-normalize-forms) + +(defun use-package-handler/:preface (name keyword arg rest state) + (let ((body (use-package-process-keywords name rest state))) + (use-package-concat + (when arg + `((eval-and-compile ,@arg))) + body))) + +;;;; :catch + +(defvar use-package--form) +(defvar use-package--hush-function #'(lambda (keyword body) body)) + +(defsubst use-package-hush (context keyword body) + `((condition-case-unless-debug err + ,(macroexp-progn body) + (error (funcall ,context ,keyword err))))) + +(defun use-package-normalize/:catch (name keyword args) + (if (null args) + t + (use-package-only-one (symbol-name keyword) args + use-package--hush-function))) + +(defun use-package-handler/:catch (name keyword arg rest state) + (let* ((context (gensym "use-package--warning"))) + (cond + ((not arg) + (use-package-process-keywords name rest state)) + ((eq arg t) + `((let ((,context + #'(lambda (keyword err) + (let ((msg (format "%s/%s: %s" ',name keyword + (error-message-string err)))) + ,(when (eq use-package-verbose 'debug) + `(progn + (with-current-buffer + (get-buffer-create "*use-package*") + (goto-char (point-max)) + (insert "-----\n" msg ,use-package--form) + (emacs-lisp-mode)) + (setq msg + (concat msg + " (see the *use-package* buffer)")))) + (ignore (display-warning 'use-package msg :error)))))) + ,@(let ((use-package--hush-function + (apply-partially #'use-package-hush context))) + (funcall use-package--hush-function keyword + (use-package-process-keywords name rest state)))))) + ((functionp arg) + `((let ((,context ,arg)) + ,@(let ((use-package--hush-function + (apply-partially #'use-package-hush context))) + (funcall use-package--hush-function keyword + (use-package-process-keywords name rest state)))))) + (t + (use-package-error "The :catch keyword expects 't' or a function"))))) + ;;;; :bind, :bind* (defalias 'use-package-normalize/:bind 'use-package-normalize-binder) @@ -1085,8 +1143,11 @@ deferred until the prefix key sequence is pressed." (when fun (mapcar #'(lambda (sym) - `(add-hook (quote ,(intern (format "%s-hook" sym))) - (function ,fun))) + `(add-hook + (quote ,(intern + (concat (symbol-name sym) + use-package-hook-name-suffix))) + (function ,fun))) (if (use-package-non-nil-symbolp syms) (list syms) syms))))) nargs)))))) @@ -1096,20 +1157,20 @@ deferred until the prefix key sequence is pressed." (defun use-package-handler/:commands (name keyword arg rest state) (use-package-concat - (unless (plist-get state :demand) - ;; Since we deferring load, establish any necessary autoloads, and also - ;; keep the byte-compiler happy. - (let ((name-string (use-package-as-string name))) - (cl-mapcan - #'(lambda (command) - (when (symbolp command) - (append + ;; Since we deferring load, establish any necessary autoloads, and also + ;; keep the byte-compiler happy. + (let ((name-string (use-package-as-string name))) + (cl-mapcan + #'(lambda (command) + (when (symbolp command) + (append + (unless (plist-get state :demand) `((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 arg)))) + (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 arg))) (use-package-process-keywords name rest state))) ;;;; :defer @@ -1253,7 +1314,7 @@ no keyword implies `:all'." (use-package-hook-injector (use-package-as-string name) :init arg))) (when init-body - (funcall use-package--hush-function + (funcall use-package--hush-function :init (if use-package-check-before-init `((when (locate-library ,(use-package-as-string name)) ,@init-body)) @@ -1285,7 +1346,7 @@ no keyword implies `:all'." body (use-package-with-elapsed-timer (format "Configuring package %s" name-symbol) - (funcall use-package--hush-function + (funcall use-package--hush-function :config (use-package-concat (use-package-hook-injector (symbol-name name-symbol) :config arg) @@ -1297,52 +1358,24 @@ no keyword implies `:all'." ;;; The main macro ;; -(defsubst use-package-hush (context body) - `((condition-case-unless-debug err - ,(macroexp-progn body) - (error (funcall ,context err))))) - -(defun use-package-core (name args) - (let* ((context (gensym "use-package--warning")) - (args* (use-package-normalize-keywords name args)) - (use-package--hush-function #'identity)) - (if use-package-expand-minimally - (use-package-process-keywords name args* - (and (plist-get args* :demand) - (list :demand t))) - `((let - ((,context - #'(lambda (err) - (let ((msg (format "%s: %s" ',name (error-message-string err)))) - ,(when (eq use-package-verbose 'debug) - `(progn - (with-current-buffer (get-buffer-create "*use-package*") - (goto-char (point-max)) - (insert - "-----\n" msg - ,(concat - "\n\n" - (pp-to-string `(use-package ,name ,@args)) - "\n -->\n\n" - (pp-to-string `(use-package ,name ,@args*)) - "\n ==>\n\n" - (pp-to-string - (macroexp-progn - (let ((use-package-verbose 'errors) - (use-package-expand-minimally t)) - (use-package-process-keywords name args* - (and (plist-get args* :demand) - (list :demand t)))))))) - (emacs-lisp-mode)) - (setq msg (concat msg " (see the *use-package* buffer)")))) - (ignore (display-warning 'use-package msg :error)))))) - ,(let ((use-package--hush-function - (apply-partially #'use-package-hush context))) - (macroexp-progn - (funcall use-package--hush-function +(defmacro use-package-core (name args) + `(let* ((args* (use-package-normalize-keywords ,name ,args)) + (use-package--form + (concat "\n\n" + (pp-to-string `(use-package ,name ,@,args)) + "\n -->\n\n" + (pp-to-string `(use-package ,name ,@args*)) + "\n ==>\n\n" + (pp-to-string + (macroexp-progn + (let ((use-package-verbose 'errors) + (use-package-expand-minimally t)) (use-package-process-keywords name args* (and (plist-get args* :demand) - (list :demand t))))))))))) + (list :demand t))))))))) + (use-package-process-keywords name args* + (and (plist-get args* :demand) + (list :demand t))))) ;;;###autoload (defmacro use-package (name &rest args) diff --git a/up-ensure.el b/up-ensure.el index fa19e1d5a8e..30f2190e922 100644 --- a/up-ensure.el +++ b/up-ensure.el @@ -33,6 +33,7 @@ ;;; Code: +(require 'cl-lib) (require 'up-core) (defgroup use-package-ensure nil @@ -58,9 +59,9 @@ See also `use-package-defaults', which uses this value." (defcustom use-package-ensure-function 'use-package-ensure-elpa "Function that ensures a package is installed. This function is called with three arguments: the name of the -package declared in the `use-package' form; the argument passed -to `:ensure'; and the current `state' plist created by previous -handlers. +package declared in the `use-package' form; the arguments passed +to all `:ensure' keywords (always a list, even if only one); and +the current `state' plist created by previous handlers. 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 @@ -136,38 +137,43 @@ manually updated package." t (use-package-only-one (symbol-name keyword) args #'(lambda (label arg) - (if (symbolp arg) - arg + (cond + ((symbolp arg) + (list arg)) + ((and (listp arg) (cl-every #'symbolp arg)) + arg) + (t (use-package-error (concat ":ensure wants an optional package name " - "(an unquoted symbol name)"))))))) + "(an unquoted symbol name)")))))))) -(defun use-package-ensure-elpa (name ensure state &optional no-refresh) - (let ((package - (or (and (eq ensure t) (use-package-as-symbol name)) - ensure))) - (when package - (require 'package) - (unless (package-installed-p package) - (condition-case-unless-debug err - (progn - (when (assoc package (bound-and-true-p - package-pinned-packages)) - (package-read-all-archive-contents)) - (if (assoc package package-archive-contents) - (package-install package) - (package-refresh-contents) +(defun use-package-ensure-elpa (name args state &optional no-refresh) + (dolist (ensure args) + (let ((package + (or (and (eq ensure t) (use-package-as-symbol name)) + ensure))) + (when package + (require 'package) + (unless (package-installed-p package) + (condition-case-unless-debug err + (progn (when (assoc package (bound-and-true-p package-pinned-packages)) (package-read-all-archive-contents)) - (package-install package)) - t) - (error - (ignore - (display-warning 'use-package - (format "Failed to install %s: %s" - name (error-message-string err)) - :error)))))))) + (if (assoc package package-archive-contents) + (package-install package) + (package-refresh-contents) + (when (assoc package (bound-and-true-p + package-pinned-packages)) + (package-read-all-archive-contents)) + (package-install package)) + t) + (error + (ignore + (display-warning 'use-package + (format "Failed to install %s: %s" + name (error-message-string err)) + :error))))))))) (defun use-package-handler/:ensure (name keyword ensure rest state) (let* ((body (use-package-process-keywords name rest state))) @@ -184,7 +190,7 @@ manually updated package." body)) (add-to-list 'use-package-defaults - '(:ensure use-package-always-ensure + '(:ensure (list use-package-always-ensure) (lambda (args) (and use-package-always-ensure (not (plist-member args :load-path))))) t) diff --git a/up-tests.el b/up-tests.el index 33b43654313..bb22b344479 100644 --- a/up-tests.el +++ b/up-tests.el @@ -22,6 +22,7 @@ ;;; Code: +(require 'cl) (require 'ert) (require 'use-package) @@ -61,6 +62,11 @@ (use-package-expand-minimally t)) (macroexpand-1 ',form))) +(defmacro expand-maximally (form) + `(let ((use-package-verbose 'debug) + (use-package-expand-minimally nil)) + (macroexpand-1 ',form))) + (defmacro match-expansion (form &rest value) `(should (pcase (expand-minimally ,form) ,@(mapcar #'(lambda (x) (list x t)) value)))) @@ -214,9 +220,9 @@ (flet ((norm (&rest args) (apply #'use-package-normalize/:ensure 'foopkg :ensure args))) - (should (equal (norm '(t)) t)) - (should (equal (norm '(nil)) nil)) - (should (equal (norm '(sym)) 'sym)) + (should (equal (norm '(t)) '(t))) + (should (equal (norm '(nil)) '(nil))) + (should (equal (norm '(sym)) '(sym))) (should-error (norm '(1))) (should-error (norm '("Hello"))))) @@ -225,7 +231,7 @@ (match-expansion (use-package foo :ensure t) `(progn - (use-package-ensure-elpa 'foo 't 'nil) + (use-package-ensure-elpa 'foo '(t) 'nil) (require 'foo nil nil))))) (ert-deftest use-package-test/:ensure-2 () @@ -233,7 +239,7 @@ (match-expansion (use-package foo :ensure t) `(progn - (use-package-ensure-elpa 'foo 't 'nil) + (use-package-ensure-elpa 'foo '(t) 'nil) (require 'foo nil nil))))) (ert-deftest use-package-test/:ensure-3 () @@ -241,7 +247,7 @@ (match-expansion (use-package foo :ensure nil) `(progn - (use-package-ensure-elpa 'foo 'nil 'nil) + (use-package-ensure-elpa 'foo '(nil) 'nil) (require 'foo nil nil))))) (ert-deftest use-package-test/:ensure-4 () @@ -249,7 +255,7 @@ (match-expansion (use-package foo :ensure nil) `(progn - (use-package-ensure-elpa 'foo 'nil 'nil) + (use-package-ensure-elpa 'foo '(nil) 'nil) (require 'foo nil nil))))) (ert-deftest use-package-test/:ensure-5 () @@ -275,7 +281,7 @@ (match-expansion (use-package foo :ensure nil :load-path "foo") `(progn - (use-package-ensure-elpa 'foo 'nil 'nil) + (use-package-ensure-elpa 'foo '(nil) 'nil) (eval-and-compile (add-to-list 'load-path ,(pred stringp))) (require 'foo nil nil))))) @@ -285,7 +291,7 @@ (match-expansion (use-package foo :ensure nil :load-path "foo") `(progn - (use-package-ensure-elpa 'foo 'nil 'nil) + (use-package-ensure-elpa 'foo '(nil) 'nil) (eval-and-compile (add-to-list 'load-path ,(pred stringp))) (require 'foo nil nil))))) @@ -295,7 +301,7 @@ (match-expansion (use-package foo :ensure t :load-path "foo") `(progn - (use-package-ensure-elpa 'foo 't 'nil) + (use-package-ensure-elpa 'foo '(t) 'nil) (eval-and-compile (add-to-list 'load-path ,(pred stringp))) (require 'foo nil nil))))) @@ -305,7 +311,7 @@ (match-expansion (use-package foo :ensure t :load-path "foo") `(progn - (use-package-ensure-elpa 'foo 't 'nil) + (use-package-ensure-elpa 'foo '(t) 'nil) (eval-and-compile (add-to-list 'load-path ,(pred stringp))) (require 'foo nil nil))))) @@ -320,6 +326,30 @@ (use-package foo :ensure t) (should (eq tried-to-install 'foo))))) +(ert-deftest use-package-test/:ensure-12 () + (let ((use-package-always-ensure t)) + (match-expansion + (use-package foo :ensure bar) + `(progn + (use-package-ensure-elpa 'foo '(bar) 'nil) + (require 'foo nil nil))))) + +(ert-deftest use-package-test/:ensure-13 () + (let ((use-package-always-ensure t)) + (match-expansion + (use-package foo :ensure bar :ensure quux) + `(progn + (use-package-ensure-elpa 'foo '(bar quux) 'nil) + (require 'foo nil nil))))) + +(ert-deftest use-package-test/:ensure-14 () + (let ((use-package-always-ensure t)) + (match-expansion + (use-package foo :ensure bar :ensure (quux bow)) + `(progn + (use-package-ensure-elpa 'foo '(bar quux bow) 'nil) + (require 'foo nil nil))))) + (ert-deftest use-package-test/:if-1 () (match-expansion (use-package foo :if t) @@ -671,6 +701,52 @@ (autoload #'bar "foo" nil t)) (bar)))) +(ert-deftest use-package-test/:commands-5 () + (match-expansion + (use-package gnus-harvest + :load-path "lisp/gnus-harvest" + :commands gnus-harvest-install + :demand t + :config + (if (featurep 'message-x) + (gnus-harvest-install 'message-x) + (gnus-harvest-install))) + `(progn + (eval-and-compile + (add-to-list 'load-path "/Users/johnw/.emacs.d/lisp/gnus-harvest")) + (require 'gnus-harvest nil nil) + (if (featurep 'message-x) + (gnus-harvest-install 'message-x) + (gnus-harvest-install)) + t))) + +(ert-deftest use-package-test/:commands-6 () + (let ((byte-compile-current-file t)) + (match-expansion + (use-package gnus-harvest + :load-path "lisp/gnus-harvest" + :commands gnus-harvest-install + :demand t + :config + (if (featurep 'message-x) + (gnus-harvest-install 'message-x) + (gnus-harvest-install))) + `(progn + (eval-and-compile + (add-to-list 'load-path "/Users/johnw/.emacs.d/lisp/gnus-harvest")) + (eval-and-compile + (eval-when-compile + (with-demoted-errors "Cannot load gnus-harvest: %S" nil + (load "gnus-harvest" nil t)))) + (eval-when-compile + (declare-function gnus-harvest-install "gnus-harvest")) + (require 'gnus-harvest nil nil) + (if + (featurep 'message-x) + (gnus-harvest-install 'message-x) + (gnus-harvest-install)) + t)))) + (ert-deftest use-package-test/:defines-1 () (match-expansion (use-package foo :defines bar) @@ -815,6 +891,38 @@ (ignore (bind-keys :package foo ("C-a" . key)))))))) +(ert-deftest use-package-test/:hook-2 () + (match-expansion + (use-package foo + :hook (hook . fun)) + `(progn + (unless (fboundp 'fun) + (autoload #'fun "foo" nil t)) + (ignore + (add-hook 'hook-hook #'fun))))) + +(ert-deftest use-package-test/:hook-3 () + (let ((use-package-hook-name-suffix nil)) + (match-expansion + (use-package foo + :hook (hook . fun)) + `(progn + (unless (fboundp 'fun) + (autoload #'fun "foo" nil t)) + (ignore + (add-hook 'hook #'fun)))))) + +(ert-deftest use-package-test/:hook-4 () + (let ((use-package-hook-name-suffix "-special")) + (match-expansion + (use-package foo + :hook (hook . fun)) + `(progn + (unless (fboundp 'fun) + (autoload #'fun "foo" nil t)) + (ignore + (add-hook 'hook-special #'fun)))))) + (ert-deftest use-package-test-normalize/:custom () (flet ((norm (&rest args) (apply #'use-package-normalize/:custom @@ -861,6 +969,35 @@ (init) (require 'foo nil nil))))) +(ert-deftest use-package-test/:catch-1 () + (match-expansion + (use-package foo :catch t) + `(let + ((,_ #'(lambda (keyword err) + (let ((msg (format "%s/%s: %s" 'foo keyword + (error-message-string err)))) + nil + (ignore (display-warning 'use-package msg :error)))))) + (condition-case-unless-debug err + (require 'foo nil nil) + (error + (funcall ,_ :catch err)))))) + +(ert-deftest use-package-test/:catch-2 () + (match-expansion + (use-package foo :catch nil) + `(require 'foo nil nil))) + +(ert-deftest use-package-test/:catch-3 () + (match-expansion + (use-package foo :catch (lambda (keyword error))) + `(let + ((,_ (lambda (keyword error)))) + (condition-case-unless-debug err + (require 'foo nil nil) + (error + (funcall ,_ :catch err)))))) + (ert-deftest use-package-test/:after-1 () (match-expansion (use-package foo :after bar) @@ -1219,6 +1356,38 @@ (if (fboundp 'delight) (delight '((foo "bar" foo))))))) +(ert-deftest use-package-test/506 () + (match-expansion + (use-package ess-site + :ensure ess + :pin melpa-stable) + `(progn + (use-package-pin-package 'ess-site "melpa-stable") + (use-package-ensure-elpa 'ess-site + '(ess) + 'nil) + (require 'ess-site nil nil)))) + +(ert-deftest use-package-test/538 () + (match-expansion + (use-package mu4e + :commands (mu4e) + :bind (("" . mu4e)) + :init + :config + (config)) + `(progn + (unless + (fboundp 'mu4e) + (autoload #'mu4e "mu4e" nil t)) + (eval-after-load 'mu4e + '(progn + (config) + t)) + (ignore + (bind-keys :package mu4e + ("" . mu4e)))))) + ;; Local Variables: ;; indent-tabs-mode: nil ;; no-byte-compile: t