6

Emacs' source code contains multiple instances of using fset with a keymap.

For example, in ediff-util.el:

;; Allow ediff-mode-map to be referenced indirectly
(fset 'ediff-mode-map ediff-mode-map)

Or in esh-mode.el:

(fset eshell-command-prefix (make-sparse-keymap))

Or compile.el:

(defvar compilation-button-map
  (let ((map (make-sparse-keymap)))
    (define-key map [mouse-2] 'compile-goto-error)
    (define-key map [follow-link] 'mouse-face)
    (define-key map "\C-m" 'compile-goto-error)
    map)
  "Keymap for compilation-message buttons.")
(fset 'compilation-button-map compilation-button-map)

I've found examples in third-party elisp projects too, such as projectile. I've looked at the creating keymaps documentation but I can't find anything relevant.

These values cannot even be called as functions:

ELISP> (compilation-button-map)
*** Eval error ***  Invalid function: compilation-button-map

What's the purpose of setting the function slot of a symbol with a keymap? Where is it documented?

Drew
  • 75,699
  • 9
  • 109
  • 225
Wilfred Hughes
  • 6,890
  • 2
  • 29
  • 59

2 Answers2

4

There's nothing new or unusual about this. This is how prefix keys work. They are bound to a keymap -- or they are bound to a symbol whose value or whose function definition is a keymap.

The Elisp manual node Prefix Keys tells you this:

The keymap binding of a prefix key is used for looking up the event that follows the prefix key. (It may instead be a symbol whose function definition is a keymap. The effect is the same, but the symbol serves as a name for the prefix key.) Thus, the binding of C-x is the symbol Control-X-prefix, whose function cell holds the keymap for C-x commands. (The same keymap is also the value of [variable] ctl-x-map.)

Drew
  • 75,699
  • 9
  • 109
  • 225
1

This was news to me. After doing some experiment it looks like it allows you to refer to a keymap by name.

(defun my-test () (interactive) (message "TEST TEST"))
(defvar my-test-mode t)
(defvar my-test-map (make-sparse-keymap))
(define-key my-test-map (kbd "C-c q") 'my-test)
(add-to-list 'minor-mode-map-alist '(my-test-mode . my-test-map))

If you press C-c q, Emacs informs that they binding is undefined.

Add the following:

(fset 'my-test-map my-test-map)

Now, the key binding is working.

My guess is that when the key lookup code find a symbol it looks at its function definition. If that looks like a keymap it will use it.

Note: You don't need to add a key binding by name. The standard way to add a keymap is by value:

(add-to-list 'minor-mode-map-alist (cons 'my-test-mode . my-test-map))

This will include the value of my-test-map. Since all functions binding keys destructively change the keymap, the change will take effect both in my-test-map and minor-mode-map-alist. The only drawback is that if you reinitialize the keymap variable, the old value will still be in minor-mode-map-alist. Effectively, it would appear as though new bindings wouldn't work.

Lindydancer
  • 6,095
  • 1
  • 13
  • 25