Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elisp: call keymap from code?

Tags:

emacs

elisp

Here's a minimal snippet to get things going:

(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)

Now I can "call" the foo keymap when I press C-M-r. But I wonder how I can do this from code, e.g. something like:

(funcall (lambda-from-keymap 'foo))

After this call, I expect the focus to be in the minibuffer, expecting either a, or b or C-h to be entered. Is something like this possible?

like image 972
abo-abo Avatar asked Jul 23 '14 15:07

abo-abo


2 Answers

You can use read-key-sequence and lookup-key to implement this:

(defun call-keymap (map &optional prompt)
  "Read a key sequence and call the command it's bound to in MAP."
  ;; Note: MAP must be a symbol so we can trick `describe-bindings' into giving
  ;; us a nice help text.
  (let* ((overriding-local-map `(keymap (,map . ,map)))
         (help-form `(describe-bindings ,(vector map)))
         (key (read-key-sequence prompt))
         (cmd (lookup-key map key t)))
    (if (functionp cmd) (call-interactively cmd)
      (user-error "%s is undefined" key))))

If you hit C-h read-key-sequence still waits for you to complete the sequence. I think you could simulate Emacs' normal behaviour by looping with read-key instead, it's a bit more involved though.

Use it like this:

(defun bar () (interactive) (message "you called bar"))
(defun baz () (interactive) (message "you called baz"))

(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)

(defun call-foo ()
  (interactive)
  ;; Note: pass the symbol form of the keymap so we can give nice help
  (call-keymap 'foo "enter a foo command: "))

(global-set-key (kbd "C-c f") 'call-foo)
like image 59
npostavs Avatar answered Sep 22 '22 19:09

npostavs


If the keymap is bound to a key sequence, you can invoke it by emulating the exact key sequence by setting unread-command-events:

(setq unread-command-events
      (mapcar (lambda (e) `(t . ,e))
              (listify-key-sequence (kbd "C-M-r"))
like image 43
Akinori MUSHA Avatar answered Sep 22 '22 19:09

Akinori MUSHA