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

Customizability and appealing to a wider audience #4

Closed
noctuid opened this issue Nov 5, 2017 · 4 comments
Closed

Customizability and appealing to a wider audience #4

noctuid opened this issue Nov 5, 2017 · 4 comments

Comments

@noctuid
Copy link

noctuid commented Nov 5, 2017

I originally started this as a reddit reply but thought it would be better as an issue from an alternative perspective and some suggestions since I think this idea has a good amount of potential.

Some background:
I use evil normal state as the initial state in all my buffers and have added my own keybindings for everything I use (org, mu4e, lisp editing, elfeed, proced, paradox, pdf-tools, nov.el, mingus, dired, etc.). I've always found adding new evil keybindings to a new mode to be trivial and just do it as I'm learning what commands/key the mode provides (even if I was justing going to use the emacs keybindings, I would have have to learn what keybindings are provided anyway). Even if there wasn't the disction of "evil" vs "normal" emacs keybindings, I'd do a lot of key rebinding. I made pretty much all my keybindings myself when I used vim (i.e. I didn't normally use plugin defaults). This is in part because I use Colemak and in part because I have my own system for keybindings that differes a lot from default vim. I make a lot of swaps such as a and A and use a lot of the default keys such as r, s, t, m, and , as prefix keys with some theme (e.g. m for keybindings that are specific to a major mode, r for remote navigation with avy/evil-easymotion and for remote text object selection in operator state, etc.). Because I'm so picky, default keybindings have never appealed to me.

That all said, I definitely see the need for this sort of project, especially outside of Spacemacs. However, trying to make something like this that is generally appealing is a lot more effort than personal configuration. This is because consistency and rules are important and the package will probably end up having keybindings even for modes you don't personally use and may bind commands you don't use even in modes you do use. Looking at it briefly, I want to say that it's great that you aren't taking shortcuts but are manually making all the rebindings without using evil-make-overriding-map (unlike evil-integration.el) or evil-make-intercept-map. This is the right way to do it as far as I'm concerned. It's great that it's modular (unlike evil-integration.el), so that users can pick which modes they want configuration for. This seems to me like it could grow into a more comprehensive and less intrusive version of evil-integration.el (at least for keybindings; it would be great if evil-integration.el added an option to never make and key definitions and users could use this package as better alternative). Also, I think that having guidelines is essential, and briefly glancing over the current ones, they look very sensible.

The problem is that there is no one-size-fits-all solution to key configuration. However, I think a package like yours could address a lot of issues that emacs/vim distributions, for example, face. I don't like how Spacemacs has unreasonably long keybindings (e.g. 3-4 keys) for common actions (in part because it has a lot of stuff, much of which I'd never use). It's a good idea for discoverabilty and for logically grouping things under mnemonic prefixes, but I can handle my global keybindings by myself easily. The idea of your package is nice because of its modularity and the fact that it focuses only on non-editing modes and only on keybindings. This means a lot more letter keys are available for binding, reducing the issue of long keybindings even if a lot of commands that some users may not use often are bound. If there wasn't much optimization to be gained from making my own keybindings, and there were sensible defaults provided, I'd be a lot more inclined to use those defaults.

A potentially bigger problem is that of non-standard evil keybindings. When someone has a non-standard keybinding configuration (because of either a non-qwerty layout or non-standard remappings or both), the idea of default keybindings loses much of its appeal. Defaults are often so far from one's ideal keybindings that it may be easier to just start from scratch. The biggest plus for me for using normal state essentially everywhere (as opposed to sometimes using emacs/insert state for the already defined emacs keybinding) besides consistency (e.g. jk vs np) is that I always have certain keybindings globally available regardless of context. For example, if I use SPC in normal state as a prefix for file/buffer/workgroup navigation/management that I want to be available everywhere, and I use your proc-mode config, my SPC keybindings are gone. Now I could make that keymap a prefix keymap and bind it in motion state for the proced keymap after requiring evil-proced.el to work around this. I could even use an intercepting map to prevent any of these packages from overriding my SPC. Then I would have to figure out whether I want to rebind whatever was bound to SPC in proced and every other modes.

Maybe this amount of extra configuration isn't that bad for anyone mostly okay with the defaults provided by evil-special-modes (though it gets worse the more non-standard someone's key configuration is), but my guess is that there is at least some level of configurability that could make evil-special-modes useful to a lot more people. I have some initial suggestions for this. For example, it would be nice if the users could provide a list of keys that should never be overridden (e.g. their global prefix keys) with an optional alternative key. Allowing key swapping/cycling would also be tremendously useful. For example, the colemak version of hjkl is hnei. A lot of colemak users follow similar rules for keeping the hjkl position:

  • n replaces j (as down)
  • e -> k
  • i -> l

