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

Stefan Monnier <[email protected]> Mon, 27 Jul 2026 23:57:15 -0400
Newsgroups gmane.emacs.devel
Message-ID <[email protected]>
>> - If we evaluate the `:when` conditions during `access_keymap` (like we
>>   currently do for `menu-item`), then we don't want to allow
>>   side-effecting `:when`s, since those side-effects would be executed at
>>   an inopportune time (e.g. before we set `this-command` and run
>>   `pre-command-hook`).
>
> Yes. This is the same as in menu-item.
> We may additionally demand the :when to have 'side-effect-free declared explicitly.

As mentioned earlier, `side-effect-free` is an annotation for the
byte-compiler with a very specific meaning and I'm not sure we want to
tie those two meanings.  Also, if the function *has* to be side-effect
free, I don't see much benefit in checking `side-effect-free`.

>> While sleeping I thought of the following:
>>
>> - Define some way to mark some commands as "metafunctions".
>> - When we lookup a (list of) keymap(s) and the command we found is
>>   marked as a "metafunction", we continue looking for further bindings
>>   and return a composite command made up of the metafunctions (plus
>>   potentially a final non-metafunction) found.
>
> Could you provide an example? Your description is not entirely clear for me.

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`.

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.

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))


=== Stefan