6

In my emacs setup, I currently have two key bindings: C-C c i for command1 and C-c c j for command2. command1 outputs some text in the minibuffer while command2 insert the same text in the current buffer.

I am wondering if there's a way to bind command1 to C-c c (so my output appears in messages), but then if j is pressed after that, command2 is executed (inserting the same text in the buffer).

6

You could use a transient key map to do this:

(defun my-fun ()
  (interactive)
  (let ((mes "Important data")
        (map (make-sparse-keymap)))
    (define-key map "j" (lambda () (interactive) (insert mes))) 
    (message mes)
    (set-transient-map map)))

Here, I define a new keymap map, and give it a single binding for the key j. After I display the message, I turn on the transient map, which is active for the next key combination. If that key combination is the letter j, it calls the function to insert your data into the buffer. Any other key combination gets passed on to the other active keymaps. After that the transient map is removed and you're back to normal.

| improve this answer | |
  • Thanks, I understand the idea! Although, I am getting Symbol’s value as variable is void: mes from your code. EDIT: I think I got it. Seems to require lexical-binding being set to true. – Tohiko Jul 23 '19 at 14:35
  • Interesting. It doesn't seem to matter for me, using Emacs 27.0.50. – Tyler Jul 23 '19 at 14:54
3

You can use a transient map for this. A transient map is a keymap that is only active for a single keypress, and lets keys not in the keymap "fall through", and do their normal behavior.

This code inserts "command2" when command2 is run. When command1 is run, it prints a message into the minibuffer. Then, if you press j, it calls command2. If you instead press anything else, it does the normal behavior. So if you run M-x command1, then press k, a k is inserted into the buffer.

(defun command2 ()
  (interactive)
  (insert "command2"))

(defun command1 ()
  (interactive)
  (message "command 1")
  (set-transient-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "j") #'command2)
     map)))
| improve this answer | |
0

Here's my solution. I wrote a wrapper for the second command that, after executing the command 2, will listen for the next key press, and if that's a j, execute command 1.

(defun my/command-1()
  (interactive)
  (message "command 1"))

(defun my/command-2()
  (message "command 2"))

(defun my/command-2-wrapper()
  (interactive)
  (my/command-2)
  (let ((event (char-to-string (read-event))))
    (if (equal event "j")
        (my/command-1)
      (setq unread-command-events (listify-key-sequence event)))))
| improve this answer | |

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.