And to replace the missing j,k,l:

  • k -> n (search next)
  • l -> i (insert)
  • j -> e (forward word end)

With this functionality added, users of other keyboard layouts could benefit from the established guidelines with much less manual configuration (e.g. now directional keybindings would be added to hnei, l would be used in place of i keybindings in modes where insert mode doesn't make sense, j would be kept like e would have been in modes where navigation makes sense, etc.). These changes would break mnemonics for some evil-special-modes keybindings, but keeping the hjkl positions in a non-QWERTY layout already requires breaking the default mnemonics, and I think that these swaps being consistently done across all supported modes would be a good start even if the user decided to change things further.

Key translations/alterations would be useful in other circumstances as well. For example, if I never wanted certain keys to overridden, I could add them to some list, and keybindings that use those keys would not be created. If I had some alternate key I wanted to use instead, there could be a translation so it would be used instead. Maybe I'd prefer to use something else other than ( and ) for navigating subsections. Even beyond hjkl, there are a lot of similar types of commands between modes (e.g. filtering as mentioned in the readme), so it could make sense to have the keys used for some type of command be user-customizable.

I haven't thought enough about how far it would make sense to go with this. As they are currently, the groups of keys mentioned in the readme could be put in variables. Each mode could have an associated boolean as to whether that key type is available for the mode. The user could decide to change it in some circumstances. For example, a user could set something like -macros-useful to nil to use q to quit instead of ZQ (the idea being that he/she wouldn't personally want to use macros in the mode even though the could potentially be useful). There could be variables holding the keys that would be preferred for different generic actions, such as reverting/refreshing. Either it would always be okay for that key to be bound, or there could be a list of backups if it was in one of the matching lists of non-free keys for the current mode (like with q and ZQ).

I think it makes sense to try to group related actions as much as possible. Here are some groups of actions I've come up with off the top of my head:

  • refreshing (mentioned in readme)
  • sorting, (mentioned in readme; package/paradox, dired/ranger, proced, mu4e, etc.)
  • filtering, occur, narrowing (mentioned in readme); also querying/searching without removing things that don't match (in some packages there would need to be several keybindings)
  • marking related functionality (mentioned in readme; paradox/package, dired, pdf-tools, mail packages, etc.); in packages with a lot of actions, it could potentially make sense to use a prefix (e.g. the package list has at least 4 things you can mark a package for; mu4e even more, and evil-mu4e only binds a couple of them)
  • jumping (e.g. to a specific page in pdf, to new maildir in mu4e, etc.)
  • bookmarking and jumping to bookmarks; may need to be distinguished from marking for some modes (e.g. mingus-mark vs. mingus-bookmark-set)
  • other types of next/prev and directional actions (e.g. next unread/read); sometimes packages have multiple sets of commands that are directional
  • zooming (pdf-tools and image-mode)
  • history navigation (pdf-tools, queries in mu4e, etc.)

Sorry for the massive issue, but hopefully it will be useful. Especially since this package is relatively new, I think it makes sense to consider these things as early as possible. Even some level of basic configurability could do a lot to make this sort of thing appeal to more people. Since there are a lot of differences between different modes, you can't have perfectly similar keybindings between them, but I think a lot can still be done to promote consistency, and further discussion about additional rules/guidelines could be useful.

@Ambrevar
Copy link
Owner

Ambrevar commented Nov 5, 2017

Thank you for this rich and constructive comment! :)

In short: We cannot please everyone but that's OK. The point is to provide some key bindings with consistency.
If the user does not like them, he/she can tweak them or start from scratch.
The binding sets can be selected individually as per user preference.
It's better to have something to start from than nothing.
Should you dislike some choices made by this package, no problem, it's very easy to change any of those bindings, you can even do so globally and dynamically.
It will not cost you more than a few lines of Elisp.

