According to the define-key docstring, binding a key to a cons (MAP . CHAR) should cause that key to act as CHAR in MAP. However, I cannot get this to work. For example, evaling this and trying to use the keybinding gives the error Wrong type argument: commandp ...:

(defvar my-temp-map (make-sparse-keymap))
(define-key my-temp-map "a" #'next-line)
(define-key emacs-lisp-mode-map (kbd "C-a") (cons my-temp-map ?a))

I've tried on emacs 25 and 26 and have also tried quoting the keymap name. Am I doing this wrong or does it just not work? I realize that the same effect could be achieved in other ways, but I'm curious about whether this specific format of definition is actually possible.

1 Answer 1

(define-prefix-command 'my-temp-map)

(Or (fset 'my-temp-map my-temp-map), since you've already created the sparse keymap.)

The point is that you need to not only create the keymap for the prefix key. You also need to give the symbol whose symbol-value is the keymap a symbol-function value that is the same map. my-temp-map needs to be a function, to act as a prefix keymap. A bit weird, but that's how Emacs prefix keys work.

See the Elisp manual, node Prefix Keys.

Update after the comments

I didn't mean to suggest that I was answering how to use a cons value as the third arg to define-key. I meant to suggest that you just use your prefix-key map normally, as a prefix key.

This is, in effect, what I was suggesting:

(define-prefix-command 'my-temp-map)
(define-key my-temp-map "a" #'next-line)
(define-key emacs-lisp-mode-map (kbd "C-a") 'my-temp-map)

That makes C-a a in emacs-lisp-mode-map invoke next-line. I thought that was all you really were after: how to make C-a a prefix key, with its own keymap.

But no, this does not really respond to your question about using a cons for the 3rd define-key arg.

It gives you the behavior that I guessed you were really after. But be aware that it also puts any other keys in my-temp-map onto emacs-lisp-mode-map following prefix key C-a.

I think I've never tried to use a cons as the third arg to define-key.

The doc seems to be saying that it should, in this case, make C-a a invoke next-line in emacs-lisp-mode but it should not also make C-a b invoke whatever b might be bound to in my-temp-map. It doesn't say that explicitly, but that's my guess, since it says only that the given CHAR is bound, not that the whole map is bound as a prefix keymap. And that's the only use I can think of for this feature, which I think I never noticed.

(I'm a bit surprised now that I never noticed and tried that.)

I agree with Stefan that it looks like there is a bug here, in that what the doc describes doesn't seem to work.

Actually, it used to work - so the bug is a regression.

Your code works perfectly in Emacs 20, Emacs 22, and Emacs 23:

(defvar my-temp-map (make-sparse-keymap))
(define-key my-temp-map "a" #'next-line)
(define-key emacs-lisp-mode-map (kbd "C-a") (cons my-temp-map ?a))

When I check the result, using C-h M-k (library help-fns+.el), this is what I see:


Keymap for Emacs Lisp mode.
All commands in `shared-lisp-mode-map' are inherited by this map.

key             binding
---             -------

C-a             next-line
ESC             Prefix Command
DEL             backward-delete-char-untabify

ESC C-x         eval-defun
ESC TAB         lisp-complete-symbol
ESC C-q         indent-sexp

And when I hit C-a in emacs-lisp-mode command next-line is indeed invoked.

But in Emacs 24.5 I get this error from describe-key for C-a (same error message if I just hit C-a):

Debugger entered--Lisp error: (error "Wow, indirect keymap entry!!")
  read-key-sequence("Describe key (or click or menu item): ")

(Not a very helpful error message, in any case.)

Please consider filing a bug report: M-x report-emacs-bug.

  • Thanks. Since the define-key docstring talks about symbol keybindings just before, it's kind of weird that it calls MAP a keymap if it should actually be a symbol. Weird, but I guess it makes sense over actually including a keymap in the definition.
    – noctuid
    Commented Nov 6, 2017 at 5:00
  • 1
    @noctuid <f1> f kemapp: "A keymap is [...] a symbol whose function definition is itself a keymap"
    – npostavs
    Commented Nov 6, 2017 at 12:55
  • I think Drew is too generous to Emacs: this looks like a plain bug (I don't think there's a good reason to impose that the CAR needs to be a symbol rather than allowing actual keymap values in there. This said, I'm sad that this actually works: if it didn't, then we could have removed this unused feature.
    – Stefan
    Commented Nov 6, 2017 at 14:04
  • @npostavs That's just one thing that satisfies keymapp. A literal keymap (list) does not work in this instance which is why a distinction would make sense.
    – noctuid
    Commented Nov 6, 2017 at 15:29
  • @Stefan It seems like it could be useful. That said I actually still can't get it to work even after making my-temp-map a prefix command.
    – noctuid
    Commented Nov 6, 2017 at 15:34

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.