Home - Blog - Wiki -

Repeating Navigation in Emacs

A few weeks ago I was getting somewhat annoyed while navigating with a wild set of combinations of C-n, C-n, M-f, M-f and whatnot through an org-document that I had been working on, and wondered why there isn't a simpler way to do that. Something that could for example make the C or M stick of sorts.

This being Emacs, I was thinking there had to be a solution. I did some search but couldn't really find something that did just what I had been looking for (then again, I didn't know what to look for).

I ended up trying EVIL-Mode and God-Mode and even though the latter did work well for me (the former confused me too much) neither did what I really wanted to. Somehow switching to another mode only to navigate a little more efficient seemed overkill.

That being said, I did use God-Mode for a while, until I learned about the Repeat-Mode introduced in Emacs via Karthinks and with this found the solution!

I ended up with this code which does exactly what I wanted to: I invoke the motion I want to use, say M-b to move back a word and then happily continue moving backwards pressing only b.

Even though there is likely a much more elegant solution to write this code, it works and best of all, I did it myself (more or less that is :-) ).

Here's the snippet I came up with:

    (repeat-mode t)


(defvar svbck-nav-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "f") #'forward-char)
    (define-key map (kbd "b") #'backward-char)
    (define-key map (kbd "n") #'next-line)
    (define-key map (kbd "p") #'previous-line)
    (define-key map (kbd "a") #'backward-sentence)
    (define-key map (kbd "e") #'forward-sentence)
    map))

(dolist (cmd '(forward-char backward-char next-line previous-line backward-sentence forward-sentence))
  (put cmd 'repeat-map 'svbck-nav-repeat-map))


(defvar svbck-word-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "f") #'forward-word)
    (define-key map (kbd "b") #'backward-word)
    map))

(dolist (cmd '(forward-word backward-word))
  (put cmd 'repeat-map 'svbck-word-repeat-map))


(defvar svbck-org-sentence-repeat-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "a") #'org-backward-sentence)
    (define-key map (kbd "e") #'org-forward-sentence)
    map))

(dolist (cmd '(org-backward-sentence org-forward-sentence))
  (put cmd 'repeat-map 'svbck-org-sentence-repeat-map))


I tried to combine this into one repeat-map but that didn't work out that well since some of the keys are the same, hence I did one for each, then again it works this way.

Upadate 2022-12-10 11:15: In the meanwhile I figured out how to make the code a little bit more compact, but I'm sure it could be improved more.

Reply via Email