Some fun with Hydra
21 Mar 2015The code from this post has very little application. But it's kind of fun, so I'll post it. Star Trek: TNG is one of my favorite shows, so I've added some TNG characters to one of the Hydra features that I'm testing.
defhydradio
statement
(require 'hydra)
(defhydradio hydra-tng ()
(picard "_p_ Captain Jean Luc Picard:")
(riker "_r_ Commander William Riker:")
(data "_d_ Lieutenant Commander Data:")
(worf "_w_ Worf:")
(la-forge "_f_ Geordi La Forge:")
(troi "_t_ Deanna Troi:")
(dr-crusher "_c_ Doctor Beverly Crusher:")
(phaser "_h_ Set phasers to " [stun kill]))
The defhydradio
macro is akin to a namespace construct that defines multiple variables that can
assume only certain values (either t
or nil
by default), and functions to cycle those values.
defhydradio
implementation
Here's what you may see after a macroexpand
:
(progn
(defvar hydra-tng/picard nil
"_p_ Captain Jean Luc Picard:")
(put (quote hydra-tng/picard)
(quote range)
[nil t])
(defun hydra-tng/picard nil
(hydra--cycle-radio (quote hydra-tng/picard)))
(defvar hydra-tng/riker nil
"_r_ Commander William Riker:")
(put (quote hydra-tng/riker)
(quote range)
[nil t])
(defun hydra-tng/riker nil (hydra--cycle-radio (quote hydra-tng/riker)))
;; ...
(defvar hydra-tng/names
'(hydra-tng/picard hydra-tng/riker
hydra-tng/data hydra-tng/worf hydra-tng/la-forge
hydra-tng/troi hydra-tng/dr-crusher hydra-tng/phaser)))
As you can see, each list passed to defhydradio
:
- gets a prefixed variable definition
- gets a
range
property for the prefixed symbol - gets a prefixed function definition that cycles the variable value based on the
range
property - gets added to
hydra-tng/names
defhydra
statement
(defhydra hydra-tng (:foreign-keys run :hint nil)
(concat (hydra--table hydra-tng/names 7 2
'(" % -30s %% -3`%s"
"%s %%`%s"))
"\n\n")
("p" (hydra-tng/picard))
("r" (hydra-tng/riker))
("d" (hydra-tng/data))
("w" (hydra-tng/worf))
("f" (hydra-tng/la-forge))
("t" (hydra-tng/troi))
("c" (hydra-tng/dr-crusher))
("h" (hydra-tng/phaser))
("b" beam-down "beam down" :exit t)
("o" (hydra-reset-radios hydra-tng/names) "reset")
("q" nil "cancel"))
The interesting statement in place of the docstring will actually evaluate to this docstring:
" _p_ Captain Jean Luc Picard: % -3`hydra-tng/picard^^^^ _h_ Set phasers to %`hydra-tng/phaser
_r_ Commander William Riker: % -3`hydra-tng/riker^^^^^
_d_ Lieutenant Commander Data: % -3`hydra-tng/data^^^^^^
_w_ Worf: % -3`hydra-tng/worf^^^^^^
_f_ Geordi La Forge: % -3`hydra-tng/la-forge^^
_t_ Deanna Troi: % -3`hydra-tng/troi^^^^^^
_c_ Doctor Beverly Crusher: % -3`hydra-tng/dr-crusher
"
The first line overflows a bit, but it's clear what it is. There's some flexibility in using
hydra--table
, since you can:
- redefine the row-column format (e.g. from 7x2 to 5x3)
- add more variables to
hydra-tng/names
Note also, that since hydra-tng/names
holds all the names, and all the names know their default
values through range
, it's possible to reset them all at once with hydra-reset-radios
.
Finally, here's a simple implementation of beam-down
:
(defun beam-down ()
(interactive)
(message
"Beaming down: %s."
(mapconcat
#'identity
(delq nil
(mapcar
(lambda (p) (when (symbol-value p)
(substring (symbol-name p) 10)))
'(hydra-tng/picard
hydra-tng/riker
hydra-tng/data
hydra-tng/worf
hydra-tng/la-forge
hydra-tng/troi
hydra-tng/dr-crusher)))
", and ")))
(global-set-key (kbd "C-c C-,") 'hydra-tng/body)
Outro
And that's it. There actually is an application of defhydradio
in
hydra-ox.el. It's not fully finished,
but you can already try it as an alternative to org-mode
export dispatch widget, most things are
working.