Upping my Emacs navigation game

| categories: hydra, emacs | tags:

I have been trying to up my navigation game in Emacs, by which I mean I want to get my cursor where I want it with a minimal number of keystrokes, and preferrably no mouse actions. There are lots of little and big navigations I do a lot:

  1. forward/backward by a character
  2. forward/backward by a word/subword
  3. forward/backward by a sentence
  4. forward/backward by a line
  5. to the beginning and end of a line
  6. to the beginning and end of a sentence
  7. to the beginning and end of a paragraph
  8. to the beginning and end of a page
  9. to the beginning and end of a buffer
  10. scrolling up/down
  11. into another window
  12. back and forth to buffers

Occasionally, I want to save a location so I can easily get back to it. Not all of these are strictly speaking navigation in the usual sense, but they are things I do often enough. There are Emacs commands for all these, and keyboard shortcuts for many of them, but I don't use them often, and as a result I don't remember them either.

Here I develop a hydra that will provide these features. Hydra is a super amazing, menu prompting system that provides hints to remind you of what can be done, and to access it from a character. It is possible to pass numeric and universal arguments to the commands by typing -, a number, or C-u before pressing the character.

I want some commands to be repeatable, which we get with a "red" hydra, and some commands to exit on running, which we get with a "blue" head. So, here is an over-the-top hydra for navigation.

(defhydra hydra-navigate (:color red
                          :hint nil)
  "
_f_: forward-char       _w_: forward-word       _n_: next-line
_b_: backward-char      _W_: backward-word      _p_: previous-line
^ ^                     _o_: subword-right      _,_: beginning-of-line
^ ^                     _O_: subword-left       _._: end-of-line

_s_: forward sentence   _a_: forward paragraph  _g_: forward page
_S_: backward sentence  _A_: backward paragraph _G_: backward page

_h_: helm mini _B_: buffer list _i_: window
_<left>_: previous buffer   _<right>_: next buffer
_<up>_: scroll-up           _<down>_: scroll-down

_[_: backward-sexp _]_: forward-sexp
_<_ beginning of buffer _>_ end of buffer _m_: set mark _/_: jump to mark
"
  ("f" forward-char)
  ("b" backward-char)
  ("w" forward-word)
  ("W" backward-word)
  ("n" next-line)
  ("p" previous-line)
  ("o" subword-right)
  ("O" subword-left)
  ("s" forward-sentence)
  ("S" backward-sentence)
  ("a" forward-paragraph)
  ("A" backward-paragraph)
  ("g" forward-page)
  ("G" backward-page)
  ("<right>" next-buffer)
  ("<left>" previous-buffer)
  ("h" helm-mini :color blue)
  ("i" ace-window :color blue)
  ("m" org-mark-ring-push)
  ("/" org-mark-ring-goto :color blue)
  ("B" helm-buffers-list)
  ("<up>" scroll-up)
  ("<down>" scroll-down)
  ("<" beginning-of-buffer)
  (">" end-of-buffer)
  ("." end-of-line)
  ("[" backward-sexp)
  ("]" forward-sexp)
  ("," beginning-of-line)
  ("q" nil "quit" :color blue))

(global-set-key (kbd "s-n") 'hydra-navigate/body)
hydra-navigate/body

I basically like it. The menu is a little on the large side, but it makes for easy modal navigation in a buffer, to other windows, and other buffers. On the whole for moderate cursor movements, this results in basically equal keystrokes. For example, to move 3 characters forward, we have C-f C-f C-f or C-u 3 C-f, or s-n 3 f. The advantage (I think) is a single interface to all these navigation commands with hints on what to do.

There is still another level of navigation, which is related to navigation by searching. That is a whole different level of navigation I will work on another day!

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter