Do you know the Emacs package Hydra? I tried it today, and I loved the way it changed my workflow. I was bragging about it to everyone at work, so I decided to write a blog post. That way I can show more people how fabulous it is :D
What is Hydra? Why should I use it?
Hydra makes it easier to execute a set of commands in succession by shortening the key bindings. A showcase of it pretty much describes it, so here it is!
Example 1: Window management
Let's say that I want to split a window into 4 with equal size, I would need to run the following key strokes.
C-w v ; split vertically C-w s ; split horizontally C-w l ; navigate to the left window C-w s ; split horizontally
When I use Hydra the key strokes becomes like this.
C-w ; start hydra v ; split vertically s ; split horizontally l ; navigate to the left window s ; split horizontally

Example 2: Navigating and changing Org mode headlines
I use Org Mode a lot. Even this blog is made by Org mode! I tend to navigate between headlines, and change headline levels after navigating.

How do you set it up?
Everything is pretty much explained in the Hydra docs, but I'll write out some of my ah-ha moments.
But first, this is my complete windows setup.
(defhydra hydra-window (:hint nil)
"
| Navigation^^ | Placement^^ | Create, Delete^^ | Adjustment^^ |
|^^-----------------+^^-------------------+^^-------------------------+^^--------------------|
| _h_: go left | _H_: move to left | _v_: split vertically | _=_: balance windows |
| _j_: go down | _J_: move to bottom | _s_: split horizontally | _+_: increase height |
| _k_: go up | _K_: move to top | _q_: delete window | _-_: decrease height |
| _l_: go right | _L_: move to right | _Q_: delete other windows | _>_: increase width |
| _w_: go to next | ^^ | ^^ | _<_: decrease width |
| _C-w_: go to next | ^^ | ^^ | ^^ |
"
("+" evil-window-increase-height)
("-" evil-window-decrease-height)
("<" evil-window-decrease-width)
(">" evil-window-increase-width)
("=" balance-windows)
("C-w" evil-window-next nil :color blue)
("H" evil-window-move-far-left)
("J" evil-window-move-very-bottom)
("K" evil-window-move-very-top)
("L" evil-window-move-far-right)
("h" evil-window-left)
("j" evil-window-down)
("k" evil-window-up)
("l" evil-window-right)
("q" evil-window-delete)
("Q" delete-other-windows)
("s" evil-window-split)
("v" evil-window-vsplit)
("w" evil-window-next))
Setting up key bindings
The documentation shows that you can setup key bindings in the first 2 arguments of the defhydra
declaration.
This example creates the key binding of hydra-zoom
to the global-map
with the key <f2>
.
(defhydra hydra-zoom (global-map "<f2>")
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out"))
This didn't work for me, probably because I have Evil Mode (Emacs) installed. I needed to setup the key bindings the usual Evil way.
(defhydra hydra-zoom ()
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out"))
(general-nmap 'global
"<f2>" 'hydra-zoom/body)
You might notice that the key is bound to hydra-zoom/body
and not hydra-zoom
. This is because the defhydra
macro does not create the hydra-zoom
function. It creates a function called hydra-zoom/body
instead.
After this setup, you should be able to invoke hydra-zoom
with the f2
key.
Setting up behaviors of keys
Basic behavior can be set with the color
option.
| color | toggle | |----------+----------------------------| | red | | | blue | :exit t | | amaranth | :foreign-keys warn | | teal | :foreign-keys warn :exit t | | pink | :foreign-keys run |
The option behaves the following way.
:exit
: when it is set tot
, exits Hydra state when key is pressed:foreign-keys
: this describes the behavior when a key not defined in Hydra is pressed
nil
: runs the command mapped to the key, and then exits Hydra statewarn
: shows a warning message and does not run anything, and stays in the Hydra staterun
: runs the command mapped to the key, but does not exit Hydra state
An example configuration will be something like this.
(defhydra hydra-zoom (:color amaranth) ; Sets the default color to amaranth
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out")
("q" nil "quit" :color blue) ; Overwrites the color to blue
)
This will result in Hydra looking like this. You can see the colors! The keys behaves according to the chart above too.

The warning message looks like this.

Setting up custom hints
My window Hydra has this beautiful hint that is easy for me reference.

You can set this up with a special docstring defhydra
. This is my window Hydra docstring.
(defhydra hydra-window (:hint nil)
"
| Navigation^^ | Placement^^ | Create, Delete^^ | Adjustment^^ |
|^^-----------------+^^-------------------+^^-------------------------+^^--------------------|
| _h_: go left | _H_: move to left | _v_: split vertically | _=_: balance windows |
| _j_: go down | _J_: move to bottom | _s_: split horizontally | _+_: increase height |
| _k_: go up | _K_: move to top | _q_: delete window | _-_: decrease height |
| _l_: go right | _L_: move to right | _Q_: delete other windows | _>_: increase width |
| _w_: go to next | ^^ | ^^ | _<_: decrease width |
| _C-w_: go to next | ^^ | ^^ | ^^ |
"
...)
The special notations I use are
_
: when the key are surrounded by_
, Hydra uses the appropriatecolor
^
: character that becomes an empty string when Hydra shows the hint
You might wonder why I have the ^
notation everywhere. This is just to make the docstring clean. You can also write the hint without ^
, but it would look a little crooked. The docstring below produces the exact same hint as the docstring above.
;; Without the ^ notations
(defhydra hydra-window (:hint nil)
"
| Navigation | Placement | Create, Delete | Adjustment |
|-----------------+-------------------+-------------------------+--------------------|
| _h_: go left | _H_: move to left | _v_: split vertically | _=_: balance windows |
| _j_: go down | _J_: move to bottom | _s_: split horizontally | _+_: increase height |
| _k_: go up | _K_: move to top | _q_: delete window | _-_: decrease height |
| _l_: go right | _L_: move to right | _Q_: delete other windows | _>_: increase width |
| _w_: go to next | | | _<_: decrease width |
| _C-w_: go to next | | | |
"
...)
Now it's your turn
Use it! It's amazing! Have fun!