progfolio / elpaca

An elisp package manager
GNU General Public License v3.0
634 stars 31 forks source link

[Feature]: elpaca-wait keyword for use-package #261

Closed montchr closed 5 months ago

montchr commented 7 months ago

Feature Description

In addition to the existing usage of elpaca-wait by calling it at the top-level of init files, provide a new use-package keyword to include the call at the end of the macro expansion.

Also, maybe: a new user option to always include an elpaca-wait call when the use-package declaration would not result in a deferred load (e.g. when :demand t is specified). I could see this as being potentially counter-intuitive, however, especially when use-package-always-defer is nil.

Usage

(use-package no-littering
  :ensure t
  :demand t
  :elpaca-wait t
  :init
  (setq no-littering-etc-directory my-etc-dir)
  (setq no-littering-var-directory my-var-dir))

Expansion

(elpaca no-littering
  (setq no-littering-etc-directory my-etc-dir)
  (setq no-littering-var-directory my-var-dir)
  (require 'no-littering nil nil))
(elpaca-wait)

Confirmation

progfolio commented 7 months ago

Thanks for the suggestions.

provide a new use-package keyword to include the call at the end of the macro expansion.

It would be more flexible to introduce a recipe keyword which will run elpaca-wait immediately after the package is queued. This way it can be used with, or without, use-package. e.g.

(use-package test :ensure (:wait t))

;; Expansion is "vanilla" syntax:
;; (elpaca (test :wait t))

See the output of the following two tests:

Master Branch [How to run this test?](https://github.com/progfolio/elpaca/wiki/Troubleshooting#the-elpaca-test-macro) ```emacs-lisp (elpaca-test :early-init (setq elpaca-menu-functions '(elpaca-menu-extensions elpaca-menu-melpa)) :init (elpaca (elpaca-use-package :wait t) (elpaca-use-package-mode)) (message "first") (use-package doct :ensure (:wait t) :config (message "second")) (message "third")) ```
Host Env
elpacae8552ec HEAD -> feat/wait-recipe-keyword, origin/feat/wait-recipe-keyword
installer0.6
emacsGNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0) of 2024-02-03
gitgit version 2.43.0
Output ```emacs-lisp Elpaca menu item cache discarded due to version change. INFO Scraping files for loaddefs... INFO Scraping files for loaddefs...done GEN ../elpaca-autoloads.el Cloning into '/tmp/elpaca.vxSrzk/elpaca/repos/elpaca'... Your branch is up to date with 'origin/master'. Checking /tmp/elpaca.vxSrzk/elpaca/repos/elpaca... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-info.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-log.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-manager.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-menu-elpa.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-menu-melpa.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-menu-org.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-process.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-test.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca-ui.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/elpaca.el... Checking /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/doc... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/doc/early-init.el... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/doc/init.el... Checking /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/extensions... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/extensions/elpaca-use-package.el... Checking /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/images... Checking /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/test... Compiling /tmp/elpaca.vxSrzk/elpaca/repos/elpaca/test/elpaca-test.el... Done (Total of 11 files compiled, 3 skipped in 4 directories) Downloading MELPA recipes... Downloading MELPA recipes...100% first Debugger entered--Lisp error: (error "use-package: :ensure wants an optional package name (an unquoted symbol name), or ( :pin )") error("use-package: %s" ":ensure wants an optional package name (an unquoted symbol name), or ( :pin )") #(":ensure" (:wait t)) use-package-only-one(":ensure" ((:wait t)) #) use-package-normalize/:ensure(doct :ensure ((:wait t))) use-package-normalize-plist(doct (:ensure (:wait t) :config (message "second")) nil use-package-merge-keys) use-package-normalize-keywords(doct (:ensure (:wait t) :config (message "second"))) #f(compiled-function (name &rest args) "Declare an Emacs package by specifying a group of configuration options.\n\nFor the full documentation, see Info node `(use-package) top'.\nUsage:\n\n (use-package package-name\n [:keyword [option]]...)\n\n:init Code to run before PACKAGE-NAME has been loaded.\n:config Code to run after PACKAGE-NAME has been loaded. Note that\n if loading is deferred for any reason, this code does not\n execute until the lazy load has occurred.\n:preface Code to be run before everything except `:disabled'; this\n can be used to define functions for use in `:if', or that\n should be seen by the byte-compiler.\n\n:mode Form to be added to `auto-mode-alist'.\n:magic Form to be added to `magic-mode-alist'.\n:magic-fallback Form to be added to `magic-fallback-mode-alist'.\n:interpreter Form to be added to `interpreter-mode-alist'.\n\n:commands Define autoloads for commands that will be defined by the\n package. This is useful if the package is being lazily\n loaded, and you wish to conditionally call functions in your\n `:init' block that are defined in the package.\n:autoload Similar to :commands, but it for no-interactive one.\n:hook Specify hook(s) to attach this package to.\n\n:bind Bind keys, and define autoloads for the bound commands.\n:bind* Bind keys, and define autoloads for the bound commands,\n *overriding all minor mode bindings*.\n:bind-keymap Bind a key prefix to an auto-loaded keymap defined in the\n package. This is like `:bind', but for keymaps.\n:bind-keymap* Like `:bind-keymap', but overrides all minor mode bindings\n\n:defer Defer loading of a package -- this is implied when using\n `:commands', `:bind', `:bind*', `:mode', `:magic', `:hook',\n `:magic-fallback', or `:interpreter'. This can be an integer,\n to force loading after N seconds of idle time, if the package\n has not already been loaded.\n:demand Prevent the automatic deferred loading introduced by constructs\n such as `:bind' (see `:defer' for the complete list).\n\n:after Delay the effect of the use-package declaration\n until after the named libraries have loaded.\n Before they have been loaded, no other keyword\n has any effect at all, and once they have been\n loaded it is as if `:after' was not specified.\n\n:if EXPR Initialize and load only if EXPR evaluates to a non-nil value.\n:disabled The package is ignored completely if this keyword is present.\n:defines Declare certain variables to silence the byte-compiler.\n:functions Declare certain functions to silence the byte-compiler.\n:load-path Add to the `load-path' before attempting to load the package.\n:diminish Support for diminish.el (if installed).\n:delight Support for delight.el (if installed).\n:custom Call `Custom-set' or `set-default' with each variable\n definition without modifying the Emacs `custom-file'.\n (compare with `custom-set-variables').\n:custom-face Call `custom-set-faces' with each face definition.\n:ensure Loads the package using package.el if necessary.\n:pin Pin the package to an archive.\n:vc Install the package directly from a version control system\n (using `package-vc.el')." #)(doct :ensure (:wait t) :config (message "second")) macroexpand((use-package doct :ensure (:wait t) :config (message "second"))) internal-macroexpand-for-load((use-package doct :ensure (:wait t) :config (message "second")) nil) load-with-code-conversion("/tmp/elpaca.vxSrzk/init.el" "/tmp/elpaca.vxSrzk/init.el" nil t) command-line-1(("--eval" "(setq debug-on-error t after-init-time nil)" "--eval" "(setq user-emacs-directory \"/tmp/elpaca.vxSrzk\")" "-l" "./early-init.el" "--eval" "(run-hooks 'before-init-hook)" "-l" "./init.el" "--eval" "(setq after-init-time (current-time))" "--eval" "(run-hooks 'after-init-hook)" "--eval" "(run-hooks 'emacs-startup-hook)" "--eval" "(message \"\n Test Env\n\")" "--eval" "(elpaca-version 'message)")) command-line() normal-top-level() ```
Feature Branch [How to run this test?](https://github.com/progfolio/elpaca/wiki/Troubleshooting#the-elpaca-test-macro) ```emacs-lisp (elpaca-test :ref "feat/wait-recipe-keyword" :early-init (setq elpaca-menu-functions '(elpaca-menu-extensions elpaca-menu-melpa)) :init (elpaca (elpaca-use-package :wait t) (elpaca-use-package-mode)) (message "first") (use-package doct :ensure (:wait t) :config (message "second")) (message "third")) ```
Host Env
elpacae8552ec HEAD -> feat/wait-recipe-keyword, origin/feat/wait-recipe-keyword
installer0.6
emacsGNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0) of 2024-02-03
gitgit version 2.43.0
Output ```emacs-lisp Elpaca menu item cache discarded due to version change. INFO Scraping files for loaddefs... INFO Scraping files for loaddefs...done GEN ../elpaca-autoloads.el Cloning into '/tmp/elpaca.Vqzeo8/elpaca/repos/elpaca'... Switched to a new branch 'feat/wait-recipe-keyword' branch 'feat/wait-recipe-keyword' set up to track 'origin/feat/wait-recipe-keyword'. Checking /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-info.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-log.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-manager.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-menu-elpa.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-menu-melpa.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-menu-org.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-process.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-test.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca-ui.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/elpaca.el... Checking /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/doc... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/doc/early-init.el... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/doc/init.el... Checking /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/extensions... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/extensions/elpaca-use-package.el... Checking /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/images... Checking /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/test... Compiling /tmp/elpaca.Vqzeo8/elpaca/repos/elpaca/test/elpaca-test.el... Done (Total of 11 files compiled, 3 skipped in 4 directories) Downloading MELPA recipes... Downloading MELPA recipes...100% first second third Test Env Elpaca e8552ec HEAD -> feat/wait-recipe-keyword, origin/feat/wait-recipe-keyword installer: 0.6 emacs-version: GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0) of 2024-02-03 git --version: git version 2.43.0 ```

I'll have to do some more testing and think about the design a bit, but what do you think of that idea in general?

Also, maybe: a new user option to always include an elpaca-wait call when the use-package declaration would not result in a deferred load (e.g. when :demand t is specified). I could see this as being potentially counter-intuitive, however, especially when use-package-always-defer is nil.

I think this suggestion might be too confusing for the reason you pointed out. Loading a package and ensuring its queue is processed aren't necessarily the same, either. It's valid to :demand t a package so it is immediately required after its queue is processed, but for its installation to take place asynchronously. Does that make sense?

montchr commented 7 months ago

I'll have to do some more testing and think about the design a bit, but what do you think of that idea in general?

I like it, and it totally makes sense to include as a recipe keyword since the feature would be useful with or without use-package. Thanks for improving upon my initial suggestion!

I think this suggestion might be too confusing for the reason you pointed out.
Loading a package and ensuring its queue is processed aren't necessarily the same, either. It's valid to :demand t a package so it is immediately required after its queue is processed, but for its installation to take place asynchronously.
Does that make sense?

Definitely. I often use a use-feature! macro wrapper for use-package (originally based on the one from your personal config). There are some cases when I'm using :demand t there, which I think demonstrates a case like you described.

oxcl commented 7 months ago

@progfolio is it possible to use the :after functionality of use-package with elpaca? I'm trying to load a package after another package is loaded without much success

progfolio commented 7 months ago

@progfolio is it possible to use the :after functionality of use-package with elpaca? I'm trying to load a package after another package is loaded without much success

It is. Please open a separate support issue with the details and I can help.

progfolio commented 5 months ago

I've added a :wait recipe keyword as described above. Testing is appreciated.