jwiegley / use-package

A use-package declaration for simplifying your .emacs
https://jwiegley.github.io/use-package
GNU General Public License v3.0
4.41k stars 260 forks source link

Deferring hooks? #889

Open Ergus opened 3 years ago

Ergus commented 3 years ago

Hi:

I am wondering if there is a way to do something like defer with integer but for modes that load with hooks. The problem is that some "not urgent" modes (ex: lsp, flycheck) slows down (when not using emacs server of course) the startup time. For a permanent delayed always loaded modes I could make ":defer 2" but right now lsp is loaded in a hook only in some modes.

I have the following workaround:

(use-package lsp
  :diminish
  :preface
  (defun my/lsp ()
    (run-with-idle-timer 2 nil #'lsp))
  :hook (c-mode-common . my/lsp))

does use-package has anything better and less hacky?

Thanks in advance, Ergus

Ergus commented 3 years ago

Sorry to bother but to extend this a bit more:

I have observed that when using code like this

(use-package which-func
  :diminish
  :hook (prog-mode . (lambda ()
               (run-with-idle-timer 1 nil #'which-function-mode 1))))

The macrostep-expand code is different than:

(use-package which-func :ensure nil
  :diminish
  :hook (prog-mode . (lambda ()
               (run-with-idle-timer 1 nil #'which-function-mode 1)))
  :defer t)

The documentation says that hook implies defer. But in the first case a required is added but in the second an eval-after-load.

Is this intended?

Ergus commented 3 years ago

To follow this a little bit, maybe a new keybord in use-package may be useful here.

According with this:

https://lists.gnu.org/archive/html/emacs-devel/2020-12/msg01549.html

To make the code work properly it is needed some extra cumbersome work to generate code like this:

(add-hook 'prog-mode-hook
              (lambda ()
                (run-with-idle-timer 1 nil
                  (lambda (buf) (with-current-buffer buf (flycheck-mode 1)))
                  (current-buffer))))

In my use-package the it is possible to do:

(use-package prog-mode :ensure nil
  :preface
  (defvar prog-mode-delay-hook nil)
  (defun my/prog-mode-hook ()
    "Some hooks only for prog mode."
     (run-with-idle-timer 1 nil
             (lambda (buf)
               (with-current-buffer buf
                 (run-hooks 'prog-mode-delay-hook)))
             (current-buffer)))
  :hook (prog-mode . my/prog-mode-hook)
  :defer t)

So I could add hooks to prog-mode-delay-hook in order to simplify and keep modularization in other packages.

conao3 commented 3 years ago

the first issue is a feature request, I cannot comment on it, but the second one is an intended way I think. Please read https://github.com/jwiegley/use-package/issues/895#issuecomment-783305743

I'm bit surprised at this behavior, but use-package check hooked function is autoloader and generate require statement if not autoloaded function. (so if you specify lambda statement, use-package always generate require statement still you use :hook keyword.

On the other hand, leaf don't check to see if the function is autoloaded if you use :hook, it don't generate require statement. This is not smart, but its behavior is more expected.)