Emacs: Type Last Key to Repeat
Published on: 2013-06-03
My Emacs configuration most comprises of bits I got here and there
from several different packages, blogs, githubs, etc. There’s not a
whole lot of original ideas in there, but there’s this one thing I
haven’t seen anyone doing which I found pretty neat. The
kmacro-end-and-call-macro
command on Emacs, normally bound to
C-x e
, will repeatedly call the macro if you keep pressing e
. When
I first wrote a function for duplicating a line, I wanted to bind it
to C-c c
and be able to repeatedly press c
after that to keep
duplicating the line without typing the whole key sequence over and
over, just like the kmacro-end-and-call-macro
command is.
I looked at the implementation of kmacro-end-and-call-macro
and
managed to extract the bits responsible for doing the repetition by
key. When I went to write my duplicate line function, suddenly I could
thing about a whole lot of functions that would be nicer with the same
behavior. Hence, I came up with the following elisp macro:
(defmacro kao/type-last-key-to-repeat (&rest body)
"Repeat body when typing the last key on the key sequence used
to call the enclosing command."
(declare (indent defun))
`(progn
(progn ,@body)
(let* ((repeat-key last-input-event)
(repeat-key-str (format-kbd-macro (vector repeat-key) nil)))
(while repeat-key
(message "(Type %s to repeat.)" repeat-key-str)
(if (equal repeat-key (read-event))
(progn
(clear-this-command-keys t)
(progn ,@body)
(setq last-input-event nil))
(setq repeat-key nil)))
(when last-input-event
(clear-this-command-keys t)
(setq unread-command-events (list last-input-event))))))
Basically, I can wrap any code I want with this and make it repeatable by typing the last key in the key sequence of the command. My duplicate line function ended up like this:
(defun duplicate-line (times)
"Duplicates the current line."
(interactive "p")
(kao/type-last-key-to-repeat
(save-excursion
(dotimes (ignored times)
(end-of-line)
(insert "\n" (replace-regexp-in-string "\n" ""
(thing-at-point 'line)))))))
And I did some things like this:
(defun repeatable-enlarge-window (size)
"Like enlarge-window, but repeats if you keep pressing the last key in the command shortcut"
(interactive "p")
(kao/type-last-key-to-repeat (enlarge-window size)))
You should be able to apply it to any command that you want and it should work. It’s pretty neat!