repeatable-lite: Make Any Prefix Command Repeatable
Table of Contents
1. About emacs keybindings productivity
Figure 1: JPEG produced with DALL-E 4o
Emacs loves prefix keys. C-x, C-c, C-c w, C-c p … the deeper your configuration goes, the longer your prefixes get. The problem is that many commands you'd want to call repeatedly sit behind these prefixes: window navigation, text scaling, buffer cycling. You end up typing the same prefix over and over. repeatable-lite fixes this in about 230 lines. Wrap a command with repeatable-lite-wrap and after the first invocation, the prefix stays active. Press the final key again to repeat. Press anything else to exit.
2. The Prefix Problem emacs problem
Say you've bound window navigation to C-c w h/j/k/l:
(global-set-key (kbd "C-c w h") #'windmove-left) (global-set-key (kbd "C-c w l") #'windmove-right) (global-set-key (kbd "C-c w j") #'windmove-down) (global-set-key (kbd "C-c w k") #'windmove-up)
You want to move two windows left. That's C-c w h C-c w h, eight keystrokes for two moves. Navigate through a four-window layout and you're pressing C-c w four times. The prefix is supposed to organize your keybindings, but under repetition it becomes dead weight.
The prefix is supposed to organize your keybindings, but under repetition it becomes dead weight.
Emacs has repeat-mode (built-in since Emacs 28), which solves this for built-in commands. But it requires you to define repeat-map keymaps manually for every group of commands, and it doesn't integrate with which-key to show what's available. hydra and transient are more powerful but heavier, with their own configuration DSLs and display systems. repeatable-lite sits in the gap: one macro, automatic which-key integration, no configuration language.
3. How It Works emacs implementation
The API is a single macro: repeatable-lite-wrap. It takes a function name and returns a new command that:
- Calls the original function.
- Re-activates the prefix keymap.
- Shows which-key with all available keys in that prefix.
- Reads the next key and dispatches it:
- If it's bound in the prefix keymap, execute it and loop.
- If it's
C-h, show help and continue. - If it's
C-u, accumulate prefix arguments and continue. - If it's anything else, exit the loop and feed the key back to normal command dispatch.
(global-set-key (kbd "C-c w h") (repeatable-lite-wrap windmove-left)) (global-set-key (kbd "C-c w l") (repeatable-lite-wrap windmove-right)) (global-set-key (kbd "C-c w j") (repeatable-lite-wrap windmove-down)) (global-set-key (kbd "C-c w k") (repeatable-lite-wrap windmove-up))
Now C-c w h h h moves three windows left, six keystrokes saved. And because which-key appears immediately after the first command, you can see all the other keys in the C-c w prefix without memorizing them.
3.1. Which-Key Integration
repeatable-lite configures which-key for optimal display during the repeatable loop. It saves your current which-key settings, enables persistent popup mode, and sets aggressive idle timers (0.1 seconds) so the guide appears instantly. When you exit the loop, all settings are restored to their previous values.
This means which-key acts as a live reference while you're in the repeatable state. You don't need to remember every key in the prefix, you just need to know one, and the popup shows you the rest.
5. Getting Started emacs installation
repeatable-lite is on GitHub. It requires Emacs 30.1+ (which-key is built-in since 30.1).
(use-package repeatable-lite :ensure (:host github :repo "chiply/repeatable-lite") :config (repeatable-lite-mode 1))
Then wrap any commands you want to make repeatable. Here's a fuller example using general.el:
(general-define-key "C-c w h" (repeatable-lite-wrap windmove-left) "C-c w l" (repeatable-lite-wrap windmove-right) "C-c w j" (repeatable-lite-wrap windmove-down) "C-c w k" (repeatable-lite-wrap windmove-up) "C-c w =" (repeatable-lite-wrap enlarge-window-horizontally) "C-c w -" (repeatable-lite-wrap shrink-window-horizontally))
Every command under C-c w becomes repeatable. Type the prefix once, then just the final key. When you're done, press anything outside the keymap and you're back to normal.