4

Suppose, I have some keymap bound to a key prefix, e.g. help-map bound to C-h. However, suppose also that I don't know what the prefix is. It might be C-h, it might be C-x h, it might be just C-? or something else.

How do I learn (preferably, non-interactively) what the key prefix is?

where-is only works for definitions, not keymaps, alas.

1 Answer 1

3

Looking at the definition of define-prefix-command we find that a prefix is created by assigning the map to the function cell of a symbol (via fset). From this, we conclude that a prefix is actually a map bound to a command. From the same definition, we find that the map additionally is assigned to (in that function) either MAPVAR or COMMAND. If it is bound to COMMAND then we can find the map with where-is. Otherwise, we first have to find out to which command the map has been assigned, and subsequently call where-is passing the command as argument (e.g for help-map) as follows:

(mapatoms (lambda (s)
            (when (equal (symbol-function s) help-map)
              (where-is s)))
          obarray)

EDIT in response to your comments

If the map is bound directly via define-key, then I guess, because the keymap is bound directly (not its symbol, which gets evaluated first), there is no direct way to retrieve the map's binding.

However, you can lookup the prefixes of the bindings to the commands within the map as follows

(map-keymap
 (lambda (ev def)
   (if (keymapp def)
     (eq (where-is def))))
 help-map)

If only a single keymap is bound within the map, then you could modify the code so that it additionally searches within that keymap.

I guess it should be possible, and not difficult, to create a recursive function to search down the keymaps from the global keymap and filter for the 'target' map as in:

(map-keymap
 (lambda (ev def)
   (when (equal def help-map)
     (print (string ev))))
 ctl-x-map)

but I have not tried it (it can go wrong if there exist some recursive keymap definitions).

Finally, the conclusion is that, if you want keymaps to be discoverable, then use define-prefix-command and bind the command (not the value of the created variable) created with that function.

END EDIT

9
  • Thanks a lot! The answer is very helpful to understand what is happening. It prompted me to explore more within the keybinding-related definitions and I found an arguably more elegant solution using where-is-internal: (mapcar #'key-description (where-is-internal help-map)). Would you consider to include that in your answer? Or do you think, given that it's rather different, that it warrants a separate answer by me?
    – Artem Yu
    Commented Jan 5 at 23:16
  • @ArtemYu (mapcar #'key-description (where-is-internal help-map)) returns nil for me and nothing gets printed. What exactly do you get?
    – NickD
    Commented Jan 6 at 2:23
  • Huh. I'm getting ("C-x h"). I assume, due to the fact that I reassigned it. On emacs -Q, I'm also getting nil.
    – Artem Yu
    Commented Jan 6 at 2:52
  • Meanwhile, the method from the answer gives me <f1, <help> but not C-x h... So, the methods are kind of complementary, but it's not immediately clear to me why
    – Artem Yu
    Commented Jan 6 at 2:54
  • How did you reassign it? Please update your question with that information.
    – NickD
    Commented Jan 6 at 3:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.