reddit / emacs
Opinion: Packages should never bind keys
nicholas_hubbard · 2022-04-29 17:08
It is annoying having to fix broken keybinding configurations or undo keybindings introduced by a package.
Worse is that this can make your configs package definition order matter which is something I put a lot of effort into preventing.
If the package author thinks that their keybindings are useful then they should give the user an explicit opt-in setting.
I don't mind built-in packages doing this.
NextTimeJim · 2022-04-29 17:13
Yeah, if there are a bunch of keybinds that make sense I'd like to have to call something like "package-x-use-default-keybinds" in my init to opt in.
SasukeUchiha231 · 2022-04-29 17:32
1+ on this. Coming from vim, it felt really weird with plugins messing up with your keybindings. Plugins should offer functions that we can use, and that's it. Unless it's a major mode like org-mode.
walseb · 2022-04-29 17:39
Are you talking about packages setting the global mode map or their own package mode maps? I don't think I have ever encountered a package that sets the global mode map apart from completion frameworks and such. If you mean the package mode map, you set their mode map to `(make-sparse-keymap)` before the package is initialized. Given that they follow common keybind creation conventions, the package shouldn't be able to bind anything to it and you will have the mode map all to yourself without needing to unbind anything. Some packages like compilation mode seems to still write to its mode map even with this however. Example: [https://github.com/walseb/QualityEmacsConfig/blob/master/early-init.el#L10](https://github.com/walseb/QualityEmacsConfig/blob/master/early-init.el#L10)
EDIT: I realize now you are probably referring to packages mapping to C-c and C-x. That is indeed common and annoying.
nicholas_hubbard · 2022-04-29 18:05
I think it makes more sense to always have to opt-in to the keybindings instead of needing to opt-out like you do in your link, but yes C-c and C-x keybindings are a worse problem.
Krisselak · 2022-04-29 18:54
In my understanding, C-c is more related to certain modes (usually influenced by packages), while C-x is more system wide. So, C-c should ideally only affect certain modes (e.g. tex-mode) and leave the others alone.
I find C-c bindings, introduced by packages, mostly useful. Also, if you setup a certain binding in your config, shouldn't it override package-bindings?
ElCondorHerido · 2022-04-29 18:56
Agree. And even more important IMO, documentations should ALWAYS use function names and not only keybindings.
nicholas_hubbard · 2022-04-29 19:03
In general when providing help/advice/tips to another person you should always say the function names and not the keybindings. But that is an aside :)
sstepashka · 2022-04-29 19:29
Package loading should never affect any behavior. Enabling modes and calling functions from those packages can. I really don’t like package like I edit and org-journal to override any keybindings.
Also, the problem is once the package is loaded I can’t call the same behavior by loading the same package. Packages loaders only once.
For example, in case of conflicting bindings. Where order of package loading affect the behavior.
But… we can always jack it, right? :) or fix it.
I have to submit this: https://github.com/bastibe/org-journal/pull/345
andreyorst · 2022-04-29 19:34
If Org mode didn't came with a lot of useful keybindings I wouldn't use it, or the adoption would be much more painful for me. Same with things like Magit, or Sly, CIDER, e.t.c.
These all are major modes, but the same applies to minor modes as well, Smartparens/Paredit come with predifined set of bindings that were designed to support a certain way of editing, and I like that.
Still, I have to agree, that when the conflicts appear it's not a pleasant time, so an easy way of preventing a certain package from binding keys would be a nice feature.
ftrx · 2022-04-29 20:26
IMVHO any package should show a doc page with all commands and a pre-defined bind-key declaration, so anyone who want can just copy-paste them or cherry-pick some or use the text to change bindings.
*Some* defaults are needed, in the sense that without Emacs is useless at first start, but those should be just for the Emacs upstream/built-ins.
Perhaps it's about time to start discussing a "Emacs config suggestions and best practice" that cover a single `keyboard.el` / `mybinds.el` stating consider concentrate bindings there even if packages are configured elsewhere because in any case you have a single keyboard, so you need to know what's bound and what's not at a glance anyway... Perhaps some helper functions like a tree-style view:
- inst. pkg foo
|_command one [bind]
|_command two [bind]
- inst. pkg bar
|_ ... [...]
Perhaps in customize.
thetemp_ · 2022-04-29 20:48
If you only use the following for your own bindings, you should be able to avoid this problem.
* "C-c \[letter\]" (note that this only applies to letters, not other characters under C-c)
* F5 through F9
* Super-modified keys\*
* Hyper-modified keys (if your OS supports it)\*
Super and Hyper technically aren't set aside for personal bindings, but they are rarely used by packages. The only exception I've come across so far is lsp-mode, which uses "s-l".
The first two categories listed above [are specifically set aside for personal keybindings](https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Binding-Conventions.html), so they shouldn't be used by packages.
ThockiestBoard · 2022-04-29 20:57
[“What do you mean it isn’t clear?”](https://imgur.com/a/h95ujoT)
by_wicker · 2022-04-29 21:27
I agree that I'd often want their recommended bindings, but as per OP's post it should be opt-in in some canned default.
It's very helpful if the package container identifies useful recommended default keys so ideally there should be a function to apply them and it should be done (or documented) in a clear way so you can easily blacklist or whitelist a subset.
Quite a few modes have redefined something in their own map I have as a global key and then I often have to remove them from the mode map manually. That's not too onerous, but if it were more obvious and explicit it would be a good thing.
emax-gomax · 2022-04-29 22:03
Better yet... put it in a map. You don't need to assign that map to a key or prefix or mode. Just put it somewhere we can easily bind it ourselves if we want to.
doomvox · 2022-04-29 22:44
I tend to write functions that define a default keymap, for the users who like my idea of how the commands should be mapped. I also like to put a prefix key in as the first argument, so you can go for the defaults but just swapped into a different place.
Here's an example, see "perlnow-define-standard-keymappings":
https://github.com/doomvox/perlnow
doomvox · 2022-04-29 22:48
A particular peeve of mine is yasnippet-- it has many vocal fans, but I just played with it once and found it hi-jacked the TAB key for it's own purposes. I don't doubt that's fixable in some way, but I didn't bother with trying-- I can't fathom the egocentric attitude of messing with the TAB key in a minor mode intended to work with programming modes...
thoomfish · 2022-04-30 00:28
Similarly, company-active-map uses Enter for completion, meaning in plain text files almost any short word I type at the end of a line ends up morphing into something else that I didn't want until I disable that binding.
7890yuiop · 2022-04-30 01:12
Emacs documentation generally *does* use the command names. Emacs then translates that to the key binding you're using, if any, or displays the `M-x` invocation otherwise.
7890yuiop · 2022-04-30 01:18
Opinion: That opinion is pretty nuts. Packages should be useful to users *by default*, which typically includes providing key bindings.
If users want to opt out of a package's keybindings they can virtually always do that by clobbering the keymaps(s) defined by that package after loading it.
There are documented key binding conventions which it is assumed both package authors *and you* will adhere to, regarding which key sequences are available for them to use, and which key sequences are available for you to use. If you find a package which is violating those conventions, you should raise it as a bug. If you're violating them, you've opted in to making that your problem to manage if conflicts arise.
* `C-h i g (elisp)Key Binding Conventions`
* `C-h i g (emacs)Key Bindings`
If there are conflicts between minor mode maps then it's true that you may need to do something additional to resolve that. These occasional manual tasks are still better than requiring all users to bind all keys for all modes.
n.b. If you just want a custom keymap which has priority, you can look at https://stackoverflow.com/questions/683425/globally-override-key-binding-in-emacs
[deleted] · 2022-04-30 01:23
[deleted]
karthink · 2022-04-30 02:59
I'm a fan of suggesting keybindings in the README or in the code commentary but not including it in the code. A good example of this is [org-roam](https://github.com/org-roam/org-roam), which provides this `use-package` block prominently in the README:
(use-package org-roam
:ensure t
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n i" . org-roam-node-insert)
("C-c n c" . org-roam-capture)
;; Dailies
("C-c n j" . org-roam-dailies-capture-today))
:config
;; ...
)
In this case this is doubly important, since the `C-c n` keymap is reserved for the user per Elisp guidelines, and no package should ever bind commands to it.
7890yuiop · 2022-04-30 03:24
`C-h b` ??
b3n · 2022-04-30 06:34
Note that modes should not bind anything to `C-c` followed to a letter (without modifier), e.g. `C-c a`, as those are reserved for users to put their own personal bindings. They should instead bind to things like `C-c *` or `C-c C-a`.
The documentation here makes that clear: https://www.gnu.org/software/emacs/manual/html_node/emacs/Key-Bindings.html
Krisselak · 2022-04-30 07:05
Thanks for the clarification.
ftrx · 2022-04-30 07:08
It show all bindings to search through, useful once the configuration is done, useful to discover "ghost bindings" [1] but for a first customize-style or elisp/direct style config is not much nice: supposing you installing a new package, all you want is a summary of it's commands (interactive functions) to choose if and what bind, going through a list of 700+ elements is not that nice... Another example: a newbie who learn a complex package like org-mode a list sorted for frequency of usage of some users (who contribute the statistic) of all commands and eventually default suggested bindings is helpful, the curious will go through them all anyway, who just want to start have a good summary in hand and a good idea on how to use Emacs in keyboard terms...
[1] I do not know if they have a name sometimes I accidentally hit some keys and discover that those are bound to something
flyin1501 · 2022-04-30 08:52
While the title is a bit too general, this is already part of the convention.
> Simply loading a package should not change Emacs’s editing behavior. Include a command or commands to enable and disable the feature, or to invoke it.
>
> https://www.gnu.org/software/emacs/manual/html_node/elisp/Coding-Conventions.html
It would be completely broken if no major mode or minor mode keymaps are provided whatsoever, but judging from your wording that probably isn't what you meant.
The best practice is indeed for keybinds to be provided via a minor mode; the "explicit opt-in" is turning a minor mode on.
Good:
(defvar example-repl-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "<f5>") #'example-repl-run)
map))
;;;###autoload
(define-minor-mode example-repl-mode
"Minor mode providibg keybinds for example-repl."
:keymap example-repl
:global t)
;; Then ask the user to turn it on themself
Bad:
;;;###autoload
(define-key global-map (kbd "<f5>") #'example-repl-run)
[deleted] · 2022-04-30 09:43
[deleted]
Phil-Hudson · 2022-04-30 10:00
Bear in mind that well-written Emacs docstrings can/do/should use the special notation for keybindings. This dynamically looks up the keybinding in effect at runtime and interpolates it into the documentation you read in the help buffer. The interpolated keybinding is itself a link to the doco for the command it's bound to.
Phil-Hudson · 2022-04-30 10:12
How about if the `:keymap` slot of `define-minor-mode` planted a `defcustom` form for the keymap, thus automagically making each minor mode keymap a customization option?
7890yuiop · 2022-04-30 11:11
The message I'd replied to indicated that you wanted a list of key bindings categorised by package.
`C-h b` gives you a list of key bindings categorised by keymap (which is the closest that you'll get, because there's no direct association between a keymap and a package; but a user can intuitively associate the two things).
> going through a list of 700+ elements is not that nice
That's what's going to happen, based on your example. You won't just have `foo` package with two bindings, and `bar` package with one binding -- you'll have dozens of packages each with dozens of bindings. The thing you've described can only contain those 700+ elements. `C-h b` is displaying that about as compactly as possible.
https://emacs.stackexchange.com/questions/59483/how-to-list-a-key-binding-in-any-modes might also be useful.
ftrx · 2022-04-30 11:50
What I mean is for instance (+ indicate a folded element), from M-x customize:
+ foo bar
+ baz
+ gaz
where expanded
- foo bar
- command-1 [bind] :: brief description 1
- command-2 [bind] :: brief description 2
- ...
Another in the package main .el file heading a list of all commands with a brief description and suggested default bindings, settable in a single sexp.
Nothing special, just a suggestion/a visual presentation to the user to help configuring Emacs.
a-c-d-w · 2022-04-30 12:58
I was about to say this exactly. Some packages do have a top-level `(define-key [foo] #'bar)`, but the good ones utilize a minor mode, if only for a keymap. (I know I do that with mine; I've even written some glue minor modes for variables in stock Emacs to toggle keybinds.)
nicholas_hubbard · 2022-04-30 13:47
That is such a good solution.
Phil-Hudson · 2022-05-09 10:37
I've now proposed this on the dev list. bug#55301