HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Keys in mode maps

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
keysmodemaps

Problem

I noticed a pattern in some elisp modes I was putting together:

(let ((map (make-sparse-keymap)))
  (define-key map KEY 'FN)
  ...
  (setq FOO map))


so I wrote up the following macro

(defmacro def-sparse-map (name &rest key/fn-list)
  `(let ((map (make-sparse-keymap)))
     ,@(loop for (key fn) on key/fn-list by #'cddr
         collecting `(define-key map ,key ',fn))
     (setq ,name map)))


which lets me write

(def-sparse-map FOO
  KEY FN
  ...)


instead. All comments welcome, but some specific questions are

  • Can this be done more cleanly (and more generally, is it acceptable practice to use the ported CL functions when defining Elisp modes)?



  • Are there some issues I'm not seeing with that use of let/setq?



  • Is it worth it writing up an elisp with-gensyms to keep map from being bound externally?



and most importantly

  • Is there an Elisp primitive that does the same thing, or close to it?

Solution

General notes

  • Standard modes are not supposed to use cl. This, in practice, leads to more code duplication than it saves memory (a lot of third-party modes or user init files use cl anyway). So don't worry about using it unless you're really intent on having your package integrated into GNU Emacs.



  • Yes, using the map symbol in this way will interfere a use of map outside your macro. That's what gensym is for.



My approach

You don't need a complex macro here.

(defun inaimathi-make-keymap (&rest bindings)
  "Make a sparse keymap containing the specified bindings"
  (let ((map (make-sparse-keymap)))
    (while (consp bindings)
      (define-key map (car bindings) (car (cdr bindings)))
      (setq bindings (cdr (cdr bindings))))
    map))
(defmacro inaimathi-defmap (symbol docstring &rest bindings)
  "Define a keymap called SYMBOL, with a DOCSTRING.
Populate the keymap with BINDINGS by building it with `inaimathi-make-keymap'"
  `(progn
     (defvar ,symbol nil ,docstring)
     (setq map (inaimathi-make-keymap . ,bindings))))
(inaimathi-defmap some-map "Keymap for some mode."
  "\C-c\C-a" 'do-something
  "\C-c\C-z" 'do-something-else)

Code Snippets

(defun inaimathi-make-keymap (&rest bindings)
  "Make a sparse keymap containing the specified bindings"
  (let ((map (make-sparse-keymap)))
    (while (consp bindings)
      (define-key map (car bindings) (car (cdr bindings)))
      (setq bindings (cdr (cdr bindings))))
    map))
(defmacro inaimathi-defmap (symbol docstring &rest bindings)
  "Define a keymap called SYMBOL, with a DOCSTRING.
Populate the keymap with BINDINGS by building it with `inaimathi-make-keymap'"
  `(progn
     (defvar ,symbol nil ,docstring)
     (setq map (inaimathi-make-keymap . ,bindings))))
(inaimathi-defmap some-map "Keymap for some mode."
  "\C-c\C-a" 'do-something
  "\C-c\C-z" 'do-something-else)

Context

StackExchange Code Review Q#2284, answer score: 3

Revisions (0)

No revisions yet.