TIL: Emacs Repeat Maps
I learned about Emacs’ repeat-mode from the dape docs. It’s explained effectively in this blog post by Karthinks. It turns out repeat-mode has recently been added to Emacs core — I’m using 30.0.91, which has a bunch of my favourite recent packages included. It’s a very convenient package. I’m using it with dape, smerge, and flymake, and it really helps cut down on repeated modifiers.
I also discovered that use-package has a neat shorthand for creating repeat maps. Here are my definitions for flymake and smerge:
(use-package smerge-mode
:elpaca nil
:bind
(:repeat-map
josh/smerge-mode-repeat-map
("n" . smerge-next)
("p" . smerge-prev)
("u" . smerge-keep-upper)
("l" . smerge-keep-lower)
("a" . smerge-keep-all)))
(use-package flymake
:elpaca nil
:after project
:config
(setq josh/allowed-flymake-commands
'(("ruff" "--quiet" "--stdin-filename=stdin" "-")))
(put 'python-flymake-command 'safe-local-variable
(lambda (command) (member command josh/allowed-flymake-commands)))
(defun josh/window-bottom-left-side-window-p (buf act)
(with-current-buffer buf (member major-mode '(flymake-diagnostics-buffer-mode))))
(add-to-list 'display-buffer-alist
'(josh/window-bottom-left-side-window-p
(display-buffer-in-side-window)
(window-height . 0.30)
(window-width . 0.55)
(dedicated . t)
(side . bottom)
(slot . 0)
(window-parameters . ((mode-line-format . 'none)))))
(defun josh/hide-flymake-buffer-diagnostics ()
(interactive)
(dolist (buf (buffer-list))
(when (string-prefix-p "*Flymake diagnostics" (buffer-name buf))
(let ((window (get-buffer-window (buffer-name buf))))
(when window
(quit-window nil window))))))
(bind-key "C-c ! l" #'flymake-show-buffer-diagnostics 'flymake-mode-map)
(bind-key "C-c ! n" #'flymake-goto-next-error 'flymake-mode-map)
(bind-key "C-c ! p" #'flymake-goto-prev-error 'flymake-mode-map)
(bind-key "C-c ! q" #'josh/hide-flymake-buffer-diagnostics 'flymake-mode-map)
:bind
(:repeat-map
josh/flymake-repeat-map
("n" . flymake-goto-next-error)
("p" . flymake-goto-prev-error)
("q" . josh/hide-flymake-buffer-diagnostics)
("l" . flymake-show-buffer-diagnostics)))
The :bind (:repeat-map) form is more concise than the vanilla way of creating a repeat map:
(use-package smerge-mode
:elpaca nil
- :config
- (defvar josh/smerge-mode-repeat-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "n") #'smerge-next)
- (define-key map (kbd "p") #'smerge-prev)
- (define-key map (kbd "u") #'smerge-keep-upper)
- (define-key map (kbd "l") #'smerge-keep-lower)
- (define-key map (kbd "a") #'smerge-keep-all)
- map)
- "repeat-mode map for smerge-mode")
+ :bind
+ (:repeat-map
+ josh/smerge-mode-repeat-map
+ ("n" . smerge-next)
+ ("p" . smerge-prev)
+ ("u" . smerge-keep-upper)
+ ("l" . smerge-keep-lower)
The smerge map makes zipping through a diff much more efficient. Instead of “C-c ^ n, C-c ^ u, C-c ^ n, …” I can use “C-c ^ n, u, n, u, l, …”.
See the use-package docs for repeat maps.