general.el
general.el copied to clipboard
Address common user problems, poor practices, and inadequate documentation
There are several problems/questions that come up a lot that aren't specific to general.el. Attempting to bind a key sequence that has a sub-sequence already bound ("sequence starts with non-prefix key") is a common problem. Some users want to be able to keep both bound (#43, #64). For these users, general-key-dispatch
exists. Other users actually want to unbind the key (#14, #46, #54, #57, #84).
In the past, I've had the request to automatically unbind keys when necessary (#25). I've refused for a few reasons. I don't like the idea of general.el making extra keybindings not specified by the user. This definitely shouldn't happen by default; the user should understand why this is an error. To do this, general.el would have to check for this case and keep checking sub-sequences to find the key to unbind. On the other hand, I understand the usefulness of having this as an option. The user is not required to know which keys are available as prefix keys or whether those keys have already been unbound. With this as an option, specified keybindings would always be made as-is regardless of the state of the keymap they are being made in. I'm reconsidering adding this as an option (off by default). Any feedback would be appreciated (feel free to like this or reply if you would like this feature).
Regardless of whether I add this feature, I think this issue should be documented in the FAQ.
Another common question from users is how to bind keys specified by :prefix
in the same general-define-key
. The fact that keys specified with :prefix
can still be bound/unbound with "" def
is a logical consequence of how general.el handles prefix keys, but this functionality is not documented well enough in the README.
Another common issue is that users use :states
without :keymaps
(i.e. the default :keymaps 'global
is used) without understanding the implications because they don't fully understand :states
. This can potentially cause incorrect behavior (#54). I need to retest that, but regardless, evil intercept maps are the better solution to the issue of preventing global keybindings from being overridden. I should stop recommending ever binding in a state and the global map both here and in the evil-guide. I think I should even give a warning if the user tries to do this.
General.el expects users to already be familiar with Emacs' (and evil's) keybinding system, but it could help new emacs users by immediately pointing to the relevant Emacs documentation (and FAQ). General.el's README has gotten much bigger and needs a table of contents at the beginning.
I think a recommended practices section should also be added at the very beginning. I now think that allowing the users to, for example, control the default states used by general-define-key
was a mistake. This behavior can be achieved with wrappers without directly altering the behavior of general-define-key
. All mention of these default variables should be removed from the README, and ideally they should be deprecated. Furthermore, the current basic setup section is pretty bad. A lot of users don't know about general-def
. general-def
is simultaneously the most flexible and concise definer provided by general.el (it's the only definer I use), and can make switching all keybindings to general.el trivial. Along with the basic setup section, there should be an example of how to quickly convert define-key
, global-set-key
, evil-global-set-key
, evil-define-key
, etc. to general-def
using search and replace and setting general-implicit-kbd
to nil.
An alternative to general-implicit-kbd
would just be to remove all kbd
s found in general-emacs-define-key
and general-evil-define-key
for compatibility. This seems like it would be just as complicated (or potentially more complicated). I'm not sure whether or not I want to keep general-implicit-kbd
. Any feedback on this would be appreciated
- [x] Add a table of contents
- [x] Add recommended practices section and "required" reading to the beginning of the documentation
- [x] Completely rewrite introduction/basic examples
- [x] Add section detailing how to convert existing keybindings to general keybindings with regexp search/replace
- [ ] Add an info manual exported from the README
- [x] Add
general-auto-unbind-keys
(tests/documentation still needed; faq entry should also mentiongeneral-key-dispatch
) - [ ] Document
:prefix "keys" "" def
more explicitly in the README - [x] Remove all mention of default variables (e.g.
general-default-states
) from the README, make them obsolete, and add a warning that they will be removed eventually - [x] Make
:keymaps 'global :states 'normal
the same as:keymaps 'normal
(likeevil-define-key
now does); recommend intercept maps instead of the old suggestion - [ ] Update key recording to record
:states 'global :keymaps 'normal
the same as:keymaps 'normal
- [x] Keep
general-implicit-kbd
only forgeneral-define-key
as a way to make transitioning fromdefine-key
,evil-define-key
, etc. easier (update documentation about what it applies to and why) - [x] fix intercept map documentation here and on evil guide and don't recommend binding in a state with
(current-global-map)
- [ ] give :prefix its own heading and better document #82
I don't like the idea of general.el making extra keybindings not specified by the user. This definitely shouldn't happen by default; the user should understand why this is an error.
I agree with your point here, but I think have automatic unbinding as an option that's off by default is a good way to go. It doesn't change anything for users who don't want it, and people that want the option need to explicitly indicate that they want it, understanding that some bindings are made "in the background" as a side effect. (Of course that should be made very clear in the docstring for such an option).
I've added experimental (no tests) support for automatic unbinding. You can call (general-auto-unbind-keys)
if you want to try it. Since general doesn't necessarily know the keymap the key will end up being bound in (for user-created :definer
s), this is implemented by advising define-key
. I may rename it to general-force-bind
or something else.
This seems like the appropriate place to mention this minor issue which I think should be documented: Using multiple :general
keywords in a use-package
form does not work as users may expect. For example:
(use-package something
:general (:keymaps 'map1
"k" 'fn)
:general (:keymaps 'map2
"j" 'fn2))
When expanded, the clause for map2
is missing from the expansion.
The apparently correct way to do this is to have a single :general
symbol with multiple lists, i.e.:
(use-package something
:general
(:keymaps 'map1
"k" 'fn)
(:keymaps 'map2
"j" 'fn2))
However, this is (to me, at least) non-obvious, from the documentation and examples. I had to figure this out by debugging it myself.
Thanks.
For normal keyword arguments, specifying them twice will override values. Use-package does have its own custom handling of keyword arguments, but are there other keyword arguments that can be specified multiple times? Your first example does make intuitive sense, and I do think that this could be better clarified, so I will update the readme to better explain this.
Use-package does have its own custom handling of keyword arguments, but are there other keyword arguments that can be specified multiple times?
I'm not sure, sorry. I thought that some of them could be, but maybe I'm mistaken.