11

I've run into a few situations where it would be highly convenient to have to have the keymap of one major-mode act as a fallback keymap for another major-mode. For instance:

  • I write a lot of LaTeX in some of my org documents, so it would be great to have latex-mode commands easily available while editing org-mode.
  • I frequent an irc room with Markdown support, so it would also be nice to have markdown-mode keybinds added to erc-mode.

In both cases this extra keymap should act as a fallback (this why I can't just use a minor mode for this). I don't want latex commands to override any org-mode keys. What I want is:
If a key is defined in latex-mode-map AND it is not defined in org-mode-map then use the latex-mode-map binding.

Q: How can I set a keymap as a fallback keymap for a major-mode?
OR
Q: How can copy keys from one major-mode-map to another, without overriding anything?


Just to be clear. I know I could define these keys one by one, but it would be infinitely more convenient to have an automated solution.

  • 6
    Use a keymap merge. See make-composed-keymap. – Drew Nov 29 '14 at 1:55
12

This turned out to be simpler then expected. As suggested in the comments here and on the question:

(with-eval-after-load 'erc
  (require 'markdown-mode)
  (require 'cl-lib)
  (setq erc-mode-map
        (make-composed-keymap (cl-copy-list erc-mode-map)
                              markdown-mode-map)))

This will create a keymap which is a copy of erc-mode-map but which also inherits from markdown-mode-map. So all markdown keys will be shadowed whenever they collide with erc keys.

If you do want some keys of the fallback keymap to outshine the main kemap, just disable them in main one.

(define-key erc-mode-map "\C-c\C-a" nil)
  • 2
    I've noticed that using define-key on the return value of make-composed-keymap can have unexpected side effects on the original keymaps, and I suspect the same might apply to this manually appended map. If you want to use define-key, it seems to be safest to create a new keymap whose parent keymap is a composed keymap. – Jon O. Nov 30 '14 at 19:02
  • @JonO. Actually, I was very surprised to find out this does not happen here. If I do (define-key erc-mode-map "\C-c\C-s" nil), the corresponding markdown-mode key will still be available even in erc buffers. – Malabarba Dec 1 '14 at 0:47
  • Malabarba: I believe your last comment no longer applies after that code change. The make-composed-keymap documentation says "a nil binding in MAPS overrides any corresponding binding in PARENT, but it does not override corresponding bindings in other keymaps of MAPS." As markdown-mode-map is PARENT in your example, I would expect that nil binding to inhibit the markdown binding? – phils Dec 1 '14 at 1:19
  • 2
    My interpretation is that (make-composed-keymap (list erc-mode-map markdown-mode-map)) would have the effect you'd described, however? – phils Dec 1 '14 at 2:53
  • 1
    cl-copy-list will not really do what you want. If you wanted to copy the keymap, then you should have used copy-keymap. – Stefan Jul 14 '16 at 12:50
3

As mentioned by @Malabarba, you can use make-composed-keymap for that. But If you really want the new keymap to inherit from both keymaps, such tht modifying the new keymap doesn't affect any of the other two keymaps, you need to do it in two steps:

(make-composed-keymap
 nil (make-composed-keymap (list erc-mode-map markdown-mode-map)))

This is because define-key can sometimes modify the maps passed as first argument of make-composed-keymap but not those passed as second. I guess you should M-x report-emacs-bug and request that make-composed-keymap accept a list of keymaps as second argument, so you could just do

(make-composed-keymap nil (list erc-mode-map markdown-mode-map))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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