Subject: Re: bug#62207: 29.0.60; Trying to remove non-existent key binding instead adds a binding

From: Stefan Monnier <[email-masked]>
Date: Fri, 17 Mar 2023 17:09:02 -0400

>>>     Jonas> As a side-note, it would be nice if it were possible to lookup a
>>>     Jonas> key in a keymap only, while ignoring bindings in its parent keymap.
>>
>> Could you explain why you need `keymap-unset-key`
>
> Directional commands usually involve the keys "b", "p", "n" and "f".
> These keys are mnemonic but are also scattered all across the keyboard.
> So in my own Emacs I have chosen to use "physically-mnemonic" bindings
> instead:     "i"
>          "j" "k" "l"
>
> [ Maybe that was a stupid decision.  But I made it very early in my
>   readline/Emacs career.  There is no way back. ]
>
> That makes it necessary to edit many keymaps.  Using keymap-unser with
> non-nil REMOVE makes that much less painful.  It's still painful but any
> relieve is welcome.
>
> In magit-section-mode-map, for example, I make these changes
>
>   default             custom  
>   "p"     replaced by "i"     magit-section-backward
>   "n"     replaced by "k"     magit-section-forward

[ Indeed, Emacs's keymap system doesn't support this very well.
  For the same reason Evil/god-mode/boon/... need a lot of
  package-specific tweaks to "patch things up".  :-(  ]

> magit-mode-map has the above keymap as parent.  It also binds "i"
> to magit-gitignore.  I could just override that binding using
>
>   (keymap-set magit-mode-map "i" #'magit-section-backward)
>
> but it is much clean to
>
>   (keymap-unset magit-mode-map "i" t)

Agreed, this is a good use case, thanks.

> But they just came in handy.  When using keymap-unset to remove a
> binding but there isn't actually a binding, then that ends up adding
> a binding.

This is the bug we're discussing, right?  AFAIC it's a plain bug with an
easy fix (provided by Robert).

> To work around that bug I have to first check if there is a binding.
> But it must be a binding in the keymap itself, not a parent keymap.

Right, but this need is only brought about by the bug, so once the bug
is fixed, this need will disappear.  I hoped you had other needs for
that functionality.

>> I'm curious because the meaning of these can be subtly more complex than
>> meets the eye once you consider things like `make-compose-keymap`.
> My current implementation seems to treat later keymaps in composed
> keymaps like parent keymaps.  Maybe that makes sense, maybe a proper
> implementation should make a distinctions between parent keymaps and
> "tail" keymaps.

`map-keymap-internal` stops at both a parent keymap (i.e. a keymap in
the `cdr`) and a "subkeymap" (i.e. a keymap in the `car`).

> What I care about the most is that the bug is fixed

Agreed.

> (instead of users being told to not use the REMOVE argument, as you
> seem to suggest elsewhere in this thread).

I'm mostly worried about people using it in ELisp packages where it's
more likely to interact with many more situations.
For uses in an init file I think we can make it work well enough.

        Stefan