(or emacs irrelevant)

Combining ace-window and windmove with hydra

I was inspired by Sacha Chua's recent post explaining her window bindings, that combine both ace-window and windmove. So I wrote down an update to Hydra in order to get a similar setup.

Sacha's code

Here it is:

(key-chord-define-global
 "yy"
 (sacha/def-rep-command
  '(nil
    ("<left>" . windmove-left)
    ("<right>" . windmove-right)
    ("<down>" . windmove-down)
    ("<up>" . windmove-up)
    ("y" . other-window)
    ("h" . ace-window)
    ("s" . (lambda () (interactive) (ace-window 4)))
    ("d" . (lambda () (interactive) (ace-window 16))))))

My code

Here's what I've come up with, thanks to the newest code in hydra:

(defun hydra-universal-argument (arg)
  (interactive "P")
  (setq prefix-arg (if (consp arg)
                       (list (* 4 (car arg)))
                     (if (eq arg '-)
                         (list -4)
                       '(4)))))

(defhydra hydra-window (global-map "C-M-o")
  "window"
  ("h" windmove-left "left")
  ("j" windmove-down "down")
  ("k" windmove-up "up")
  ("l" windmove-right "right")
  ("a" ace-window "ace")
  ("u" hydra-universal-argument "universal")
  ("s" (lambda () (interactive) (ace-window 4)) "swap")
  ("d" (lambda () (interactive) (ace-window 16)) "delete")
  ("o"))

(key-chord-define-global "yy" 'hydra-window/body)

The new code should already be available in MELPA. I'll update the code in GNU ELPA soon, when I make sure that there were no bugs introduced by the change.

If anyone wants to see how the defhydra macro expands, you can check out hydra-test.el. I just added a Travis CI setup, so if you're interested in starting to test your Elisp code, you can have a very simple example.

How the defined Hydra works

With this setup:

  • to swap two windows (i.e. call C-u ace-window), I can do any of:

    • C-M-o s
    • C-M-o ua
    • yys
    • yyua
  • to delete one window (i.e. call C-u C-u ace-window), any of:

    • C-M-o d
    • C-M-o uua
    • yyd
    • yyuua
  • to move one window down, two windows right, and one window up:

    • C-M-o jllk
    • yyjllk

Although every other shortcut except the Hydra heads will vanquish the Hydra, sometimes I have nothing on my mind that needs doing. For that case, as you can see above, I enter o in its own list without a function, so that o will dismiss the Hydra without doing anything.