Subject: Sv: bug#78834: Feature request: make keymapp dereference symbol value slot

From: arthur miller <[email-masked]>
Date: Fri, 20 Jun 2025 00:15:29 +0000

> > I realized that and was doing something similar, admittedly less
> > effeciently because I didn't know I can trust that all keymaps have the
> > value slot set.
>
> Your mental model is a bit off.  Keymaps don't have a "value slot".
> IOW, your old loop was looking for "symbols that are keymaps" (which is
> only those whose function slot contains a keymap), but your new function
> looks for "variables which *contain* a keymap".

Aha. Yes it was. I didn't get it that keymaps are *exclusively* symbols
with a keymap in function slot. The doc says it, but since they are also
stored in variables, I was a bit off there.

> Most useful/important keymaps are stored in variables, so yes that loop
> will find almost all of the keymaps.  Not all, because some keymaps are
> produced dynamically or are stored only elsewhere (such as inside one
> of the sublists of `minor-mode-map-alist`).

Yes. I see. Some other defined in keymap.c are also not found.

The function that does the work for me, is processing each keymap
recursively. Maps stored in those lists will hopefully also be defined
elsewhere, otherwise, I will have to iterate those lists as special
cases. I don't see otherwise how to ask for all the keymaps in the
system. Hopefully it is only those alists defined in
keymap.c. Dynamically generated ones are of the reach, unless they are
stored in some parent keymap reachable from a variable in obarray.

> >> It's mostly used in very old code that uses the weird
> >> `define-prefix-command` function, such as the code that sets up some of
> >> the "core" keymaps like `ctl-x-5-prefix` `ESC-prefix` `ctl-x-4-prefix`,
> >> `Control-X-prefix`.
> > I was actually wondering why this was done, if it is just an
> > optimization or if there is some other reason?  I am just curious, I
> > don't really understand the idea behind.
>
> You'd have to ask Richard.  IIUC one of the benefit is that you can
> refer (by name) to a keymap before it's defined.  E.g. you can do
>
>     (global-set-key [?\C-z] 'my-z-keymap)
>
> and then have `my-z-keymap` autoloaded from some library the first time
> you hit `C-z`.  I can't remember the last time I've seen this used
> successfully (I tried to use it a few times, but the keymap always
> ended up being "accidentally" autoloaded much too eagerly).
>
> Maybe it was done simply because Richard thought of keymaps as kinds of
> commands?

It seems so from the docs, but how does it work? Special code that
handles keymaps when evaluation is done? I am not familiar with Emacs
eval and how it handles commands yet.

> > It would be interesting to learn, if somebody knows and is willing to
> > explain, since it is atypical to store value data in function slot.
>
> Indeed.
>
> >> It would break existing uses when the symbol has both
> >> a `symbol-function` value and a `symbol-value` value.  We could
> >> consider
> > I saw the other functions using get_keymap, so I wasn't sure if they
> > would complain or not. I have run Emacs today, the entire day, with that
> > patch, I haven't noticed anything weird.
>
> I wouldn't expect otherwise.  The affected cases would be corner cases.
>
> > DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
> >   (Lisp_Object object)
> > {
> >   if (NILP (object))
> >     return Qnil;
> >   if (CONSP (object) && EQ (XCAR (object), Qkeymap))
> >     return object;
> >
> >   if (SYMBOLP (object))
> >     {
> >       Lisp_Object tem = indirect_function (object);
> >       if (CONSP (tem) && EQ (XCAR (tem), Qkeymap))
> >       return tem;
> >
> >       tem = find_symbol_value (object);
> >       if (CONSP (tem) && EQ (XCAR (tem), Qkeymap))
> >       return tem;
> >     }
> >
> >   return Qnil;
> > }
>
> That would be wrong.  Code can expect that if `keymapp` returns non-nil,
> then you do have a keymap and you can use functions like
> `set-keymap-parent`, `lookup-key`, `map-keymap`, ... on it.  So if you
> change `keymapp` to return non-nil for some symbols, you need to adjust
> the other operations as well.

Indeed, but they will get a keymap, won't they? Because the object
stored in the symbol slot is a keymap. The only difference is from which
slot the keymap is returned. But, I can imagine some code written to
expect nil in some cases, now does not get nil, and perhaps does a wrong
thing.

Anyway, that is a bit unfortunate, because I just found I still do have
to check if the variable is bound before I take the symbol-function, so
I have to type it like this:

(defun collect-keymaps ()
  (cl-loop for s being the symbols
           when
           (or (keymapp s)
               (and (boundp s) (keymapp (symbol-value s))))
           collect s))

With the above function, I could type:

(defun collect-keymaps ()
  (cl-loop for s being the symbols
           when (keymapp s)
           collect s))

However, the second one with the patch finds one keymap less, 588 vs 587,
in my Emacs :). I guess I'll better go with the old one anyway.