Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

once / deferred loading / new binding package #644

Open
jojojames opened this issue Jun 8, 2022 · 4 comments
Open

once / deferred loading / new binding package #644

jojojames opened this issue Jun 8, 2022 · 4 comments

Comments

@jojojames
Copy link
Collaborator

Follow up to: d97e6d5

Creating an issue to better track the discussion, @noctuid

I think evil-collection is stuck with evil-collection-define-key, but maybe this will be useful for other libraries. evil-collection-define-key could use a different key definer library under the hood, but a wrapper is still needed to support the evil-collection-specific functionality like evil-collection-key-whitelist.

An interface I was thinking of was to have the definer (general/bind-key/define-key/whatever) actually take in the white/black list and respect it. So you could do something like

(setf general-white-list '("a" "b" "etc")) (general-bind "a" 'some-function "b" 'some-other-function)

That way the white/black list is handled at an even lower level than evil-collection. Trying to think of scenarios where that would not be preferable and can't think of any off the top of my head. As for how to interface with it, either defalias the current whitelists to the implementation variable or just do something like:

(setf general-white-list evil-collection-white-list) (just using the general prefix, but in general i'd prefer something shorter)

For reference, annalist.el is >2x as big as once.el and is required by evil-collection already. I think we can defer requiring annalist and doing any recording until the user actually runs evil-collection-describe-bindings to further speed up evil-collection initialization. Or, to reduce code duplication, the evil-collection-define-key implementation could be switched to use my general.el rewrite (when it is eventually ready) which will already support this.

Yeah, it might make sense to defer annalist but I thought we needed to do the recording at the time the define-key is called?

If it's your own config, you can always alias it or evil-define-key to def. And if you're using use-package or an equivalent, you can pick whatever keyword name you want. The length doesn't matter that much to me personally. Evil support for my new general-like key definer will be implemented in imp.el, so one could at least get a imp-def or just imp (doesn't get shorter than that). I don't think there is any "vim" package, so you could maybe get away with make one just for the namespace.

I try to just use what's already there. I find the aliases, etc (or even writing hand made utility functions to save some duplication) not super worth it sometimes.

I don't think there is any "vim" package, so you could maybe get away with make one just for the namespace.

That's a super interesting idea. I may actually create a new package called vimdef (dunno, will pick something...) and refactor all the evil-collection stuff to use that new package. Users could reuse the same package in their own configuration and that would be able to leverage all the evil-collection stuff. I'll have to think further on that, just an idea for now..

@noctuid
Copy link
Contributor

noctuid commented Jun 8, 2022

I added tests for once today. I'll try it out with those evil-collection packages when I get a chance.

That way the white/black list is handled at an even lower level than evil-collection. Trying to think of scenarios where that would not be preferable and can't think of any off the top of my head. As for how to interface with it, either defalias the current whitelists to the implementation variable or just do something like:

(setf general-white-list evil-collection-white-list) (just using the general prefix, but in general i'd prefer something shorter)

Maybe define-obsolete-variable-alias could also be used if the syntax was compatible. If my new package was used, the variable would be probably usul-whitelist, which is a little shorter. Like I mentioned before, the key definer for evil users could be as short as imp. (Things will be split into more packages. usul will be a DSL/building material for a key definer, there will be another package for a general-like syntax on top of usul, and then imp adds evil support).

Though switching from evil-collection-define-key to something else would be fairly tedious for every occurrence (especially if switching to auto-kbd, for example; a compatible definer could be used instead though).

I may actually create a new package called vimdef (dunno, will pick something...) and refactor all the evil-collection stuff to use that new package.

That would definitely simplify things if the underlying implementation changed.

Yeah, it might make sense to defer annalist but I thought we needed to do the recording at the time the define-key is called?

We do need to check the old definition prior to binding, but that could potentially be done outside annalist. Annalist does have some extra overhead when storing. I need to rethink some things about annalist, and I'll have to test to see if it makes a significant difference in startup time. It may or may not be worth it.

@jojojames
Copy link
Collaborator Author

I added tests for once today. I'll try it out with those evil-collection packages when I get a chance.

Anything I can do to get help, testing etc?

@noctuid
Copy link
Contributor

noctuid commented Mar 11, 2023

Sorry for the delay. I'm still quite busy, but I'm going to try get back to cleaning up once.el and putting it on MELPA soon since it is fairly close to done.

If I remember correctly, the issue was to more intelligently defer packages rather than using an idle timer.

  • Most evil-collection packages can just use eval-after-load (or once-with-eval-after-load)
  • The packages that load immediately would need a more complex method to defer them until the evil-collection configuration is actually needed

Here are the features I listed before that loaded for me with emacs -Q:

  • eldoc, tab-bar, simple, tabulated-list - very small evil-collection configuration
  • help, image, info, calc - bigger
  • replace

Calc mode could probably be handled by using calc-mode-hook or advising calc:

(once (list :hooks 'calc-mode-hook)
  (require 'evil-collection-calc)
  (evil-collection-calc-setup))

If that works, Info-mode-hook, tab-switcher-mode-hook, occur-mode-hook/occur-edit-mode-hook for replace, and tabulated-list-mode-hook should work the same way. image-mode-hook should also work for image mode (it doesn't create the variable by default, but it looks like the setup code runs image-mode-hook). There is the question of whether these hooks will trigger early enough for evil-set-initial-state (e.g. for tabulated list) to work. I haven't tested it.

I think I found help loads by default, but that's different from help-mode. I don't think evil-collection does anything for help.

For eldoc, advising before eldoc-doc-buffer might work:

(once (list :before #'eldoc-doc-buffer)
  (require 'evil-collection-eldoc)
  (evil-collection-eldoc-setup))

Handling simple would probably be more complex. You'd need to wait until the user actually visits a buffer in simple mode. Doom, for example, implements its buffer switch hook using window-buffer-change-functions and server-visit-hook. I'd have to check if these actually run in the correct buffer for the major mode check to work though.

(once (list :hooks 'window-buffer-change-functions 'server-visit-hook
            :check (lambda () (eq major-mode 'special-mode)))
  (require 'evil-collection-simple)
  (evil-collection-simple-setup))

Overall, I think eval-after-load would be good enough for most modes.

@jojojames
Copy link
Collaborator Author

Here are the features I listed before that loaded for me with emacs -Q:

I think other than the emacs -Q packages, we'd still need to have a story for packages users may download and load other than their default emacs -Q packages as that can cause slowdown too.

Most evil-collection packages can just use eval-after-load (or once-with-eval-after-load)

We already use eval-after-load/with-eval-after-load I believe. I think avoiding even adding the the function to with-eval-after-load is ideal.

Calc mode could probably be handled by using calc-mode-hook or advising calc:

Hooks seems more ideal than with-eval-after-load but I figure we'd want it to be configurable (hopefully that's where once comes in).

Overall, I think eval-after-load would be good enough for most modes.

I'm envisioning some configuration variable users can customize to their mode list (and we supply a default one) that can set up how much evil-collection file is loaded. Not sure what it could look like, maybe:

defvar evil-collection-mode-config
  '((dired . (:once defer 3 :some-otherevil-collection-dired-flag t))
    (company . (:once SOME-INPUT))
    (calc . (:once HOOK )))

:some-otherevil-collection-dired-flag expands to evil-collection-some-otherevil-collection-dired-flag

(random pseudocode)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants