From 57e38152e143ef9c447c015c09e7f375737f4b8e Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Wed, 8 Mar 2017 20:05:15 -0800 Subject: [PATCH] Get :defer-install completely working, in theory * A quoting error has been fixed in `use-package-handler/:defer'. * `use-package-install-deferred-package' has been updated to return t if the package was actually installed, and nil otherwise. * The fake autoloads generated during deferred installation are doctored so Emacs does not think they were defined in the user's init-file. * The docstrings of the fake autoloads have been improved. * Arguments and interactivity are now correctly passed to the autoloaded function. * The autoload now skips requiring the feature and calling the original function if the user declines to install the package. This prevents unprofessional errors. --- lisp/use-package/use-package.el | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el index 8902b406712..94f5229eca8 100644 --- a/lisp/use-package/use-package.el +++ b/lisp/use-package/use-package.el @@ -594,7 +594,7 @@ the value of `:ensure'. The values are unevaluated Lisp forms. ") "Install a package whose installation has been deferred. NAME should be a symbol naming a package (actually, a feature). The user is prompted for confirmation first, unless NO-PROMPT is -non-nil." +non-nil. Return t if the package is installed, nil otherwise." (interactive (let ((packages nil)) (maphash (lambda (package info) @@ -612,7 +612,8 @@ non-nil." (when (or no-prompt (y-or-n-p (format "Install package %S? " name))) (eval (gethash name use-package--deferred-packages)) - (remhash name use-package--deferred-packages))) + (remhash name use-package--deferred-packages) + t)) (defalias 'use-package-normalize/:defer-install 'use-package-normalize-test) @@ -1067,15 +1068,30 @@ deferred until the prefix key sequence is pressed." (defun use-package--autoload-with-deferred-install (command package-name) "Return a form defining an autoload supporting deferred install." - `(defun ,command (&rest args) - (if (bound-and-true-p use-package--recursive-autoload) - (use-package-error - (format "Autoloading failed to define function %S" - command)) - (use-package-install-deferred-package ',package-name) - (require ',package-name) - (let ((use-package--recursive-autoload t)) - (funcall ',command args))))) + `(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) + (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 @@ -1103,7 +1119,7 @@ deferred until the prefix key sequence is pressed." ;; information. ,(if (eq (plist-get state :defer-install) :ensure) (use-package--autoload-with-deferred-install - ',command ',name) + command name) `(autoload #',command ,name-string nil t)))) (when (bound-and-true-p byte-compile-current-file) `((eval-when-compile -- 2.39.2