Currently, the total lack of bindings cost hundreds of configuration lines. Lines that are hard to write consistently.
And that is the very issue we are trying to tackle here.

  • "Don't override some user-defined keys": I don't think this belongs to evil-special-modes, in fact this is part of Emacs design.
    Key bindings have priorities, namely

      global bindings < major modes < minor modes
    

    and some keys are reserved to the user (-, C-c LETTER, see the manual) and those will never be overridden.
    If you want to use a global prefix key, there is evil-leader among others.
    Another common solution is to create your own minor mode map and make sure it is loaded last. This will effectively act as truly global bindings.
    Moreover, the issue is not Evil-specific, it's the same with Emacs.
    What does SPC do for you in help-mode / info-mode?

  • Configurability: Anything can be configured and we can't predict what the user wants.
    Adding an option for all groups of bindings is basically as efficient as not adding an option at all and let the users tweak it themselves.
    Emacs can "rebind" keys and also bind keys to other bindings. They are many ways to achieve this.
    Maybe some options would make sense though, like the Evil C-u option since C-u is universal.
    I don't think that "q for macros or q for quitting" is a viable option since more often than not, macros are not useful in special modes.

  • Key translation for other layouts (e.g. colemak): Excellent point!
    I think we would definitely need this.
    That being said, to the extent it is doable. I think I've seen something similar before in Emacs, maybe in Evil mode.

  • Groups: yes, that's very helpful to have in a rationale I think.
    Thanks for the suggestions, I'll re-use them.

@noctuid
Copy link
Author

noctuid commented Nov 5, 2017

I don't think this belongs to evil-special-modes

That's fair enough. I was more concerned with potentially being able substitute another key to be bound instead of the global prefix. As a side note, evil-leader is poorly designed (and just uses a global minor mode itself for this); the keymap hiearchy is more complex than that, and you don't need to worry about loading order if you just use evil intercept maps.

What does SPC do for you in help-mode / info-mode?

I never use motion as the initial state, so it works fine as my global prefix in info-mode. By the way, what is the rationale for using motion state as the initial state? I know evil-integration.el does this, and in some way it makes sense because commands bound in normal state sometimes don't make sense in these modes, but the new commands bound aren't all motions. It kind of seems like an abuse of motion state to me. After all, motions aren't useful in some modes either, and many users expect normal to be the default state. Maybe it is a better starting point though. It might be nice if the initial state and the state keybindings are made in was customizable.

Adding an option for all groups of bindings is basically as efficient as not adding an option at all and let the users tweak it themselves.

The idea was that these groups of bindings would be used for every mode where they are relevant, so they would only need to be set once as opposed to making bindings each for each mode separately. Let me formalize my suggestions a little more with the complex grouping options removed:

  1. Some way to swap keys around (translations; for users of other layouts)
  2. Some way to have a single key stand in as another (when globally bound keys override some useful key); the difference is that this isn't a complete swap

Maybe emacs can help with both of these without evil-collection having to do too much. I don't know about translations. Emacs allows global translations, but I don't think there is some way to do that locally in a keymap (I'd have to check). If I remember correctly, you could solve the second problem like this thouh:

;; SPC is used as global prefix; have "key" act as space
(evil-define-key 'state some-evil-collection-keymap
  "key" (cons (evil-get-auxiliary-keymap some-evil-collection-keymap 'state)
              (kbd "SPC")))

This would be pretty tedious to do. It would be nice if evil-collection stored a list of all the keymaps it provides in the base package, so that someone could easily iterate through all of them and make this remapping (with evil-define-key it wouldn't matter if the other packages hadn't been loaded yet).

@Somelauw
Copy link

Somelauw commented Nov 5, 2017

Maybe emacs can help with both of these without evil-collection having to do too much. I don't know about translations. Emacs allows global translations, but I don't think there is some way to do that locally in a keymap (I'd have to check). If I remember correctly, you could solve the second problem like this thouh:

I am not a colemak user and I haven't tested this, but if the problem is remapping keys, then I think this is already possible in Emacs.

(defun remap-hjkl (keymap)
  (let ((new-keymap (copy-keymap keymap)))
    ;; swap n and j keys
    (let ((f-j (lookup-key keymap "j"))
          (f-n (lookup-key keymap "n")))
      (define-key new-keymap "j" f-n)
      (define-key new-keymap "n" f-j)
      new-keymap)))

;; To actually use the new keymap
(setq evil-helpmode-map (remap-hjkl evil-helpmode-map))

This is slightly more complex in evil code, because we need to do this for all the different states if we use them, but not impossible. The advantage is that no special treatment is needed in evil-special-modes.

@noctuid
Copy link
Author

noctuid commented Nov 5, 2017

That's definitely one way to do it. It's destructive though which has some potential downsides. I'll have to think more about the best way to do this. Let's continue discussion about this in emacs-evil/evil-collection#5. I'm going to close this.

The advantage is that no special treatment is needed in evil-special-modes.

I'd have to play with it, but if the method I mentioned works, it could also potentially be used without doing anything extra.

@noctuid noctuid closed this as completed Nov 5, 2017
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

3 participants