Moving from General to Hydra

John Haman

2020/07/22

Categories: Emacs Tags: Emacs

I had been happy to use General to define all my Emacs keybindings. General is especially nice if you are an Evil user, and it takes much of the pain out of the usual Emacs way of defining keymaps. I use General to make several custom keymaps: I have one big keymap that is bound to SPC giving me a mini-Spacemacs setup, and several mode specific keymaps that I bind to ,, no matter the mode.

It’s these mode-specific keymaps that are causing me to move from general to Hydra. The problem with general is that I have to re-type my leader key every time I want to execute a mode map action. For example, I write a lot of Rmd files, for which I use Polymode to edit. In polymode, I have a little keymap on , that executes lots of different commands, but the Evaluate Chunk command gets the most use. It’s also bound to ,, so end up spamming ,,,,,,, to run a lot of chunks in the R buffer.

With hydra, I can simplify this a bit, because once I press , to bring up the polymode keymap, I don’t need to press it again. The keymap is now persistent, so I can run all my ESS/polymode commands without having to press , in between them.

Overall this seems like a win to me. Here is a picture of the hydra that I came up with to execute all of my Polymode related commands:

I have all of my common Polymode commands organized into columns depending on their function. This makes glancing at the hydra much better than my old general pop-up, which was kind of a mess. You can also see that I have a lot of different types of evaluation in the Evaluation column. This is a killer feature of R and Emacs.

Here’s the code:

(defhydra hydra-polymode ()
  "Polymode Hydra"
  ("j" polymode-next-chunk-same-type "Next chunk, same type" :column "Movement")
  ("k" polymode-previous-chunk-same-type "Previous chunk, same type" :column "Movement")
  ("i" polymode-insert-new-chunk "Insert new chunk" :column "Insert")
  ("I" jth/insert-image "Insert image from file" :column "Insert")
  ("c" polymode-mark-or-extend-chunk "Mark chunk" :column "Chunk")
  ("u" polymode-insert-new-chunk-code-only "Insert chunk (code only)" :column "Insert")
  ("U" polymode-insert-new-chunk-output-only "Insert chunk (output only)" :column "Insert")
  ("p" polymode-insert-new-plot "Insert plot" :column "Insert")
  ("o" polymode-insert-yaml "Insert YAML" :column "Insert")
  ("d" polymode-kill-chunk "Kill chunk" :column "Chunk")
  ("m" my/add-pipe "Add pipe" :column "Insert")
  ("e" polymode-export "Export" :column "Export")
  ("E" polymode-set-exporter "Set exporter" :column "Export")
  ("w" polymode-weave "Weave" :column "Export")
  ("W" polymode-set-weaver "Set weaver" :column "Export")
  ("$" polymode-show-process-buffer "Show process buffer" :column "Evaluation")
  ("," polymode-eval-region-or-chunk "Eval chunk" :column "Evaluation")
  ("N" polymode-eval-buffer "Eval buffer" :column "Evaluation")
  ("1" polymode-eval-buffer-from-beg-to-point "Eval to here" :column "Evaluation")
  ("0" polymode-eval-buffer-from-point-to-end "Eval to end" :column "Evaluation"))

Moving from General to Hydra has been pretty painless. The structures that define the keymaps are similar, but with Hydra I have the added benefits of grouping commands into columns depending on their functionality, and being able to call functions repeatedly without leaving the minibuffer.