Open marczz opened 2 years ago
I got stuck in a very similar place as you, and ultimately found the explanation here. I too wonder if the documentation could be amended to show an example where a description is provided and a key is bound to a non-trivial keymap.
Suppose for example I have already constructed a keymap, and it is referred to by the symbol some-prefix-map. Then, if I understand correctly, the examples could read
(define-key some-map "f" '("foo" . command-foo))
(define-key some-map "b" (cons "bar-prefix" some-prefix-map))
and
(define-key some-map "f" 'long-command-name-foo)
(define-key some-map "b" some-prefix-map)
(which-key-add-keymap-based-replacements some-map
"f" '("foo" . long-command-name-foo)
"b" (cons "bar-prefix" some-prefix-map))
At the same time, I still can't quite wrap my head around how this is working on a deep level. My understanding is that the correct usage is to pass a BINDING
that is a cons whose car is a descriptive string and whose cdr is a keymap (literally a keymap, not a symbol referring to a keymap). My understanding is that BINDING
should get processed according to this logic, and to my naive eyes it looks the cons cell as passed would fall under the "anything else" category (the cons is a list, but its car is neither the symbol keymap
nor lambda
).
The elisp manual is not so clear about define-key, it only says
The argument BINDING can be any Lisp object, but only certain types are meaningful. (For a list of meaningful types, see *note Key Lookup::.)
If it was so, as you say, we should find the cons under the "anything else" category, and it does not fit there.
But if you look at the docstring of define-key, in the description of (define-key KEYMAP KEY DEF)
a list of possible values for DEF is given among which you find:
a cons (STRING . DEFN), meaning that DEFN is the definition (DEFN should be a valid definition in its own right),
We just use that and so for DEFN we have the choice between a command, a string treated as a keyboard macro, a keymap, a symbol which stands for its function definition.
In my first example and in your examples the CDR of the cons is a keymap.
In my second example I use a symbol, but the value slot cannot be used directly, because the symbol stands for its function definition.
So I fill also the function slot with (fset 'testmap testmap)
.
A keymap is a list with the symbol keymap
as its CAR
(doc). Therefore, (testmap)
is not a keymap. That's one issue. By the way you can use make-sparse-keymap
if you like (doc).
You also have to pay attention to what the DEF
is evaluating to. In the case of commands, you want the DEF
to evaluate to a symbol pointing to a command. In the case of keymaps, you want the DEF
to evaluate to the underlying keymap list/object, not to a symbol pointing to the keymap (doc).
Some examples might help
This works, because the DEF
evaluates to a keymap object.
(define-key parent-map "k" '(keymap))
This doesn't work, because the DEF
evaluates to a symbol pointing to a keymap object.
(setq testmap '(keymap))
(define-key parent-map "k" 'testmap)
This works again. Note the quotation.
(setq testmap '(keymap))
(define-key parent-map "k" testmap)
This doesn't work, because (testmap)
is not a keymap object (it is not a list beginning with the keymap
symbol).
(define-key parent-map "k" '(testmap))
Now, adding the CONS
form to name the definition follows the same rules. You just have to make sure that the CDR
evaluates to a keymap as before. This will work
(define-key parent-map "k" '("name" . (keymap)))
This will not
(define-key parent-map "k" '("name" . '(keymap)))
This will not work, because DEF
evaluates to ("name" . testmap)
and testmap
is not a keymap object (it is a symbol pointing to one).
(setq testmap '(keymap))
(define-key parent-map "k" '("name" . testmap))
This will work again, because cons
evaluates both of its arguments before constructing the new CONS
form.
(setq testmap '(keymap))
(define-key parent-map "k" (cons "name" testmap))
Thank you Justin, the added example in 1692a1e will help to understand the syntax. The way of understanding examples is subjective, and your mileage may vary, but I still find confusing the wording of
(define-key some-map "b" '("bar-prefix" . (keymap)))
What is the meaning of keymap
here? If it is the literal symbol keymap
that constitute the car of any keymap we should rather write:
(define-key some-map "b" '("bar-prefix" . (keymap ...)))
If it designates any keymap the parentheses are not relevant because the keymap is yet a cons, so the parentheses are included in the keymap. In this case i would rather write it:
(define-key some-map "b" '("bar-prefix" . <some keymap>))
The use of angle brackets to designate an arbitrary parameter is a posix convention, with an alternative of words separated by underlines, usually in italic.
But the main thing is by writing <some keymap>
or some_keymap
or an-other-map
like you have used some-map
the user understand that it is a generic slot to be filled with the corresponding object.
This may be quite pernickety, and the added example should dispel any confusion
In the examples that I gave in my initial post, I omitted define-prefix-command
which is equivalent to the use of fset
but more elegant, with it you would write:
(define-prefix-command 'testmap)
(define-key global-map [?\C-:] '("test map" . testmap))
Such an example might be added in the README.
I could not achieve custom string replacement as shown in the custom string replacement section
Consider the following keymap:
With this test which key gives for the top level "C-:" : "C-: -> +prefix", and for "C-:" itself "a -> lambda".
Lets try to improve that:
Now on "C-:" which-key display "a -> a key".
Now for the keymap, if I follow the custom string replacement section I try:
I get when entering "C-:"
(wrong-type-argument commandp (testmap))
of course if I replace the cdr by testmap it is also wrong because testmap is a variable whose value is not a command, but a keymap.I have few ways of solving this either one of the following works as expected:
But the documentation seems as least ambiguous on what is meant by
(keymap)