Re: On keybindings and the slow erosion of help's utility

Ihor Radchenko <[email protected]> Sat, 01 Aug 2026 18:03:04 +0000
Newsgroups gmane.emacs.devel
Message-ID <87tspd90sg.fsf@localhost>
Stefan Monnier <[email protected]> writes:

>>> Say we have:
>>>
>>>     (keymap-global-set "TAB" #'my-foo)
>>>     (keymap-set foo-mode-map "TAB" (make-partial-binding #'my-condition #'my-bar))
>>>
>>> Then `(key-binding "TAB")` in Foo mode would return something like
>>>
>>>     #f(composite-command #f(partial-binding my-condition my-bar) my-foo)
>>>
>>> So `my-condition` is not executed during keymap lookup but only during
>>> command execution (so we don't need to worry about side-effects during
>>> keymap lookups, tho we may still worry about them if we wan to run
>>> `my-condition` during `C-h k` to whether we'd run `my-foo` or `my-bar`).
>>>
>>> Calling `composite-command` could look inside the `partial-binding`
>>> command, tho a more generic approach would be for `composite-command` to
>>> just call its first command with a "continuation argument" which is
>>> the second command so it doesn't need to know about `partial-binding`.
>>
>> What if none of the `partial-binding's match?
>
> If the last command is also a partial binding and it doesn't match, then
> we can do something similar to calling `undefined`, tho maybe with
> a tweaked message.  I don't see any difficulty here.  Am I missing something?

Yes. Consider that we want to define the partial binding in
foo-minor-mode-map. If nothing match, we also want to continue resolving
the keymaps in the usual order.

>>> An important question is what to do with
>>>
>>>     (keymap-set foo-mode-map "TAB" (make-partial-binding #'my-condition1 #'my-bar1))
>>>     (keymap-set foo-mode-map "TAB" (make-partial-binding #'my-condition2 #'my-bar2))
>>>     (keymap-set foo-mode-map "TAB" (make-partial-binding #'my-condition1 #'my-bar3))
>>>
>>> should each call completely override the previous (so after those three
>>> calls we have just a single partial binding that uses `my-bar3` when
>>> `my-condition1` is true)?  Or should we just accumulate them (if so,
>>> how do we remove a partial binding without removing them all)?
>>> Or should the third call override the first but not the second (and presumably
>>> allow `(keymap-set ...(make-partial-binding #'my-condition1 nil))`
>>> to remove one of the partial bindings)?
>>>
>>> The third option sounds more flexible, but it requires more changes in
>>> the `keymap.c` code.
>>
>> IMHO, the best approach is to make the full "partial-binding" named and the
>> each condition also named (as in my suggestion with :name). I described
>> examples earlier. I think that exactly the same structure can be used to
>> manipulate the conditions. (I hope what I said in this paragraph makes sense)
>
> I'm afraid I don't understand how what you say relates to what I said.

In my earlier emails I described my idea how to solve the problem you are
describing - about adding and removing the conditions in certain order.
Instead of implicit replace/append, I suggested to adopt
add-hook semantics with passing priorities and an ability to remove the
existing bindings (like in remove-hook).

>>> Also, in the above I assume that we're not interested in something like
>>>     (keymap-set foo-mode-map "TAB" (make-partial-binding #'my-condition1 my-keymap))
>> I am not sure why we need to introduce such a limitation vs. what I proposed.
>
> Because what I'm describing moves the execution of the conditions to the
> moment we run the command, rather than the keymap-lookup, so it's late
> to do further key processing.

> Strictly speaking, it would be possible, e.g. to call `popup-menu` after
> evaluating the conditions if the chosen option is a keymap, but it
> wouldn't integrate as well into the command loop and things like `C-h k`.

I thought that one of the first problems raised in this thread was
exactly the integration with C-h k. The other one was directly affecting
keymap resolution (whether we should continue looking up the key as in
prefix map or move on to next keymap in the priority order).
Otherwise, what you propose is nothing but elaborate wrapper around

(cond
 (condition command)
 ...)

That's already possible. I do it in my meta-functions package, where
(cond ...) can be changed dynamically and the overall docstring adopts
accordingly. But that was not good enough, AFAIR. What am I missing?

-- 
Ihor Radchenko // yantar92,
Org mode maintainer,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>