(or emacs irrelevant)

Colorful Hydras

This post advertises the release of hydra.el 0.5.0. The package was introduced in an earlier post and received some positive feedback. Currently, it's available in both GNU ELPA (slightly behind) and MELPA (always current).

colorful-hydra

The newfound utility

As I originally released the Hydra, I was asked if it was similar to this approach described on Endless Parentheses. I said that it's not, since Hydra commands are meant to be repeatable instead of being called just once.

Now, after I've designated the repeatable heads with red color and the one-off heads with blue color, Hydra can reproduce the mentioned approach. Here's how it looks like:

(global-set-key
 (kbd "C-c C-v")
 (defhydra hydra-toggle (:color blue)
   "toggle"
   ("a" abbrev-mode "abbrev")
   ("d" toggle-debug-on-error "debug")
   ("f" auto-fill-mode "fill")
   ("t" toggle-truncate-lines "truncate")
   ("w" whitespace-mode "whitespace")
   ("q" nil "cancel")))

And this is what I see in the echo area after pressing C-c C-v:

hydra-toggle

At this point:

  • q will cancel without doing anything. I think it's more convenient than doing the equivalent C-g with the global-set-key approach.
  • a, d, f, t, and a will call the appropriate function. The advantage of blue Hydra heads over global-set-key is that you immediately get the hint: this can be useful for rarely used commands.
  • as with the old red Hydra heads, pressing anything other than a, d, f, t, a, or q will vanquish the Hydra and call the key binding that you just pressed. This is different from the global-set-key approach, which would e.g. error to your C-c C-v C-n with "C-c C-v C-n is undefined", unlike the Hydra, which would call C-n (next-line).

The full defhydra syntax

Note that defhydra looks intentionally like a defun, so that it's easier to remember how it works. Here's a more verbose Hydra that's largely equivalent to the one above:

(defhydra hydra-toggle (global-map "C-c" :color red)
   "toggle"
   ("a" abbrev-mode "abbrev" :color blue)
   ("d" toggle-debug-on-error "debug" :color blue)
   ("f" auto-fill-mode "fill" :color blue)
   ("t" toggle-truncate-lines "truncate" :color blue)
   ("w" whitespace-mode "whitespace" :color blue)
   ("v" recenter-top-bottom "recenter" :color red)
   ("q" nil "cancel" :color blue))
(global-set-key (kbd "C-c C-v") 'hydra-toggle/body)

First argument: Hydra name

This argument decides the prefix to all the functions that will be generated. In this case the following functions will be generated:

hydra-toggle/abbrev-mode
hydra-toggle/toggle-debug-on-error
hydra-toggle/auto-fill-mode
hydra-toggle/toggle-truncate-lines
hydra-toggle/whitespace-mode
hydra-toggle/recenter-top-bottom
hydra-toggle/nil
hydra-toggle/body

The final function calls the Hydra's body, displaying the hint in the echo area and setting the transient map. It's the return result of defhydra, that's why it was possible to pass it to global-set-key in the first example.

Second argument: Hydra body

The Hydra body consists of:

  • a map used for binding, like global-map or c++-mode-map or projectile-mode-map
  • the body prefix: it's a string passable to kbd that will be used in conjunction with heads' prefixes to bind the functions
  • an optional plist, which currently recognizes only the :color key, which in turn can be either red (the old behavior) or blue.

It's possible to omit the map and the body prefix simultaneously (it doesn't make sense to omit one but not the other), or just pass () if you want to get a red Hydra body that you can bind yourself.

Third argument: Hydra hint

This string will be used in the echo area to distinguish the current Hydra. This is optional, it case you don't provide it, it will default to "hydra".

Fourth argument: Hydra heads

Each Hydra head is a list of:

  • the key extension
  • the function
  • optional hint
  • optional plist.

Again, the plist recognizes only :color currently. The color is inherited from the body, if you don't specify it. In turn, the body color is red if you don't specify it.

The code above:

  • binds C-c a, C-c d etc with the usual global-set-key approach.
  • binds C-c C-v a, C-c C-v d with the new approach, which shows you the hint right after C-c C-v and allows you to cancel easier.
  • binds C-c v to be repeatable, i.e. you can press C-c v v v. Same with C-c C-v v v v.

Some more ideas for blue Hydras

Here's one for some helm-related functions, don't ask how projectile-find-file ended up here:

(global-set-key
 "κ"
 (defhydra hydra-helm (:color blue)
   "helm"
   ("f" projectile-find-file "file")
   ("w" helm-org-wiki "wiki")
   ("r" helm-recentf "recent")
   ("s" helm-swoop "swoop")
   ("q" nil "quit")))

Here's one more for gnus; I'm just getting the hang of it, so some hints are useful:

(defhydra hydra-gnus-reply (:color blue)
  "reply"
  ("o" gnus-summary-reply-with-original "one")
  ("O" gnus-summary-reply)
  ("a" gnus-summary-wide-reply-with-original "all")
  ("A" gnus-summary-wide-reply)
  ("u" gnus-summary-very-wide-reply-with-original "universe")
  ("U" gnus-summary-very-wide-reply)
  ("q" nil "quit"))
(define-key gnus-summary-mode-map "r" 'hydra-gnus-reply/body)

I omit the hint for the commands that do the same as the previous one, just without citing.

Outro

I hope that you enjoy the update and let me know when you invent some efficient blue or red-and-blue Hydras. Happy hacking!