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

From: Eli Zaretskii <[email-masked]>
Date: Thu, 19 Jun 2025 09:15:49 +0300

> From: arthur miller <[email-masked]>
> Date: Wed, 18 Jun 2025 22:33:24 +0000
> 
> Currently keymapp returns nil, when passed a symbol if a keymap 
> object is only in a symbol's value slot, but not fbound:
> 
> (keymapp emacs-lisp-mode-map) => t
> (keymapp 'emacs-lisp-mode-map) => nil
> 
> (boundp 'emacs-lisp-mode-map) => t
> (fboundp 'emacs-lisp-mode-map) => nil
> 
> Keymapp uses internally get_keymap to check if an object is a keymap,
> and get_keymap does not check value slot of symbols. However, the
> comment above says:
> 
> "Check that OBJECT is a keymap (after dereferencing through any
>    symbols).  If it is, return it."
> 
> Now, I don't know why is it the case, why the value slot is not
> derefenced. I guess it is by design; after all this time this function
> is in existence, that must be known. I don't understand the reason
> though, by just looking at it at the moment, so I do wonder why is it
> so?
> 
> Anyway, that leaves me in a bit awkward situation where I can ask a
> question: (keymapp some-symbol) and get two different answers:
> 
> (keymapp 'emacs-lisp-mode-map) => nil
> (keymapp 'vc-mode-map) => t
> 
> because one is fbound and the other is not. The background for this is
> that I want to collect all loaded keymaps in the system:
> 
> (defun collect-keymaps ()
>   (cl-loop for k being the symbol when (keymapp k) collect k))
> 
> But I don't get them all, since keymapp won't recognize those that are
> not fbound. That makes the whole thing quite less effective, since I
> have to additionally check if a symbol is bound and if its symbol value
> is a keymap.
> 
> As a suggestion, the attached patch dereferences symbol value slots as
> well. If it is not a wrong thing to do for some reason I am not aware
> of, I would like to suggest it as a "fix" or a "feature request",
> whichever is best describing the issue.
> 
> From c29c8acc75cbd596fe42f5c262fd7d0e8285e87c Mon Sep 17 00:00:00 2001
> From: Arthur Miller <[email-masked]>
> Date: Thu, 19 Jun 2025 00:02:59 +0200
> Subject: [PATCH] Make get_keymap dereference symbol-value slot
> 
> * src/keymap.c (get_keymap):
> Dereference symbol slot and check for a valid keymap.
> ---
>  src/keymap.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/src/keymap.c b/src/keymap.c
> index 2c250578b00..3a1b68a2113 100644
> --- a/src/keymap.c
> +++ b/src/keymap.c
> @@ -197,7 +197,15 @@ get_keymap (Lisp_Object object, bool error_if_not_keymap, bool autoload)
>    if (CONSP (object) && EQ (XCAR (object), Qkeymap))
>      return object;
>  
> -  Lisp_Object tem = indirect_function (object);
> +  Lisp_Object tem;
> +  if (SYMBOLP (object))
> +    {
> +      tem = find_symbol_value (object);
> +      if (CONSP (tem) && EQ (XCAR (tem), Qkeymap))
> +	return tem;
> +    }
> +
> +  tem = indirect_function (object);
>    if (CONSP (tem))
>      {
>        if (EQ (XCAR (tem), Qkeymap))
> -- 
> 2.50.0

Stefan, any comments?

FWIW, the ELisp manual says explicitly:

   -- Function: keymapp object
       This function returns ‘t’ if OBJECT is a keymap, ‘nil’ otherwise.
       More precisely, this function tests for a list whose CAR is
       ‘keymap’, or for a symbol whose function definition satisfies
       ‘keymapp’.

So, unless I'm missing something, the current behavior seems to match
the documentation?