emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 5aa7896 28/28: Merge commit '7783f89cdbb3e3ba57f2325527297


From: Oleh Krehel
Subject: [elpa] master 5aa7896 28/28: Merge commit '7783f89cdbb3e3ba57f232552729715148e0b9a1' from hydra
Date: Sun, 22 Mar 2015 16:34:49 +0000

branch: master
commit 5aa78963734dc6975cad8df1c8853b65a4f1b826
Merge: af29d76 7783f89
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>

    Merge commit '7783f89cdbb3e3ba57f232552729715148e0b9a1' from hydra
---
 packages/hydra/Makefile          |    8 +-
 packages/hydra/README.md         |  537 +++++++++++++++++++++++---------------
 packages/hydra/hydra-examples.el |  140 +++++++---
 packages/hydra/hydra-init.el     |   29 ++
 packages/hydra/hydra-ox.el       |   10 +-
 packages/hydra/hydra-test.el     |  348 +++++++++++++-----------
 packages/hydra/hydra.el          |  249 +++++++++++-------
 packages/hydra/lv.el             |   13 +-
 8 files changed, 813 insertions(+), 521 deletions(-)

diff --git a/packages/hydra/Makefile b/packages/hydra/Makefile
index 4b6451f..35709e1 100644
--- a/packages/hydra/Makefile
+++ b/packages/hydra/Makefile
@@ -1,5 +1,5 @@
-EMACS = emacs
-# EMACS = emacs-24.3
+emacs ?= emacs
+# emacs = emacs-24.3
 
 LOAD = -l lv.el -l hydra.el -l hydra-test.el
 
@@ -8,10 +8,10 @@ LOAD = -l lv.el -l hydra.el -l hydra-test.el
 all: test
 
 test:
-       $(EMACS) -batch $(LOAD) -f ert-run-tests-batch-and-exit
+       $(emacs) -batch $(LOAD) -f ert-run-tests-batch-and-exit
 
 compile:
-       $(EMACS) -q $(LOAD) -l init.el --eval "(progn (mapc #'byte-compile-file 
'(\"hydra.el\" \"init.el\")) (switch-to-buffer \"*Compile-Log*\") (ert t))"
+       $(emacs) -q $(LOAD) -l hydra-init.el
        make clean
 
 clean:
diff --git a/packages/hydra/README.md b/packages/hydra/README.md
index 70b31bf..172524e 100644
--- a/packages/hydra/README.md
+++ b/packages/hydra/README.md
@@ -1,23 +1,48 @@
 [![Build 
Status](https://travis-ci.org/abo-abo/hydra.svg?branch=master)](https://travis-ci.org/abo-abo/hydra)
 
-This is a package for GNU Emacs that can be used to tie related
-commands into a family of short bindings with a common prefix - a
-Hydra.
-
-![hydra](http://oremacs.com/download/Hydra.png)
-
-Once you summon the Hydra through the prefixed binding (the body + any
-one head), all heads can be called in succession with only a short
-extension.
-
-The Hydra is vanquished once Hercules, any binding that isn't the
-Hydra's head, arrives.  Note that Hercules, besides vanquishing the
-Hydra, will still serve his orignal purpose, calling his proper
-command.  This makes the Hydra very seamless, it's like a minor mode
-that disables itself auto-magically.
-
-## Sample global Hydras
-### Zoom
+This is a package for GNU Emacs that can be used to tie related commands into 
a family of short
+bindings with a common prefix - a Hydra.
+
+![hydra](http://oremacs.com/download/Hydra.jpg)
+
+Once you summon the Hydra through the prefixed binding (the body + any one 
head), all heads can be
+called in succession with only a short extension.
+
+The Hydra is vanquished once Hercules, any binding that isn't the Hydra's 
head, arrives.  Note that
+Hercules, besides vanquishing the Hydra, will still serve his original 
purpose, calling his proper
+command.  This makes the Hydra very seamless, it's like a minor mode that 
disables itself
+auto-magically.
+
+<!-- markdown-toc start - Don't edit this section. Run M-x 
markdown-toc/generate-toc again -->
+**Table of Contents**
+
+- [Sample Hydras](#sample-hydras)
+    - [The one with the least amount of 
code](#the-one-with-the-least-amount-of-code)
+    - [The impressive-looking one](#the-impressive-looking-one)
+- [Community wiki](#community-wiki)
+- [The Rules of Hydra-tics](#the-rules-of-hydra-tics)
+    - [`hydra-awesome`](#hydra-awesome)
+    - [`awesome-map` and `awesome-binding`](#awesome-map-and-awesome-binding)
+    - [`awesome-plist`](#awesome-plist)
+        - [`:pre` and `:post`](#pre-and-post)
+        - [`:exit`](#exit)
+        - [`:foreign-keys`](#foreign-keys)
+        - [`:color`](#color)
+        - [`:timeout`](#timeout)
+        - [`:hint`](#hint)
+        - [`:bind`](#bind)
+    - [`awesome-docstring`](#awesome-docstring)
+    - [`awesome-head-1`](#awesome-head-1)
+        - [`head-binding`](#head-binding)
+        - [`head-command`](#head-command)
+        - [`head-hint`](#head-hint)
+        - [`head-plist`](#head-plist)
+
+<!-- markdown-toc end -->
+
+# Sample Hydras
+
+## The one with the least amount of code
 
 ```cl
 (defhydra hydra-zoom (global-map "<f2>")
@@ -26,238 +51,341 @@ that disables itself auto-magically.
   ("l" text-scale-decrease "out"))
 ```
 
-### Goto-error
+With this simple code, you can:
 
-```cl
-(defhydra hydra-error (global-map "M-g")
-  "goto-error"
-  ("h" first-error "first")
-  ("j" next-error "next")
-  ("k" previous-error "prev")
-  ("v" recenter-top-bottom "recenter")
-  ("q" nil "quit"))
-```
+- Start zooming in with <kbd>&lt;f2&gt; g</kbd>.
+- Continue to zoom in with <kbd>g</kbd>.
+- Or zoom out with <kbd>l</kbd>.
+- Zoom in five times at once with <kbd>5g</kbd>.
+- Stop zooming with *any* key that isn't <kbd>g</kbd> or <kbd>l</kbd>.
 
-### Splitter
+For any Hydra:
 
-```cl
-(require 'hydra-examples)
-(defhydra hydra-splitter (global-map "C-M-s")
-  "splitter"
-  ("h" hydra-move-splitter-left)
-  ("j" hydra-move-splitter-down)
-  ("k" hydra-move-splitter-up)
-  ("l" hydra-move-splitter-right))
-```
+- `digit-argument` can be called with <kbd>0</kbd>-<kbd>9</kbd>.
+- `negative-argument` can be called with <kbd>-</kbd>.
+- `universal-argument` can be called with <kbd>C-u</kbd>.
 
-### Community wiki
-A few useful hydras are aggregated in projects [community 
wiki](https://github.com/abo-abo/hydra/wiki/Hydras%20by%20Topic). Feel free to 
add your own or edit existing ones.
+## The impressive-looking one
 
-## Using the functions generated by `defhydra`
+Here's the result of pressing <kbd>.</kbd> in the good-old Buffer menu:
 
-With the example above, you can e.g.:
+![hydra-buffer-menu](http://oremacs.com/download/hydra-buffer-menu.png)
+
+The code is large but very simple:
 
 ```cl
-(key-chord-define-global "tt" 'hydra-zoom/body)
+(defhydra hydra-buffer-menu (:color pink
+                             :hint nil)
+  "
+^Mark^             ^Unmark^           ^Actions^          ^Search
+^^^^^^^^-----------------------------------------------------------------
+_m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch
+_s_: save          _U_: unmark up     _b_: bury          _I_: isearch
+_d_: delete        ^ ^                _g_: refresh       _O_: multi-occur
+_D_: delete up     ^ ^                _T_: files only: % 
-28`Buffer-menu-files-only
+_~_: modified
+"
+  ("m" Buffer-menu-mark)
+  ("u" Buffer-menu-unmark)
+  ("U" Buffer-menu-backup-unmark)
+  ("d" Buffer-menu-delete)
+  ("D" Buffer-menu-delete-backwards)
+  ("s" Buffer-menu-save)
+  ("~" Buffer-menu-not-modified)
+  ("x" Buffer-menu-execute)
+  ("b" Buffer-menu-bury)
+  ("g" revert-buffer)
+  ("T" Buffer-menu-toggle-files-only)
+  ("O" Buffer-menu-multi-occur :color blue)
+  ("I" Buffer-menu-isearch-buffers :color blue)
+  ("R" Buffer-menu-isearch-buffers-regexp :color blue)
+  ("c" nil "cancel")
+  ("v" Buffer-menu-select "select" :color blue)
+  ("o" Buffer-menu-other-window "other-window" :color blue)
+  ("q" quit-window "quit" :color blue))
+
+(define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
 ```
 
-In fact, since `defhydra` returns the body symbol, you can even write
-it like this:
+Looking at the code, you can see `hydra-buffer-menu` as sort of a namespace 
construct that wraps
+each function that it's given in code that shows that hint and makes it easy 
to call the related
+functions. One additional function is created and returned as the result of 
`defhydra` -
+`hydra-buffer-menu/body`.  This function does nothing except setting up the 
hint and the keymap, and
+is usually the entry point to complex hydras.
 
-```cl
-(key-chord-define-global
- "tt"
- (defhydra hydra-zoom (global-map "<f2>")
-  "zoom"
-  ("g" text-scale-increase "in")
-  ("l" text-scale-decrease "out")))
-```
+To write your own hydras, you can:
+
+- Either modify an existing hydra to do what you want to do.
+- Or read [the rules](#the-rules-of-hydra-tics),
+  [the 
examples](https://github.com/abo-abo/hydra/blob/master/hydra-examples.el),
+  the docstrings and comments in the source.
+
+# Community wiki
+
+You can find some user created hydras and more documentation in the project's
+[community wiki](https://github.com/abo-abo/hydra/wiki/). Feel free to add your
+own or edit the existing ones.
 
-If you like key chords so much that you don't want to touch the global
-map at all, you can e.g.:
+# The Rules of Hydra-tics
+
+Each hydra (take `awesome` as a prefix to make it more specific) looks like 
this:
 
 ```
-(key-chord-define-global
- "hh"
- (defhydra hydra-error ()
-   "goto-error"
-   ("h" first-error "first")
-   ("j" next-error "next")
-   ("k" previous-error "prev")))
+(defhydra hydra-awesome (awesome-map awesome-binding awesome-plist)
+  awesome-docstring
+  awesome-head-1
+  awesome-head-2
+  awesome-head-3
+  ...)
 ```
 
-You can also substitute `global-map` with any other keymap, like
-`c++-mode-map` or `yas-minor-mode-map`.
+## `hydra-awesome`
 
-See the [introductory blog 
post](http://oremacs.com/2015/01/20/introducing-hydra/) for more information.
+Each hydra needs a name, and this one is named `hydra-awesome`. You can name 
your hydras as you wish,
+but I prefer to start each one with `hydra-`, because it acts as an additional 
namespace layer, for example:
+`hydra-zoom`, `hydra-helm`, `hydra-apropos` etc.
 
-## Using Hydra for major-mode or minor-mode bindings
+If you name your hydra `hydra-awesome`, the return result of `defhydra` will 
be `hydra-awesome/body`.
 
-Here's an example:
+Here's what `hydra-zoom/body` looks like, if you're interested:
 
 ```cl
-(defhydra lispy-vi (lispy-mode-map "C-z")
-  "vi"
-  ("l" forward-char)
-  ("h" backward-char)
-  ("j" next-line)
-  ("k" previous-line))
+(defun hydra-zoom/body nil
+  "Create a hydra with a \"<f2>\" body and the heads:
+
+\"g\":    `text-scale-increase',
+\"l\":    `text-scale-decrease'
+
+The body can be accessed via `hydra-zoom/body'."
+  (interactive)
+  (hydra-disable)
+  (catch (quote hydra-disable)
+    (when hydra-is-helpful (hydra-zoom/hint))
+    (setq hydra-last
+          (hydra-set-transient-map
+           (setq hydra-curr-map
+                 (quote
+                  (keymap (7 . hydra-keyboard-quit)
+                          (108 . hydra-zoom/text-scale-decrease)
+                          (103 . hydra-zoom/text-scale-increase)
+                          (kp-subtract . hydra--negative-argument)
+                          (kp-9 . hydra--digit-argument)
+                          (kp-8 . hydra--digit-argument)
+                          (kp-7 . hydra--digit-argument)
+                          (kp-6 . hydra--digit-argument)
+                          (kp-5 . hydra--digit-argument)
+                          (kp-4 . hydra--digit-argument)
+                          (kp-3 . hydra--digit-argument)
+                          (kp-2 . hydra--digit-argument)
+                          (kp-1 . hydra--digit-argument)
+                          (kp-0 . hydra--digit-argument)
+                          (57 . hydra--digit-argument)
+                          (56 . hydra--digit-argument)
+                          (55 . hydra--digit-argument)
+                          (54 . hydra--digit-argument)
+                          (53 . hydra--digit-argument)
+                          (52 . hydra--digit-argument)
+                          (51 . hydra--digit-argument)
+                          (50 . hydra--digit-argument)
+                          (49 . hydra--digit-argument)
+                          (48 . hydra--digit-argument)
+                          (45 . hydra--negative-argument)
+                          (21 . hydra--universal-argument))))
+           t (lambda nil (hydra-cleanup))))
+    (setq prefix-arg current-prefix-arg)))
 ```
 
-## Can Hydras can be helpful?
+## `awesome-map` and `awesome-binding`
 
-They can, if
+This can be any keymap, for instance, `global-map` or `isearch-mode-map`.
 
-```cl
-(setq hydra-is-helpful t)
-```
-
-This is the default setting. In this case, you'll get a hint in the
-echo area consisting of current Hydra's base comment and heads.  You
-can even add comments to the heads like this:
+For this example:
 
-```
+```cl
 (defhydra hydra-zoom (global-map "<f2>")
   "zoom"
   ("g" text-scale-increase "in")
   ("l" text-scale-decrease "out"))
 ```
 
-With this, you'll see `zoom: [g]: in, [l]: out.` in your echo area,
-once the zoom Hydra becomes active.
+- `awesome-map` is `global-map`
+- `awesome-binding` is `"<f2>"`
 
-## Colorful Hydras
+And here's the relevant generated code:
 
-Since version `0.5.0`, Hydra's heads all have a color associated with them:
+```cl
+(unless (keymapp (lookup-key global-map (kbd "<f2>")))
+  (define-key global-map (kbd "<f2>") nil))
+(define-key global-map [f2 103]
+  (function hydra-zoom/text-scale-increase))
+(define-key global-map [f2 108]
+  (function hydra-zoom/text-scale-decrease))
+```
 
-- *red* (default) means the calling this head will not vanquish the Hydra
-- *blue* means that the Hydra will be vanquished after calling this head
+As you see, `"<f2>"` is used as a prefix for <kbd>g</kbd> (char value 103) and 
<kbd>l</kbd>
+(char value 108).
 
-In all the older examples, all heads are red by default. You can specify blue 
heads like this:
+If you don't want to use a map right now, you can skip it like this:
 
 ```cl
-(global-set-key
- (kbd "C-c C-v")
- (defhydra toggle ()
-   "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)
-   ("q" nil "cancel")))
+(defhydra hydra-zoom (nil nil)
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out"))
 ```
 
-Or, since the heads can inherit the color from the body, the following is 
equivalent:
+Or even simpler:
 
 ```cl
-(global-set-key
- (kbd "C-c C-v")
- (defhydra 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")))
+(defhydra hydra-zoom ()
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out"))
 ```
 
-The above Hydra is very similar to this code:
+But then you would have to bind `hydra-zoom/text-scale-increase` and
+`hydra-zoom/text-scale-decrease` yourself.
+
+## `awesome-plist`
+
+You can read up on what a plist is in
+[the Elisp 
manual](https://www.gnu.org/software/emacs/manual/html_node/elisp/Property-Lists.html).
+
+You can use `awesome-plist` to modify the behavior of each head in some way.
+Below is a list of each key.
+
+### `:pre` and `:post`
+
+You can specify code that will be called before each head, and after the body. 
For example:
 
 ```cl
-(global-set-key (kbd "C-c C-v t") 'toggle-truncate-lines)
-(global-set-key (kbd "C-c C-v f") 'auto-fill-mode)
-(global-set-key (kbd "C-c C-v a") 'abbrev-mode)
+(defhydra hydra-vi (:pre (set-cursor-color "#40e0d0")
+                    :post (progn
+                            (set-cursor-color "#ffffff")
+                            (message
+                             "Thank you, come again.")))
+  "vi"
+  ("l" forward-char)
+  ("h" backward-char)
+  ("j" next-line)
+  ("k" previous-line)
+  ("q" nil "quit"))
 ```
 
-However, there are two important differences:
+Thanks to `:pre`, each time any head is called, the cursor color is changed.
+And when the hydra quits, the cursor color will be made black again with 
`:post`.
 
-- you get a hint like this right after <kbd>C-c C-v</kbd>:
+### `:exit`
 
-        toggle: [t]: truncate, [f]: fill, [a]: abbrev, [q]: cancel.
+The `:exit` key is inherited by every head (they can override it) and 
influences what will happen
+after executing head's command:
 
-- you can cancel <kbd>C-c C-v</kbd> with a command while executing that 
command, instead of e.g.
-getting an error `C-c C-v C-n is undefined` for <kbd>C-c C-v C-n</kbd>.
+- `:exit nil` (the default) means that the hydra state will continue - you'll 
still see the hint and be able to use short bindings.
+- `:exit t` means that the hydra state will stop.
 
-## Hydras and numeric arguments
+### `:foreign-keys`
 
-Since version `0.6.0`, for any Hydra:
+The `:foreign-keys` key belongs to the body and decides what to do when a key 
is pressed that doesn't
+belong to any head:
 
-- `digit-argment` can be called with <kbd>0</kbd>-<kbd>9</kbd>.
-- `negative-argument` can be called with <kbd>-</kbd>
-- `universal-argument` can be called with <kbd>C-u</kbd>
+- `:foreign-keys nil` (the default) means that the hydra state will stop and 
the foreign key will
+do whatever it was supposed to do if there was no hydra state.
+- `:foreign-keys warn` will not stop the hydra state, but instead will issue a 
warning without
+running the foreign key.
+- `:foreign-keys run` will not stop the hydra state, and try to run the 
foreign key.
 
-## Hydras can have `:pre` and `:post` statements
+### `:color`
 
-Since version `0.7.0`, you can specify code that will be called before each 
head, and
-after the body. For example:
+The `:color` key is a shortcut. It aggregates `:exit` and `:foreign-keys` key 
in the following way:
 
-```cl
-(global-set-key
- (kbd "C-z")
- (defhydra hydra-vi
-     (:pre
-      (set-cursor-color "#40e0d0")
-      :post
-      (progn
-        (set-cursor-color "#ffffff")
-        (message
-         "Thank you, come again.")))
-   "vi"
-   ("l" forward-char)
-   ("h" backward-char)
-   ("j" next-line)
-   ("k" previous-line)
-   ("q" nil "quit")))
-```
+    | color    | toggle                     |
+    |----------+----------------------------|
+    | red      |                            |
+    | blue     | :exit t                    |
+    | amaranth | :foreign-keys warn         |
+    | teal     | :foreign-keys warn :exit t |
+    | pink     | :foreign-keys run          |
+
+It's also a trick to make you instantly aware of the current hydra keys that 
you're about to press:
+the keys will be highlighted with the appropriate color.
+
+### `:timeout`
+
+The `:timeout` key starts a timer for the corresponding amount of seconds that 
disables the hydra.
+Calling any head will refresh the timer.
+
+### `:hint`
+
+The `:hint` key will be inherited by each head. Each head is allowed to 
override it, of course.
+One value that makes sense is `:hint nil`. See below for an explanation of 
head hint.
+
+### `:bind`
+
+The `:bind` key provides a lambda to be used to bind each head.  This is quite 
advanced and rarely
+used, you're not likely to need it.  But if you would like to bind your heads 
with e.g. `bind-key`
+instead of `define-key` you can use this option.
+
+The `:bind` key can be overridden by each head. This is useful if you want to 
have a few heads that
+are not bound outside the hydra.
+
+## `awesome-docstring`
+
+This can be a simple string used to build the final hydra hint.  However, if 
you start it with a
+newline, the key-highlighting and Ruby-style string interpolation becomes 
enabled, as you can see in
+`hydra-buffer-menu` above.
 
-## New Hydra color: amaranth
+To highlight a key, just wrap it in underscores. Note that the key must belong 
to one of the heads.
+The key will be highlighted with the color that is appropriate to the behavior 
of the key, i.e.  if
+the key will make the hydra exit, the color will be blue.
 
-Since version `0.8.0`, a new color - amaranth, in addition to the previous red 
and blue, is
-available for the Hydra body.
+To insert an empty character, use `^`. The only use of this is to have your 
code aligned as
+nicely as the result.
 
-According to [Wikipedia](http://en.wikipedia.org/wiki/Amaranth):
+To insert a dynamic Elisp variable, use `%`&#96; followed by the variable. 
Each time the variable
+changes due to a head, the docstring will be updated. `format`-style width 
specifiers can be used.
 
-> The word amaranth comes from the Greek word amaranton, meaning "unwilting" 
(from the
-> verb marainesthai, meaning "wilt").  The word was applied to amaranth 
because it did not
-> soon fade and so symbolized immortality.
+To insert a dynamic Elisp expression, use e.g. `%(length 
(dired-get-marked-files))`.  If a head will
+change the amount of marked files, for example, it will be appropriately 
updated.
 
-Hydras with amaranth body are impossible to quit with any binding *except* a 
blue head.
-A check for at least one blue head exists in `defhydra`, so that you don't get 
stuck by accident.
+If the result of the Elisp expression is a string and you don't want to quote 
it, use this form:
+`%s(shell-command-to-string "du -hs")`.
 
-Here's an example of an amaranth Hydra:
+## `awesome-head-1`
+
+Each head looks like this:
 
 ```cl
-(global-set-key
- (kbd "C-z")
- (defhydra hydra-vi
-     (:pre
-      (set-cursor-color "#40e0d0")
-      :post
-      (set-cursor-color "#ffffff")
-      :color amaranth)
-   "vi"
-   ("l" forward-char)
-   ("h" backward-char)
-   ("j" next-line)
-   ("k" previous-line)
-   ("q" nil "quit")))
+(head-binding head-command head-hint head-plist)
 ```
 
-The only way to exit it, is to press <kbd>q</kbd>. No other methods will work. 
 You can
-use an amaranth Hydra instead of a red one, if for you the cost of being able 
to exit only
-though certain bindings is less than the cost of accidentally exiting a red 
Hydra by
-pressing the wrong prefix.
+For the head `("g" text-scale-increase "in")`:
+
+- `head-binding` is `"g"`.
+- `head-command` is `text-scale-increase`.
+- `head-hint` is `"in"`.
+- `head-plist` is `nil`.
+
+### `head-binding`
+
+The `head-binding` is a string that can be passed to `kbd`.
+
+### `head-command`
+
+The `head-command` can be:
 
-Note that it does not make sense to define a single amaranth head, so this 
color can only
-be assigned to the body. An amaranth body will always have some amaranth heads 
and some
-blue heads (otherwise, it's impossible to exit), no reds.
+- command name, like `text-scale-increase`.
+- a lambda, like
 
-## Generate simple lambdas in-place:
+        ("g" (lambda ()
+               (interactive)
+               (let ((current-prefix-arg 4))
+                 (call-interactively #'magit-status)))
+             "git")
 
-Since version `0.9.0` it's possible to pass a single sexp instead of a 
function name or a lambda
-to a head. This sexp will be wrapped in an interactive lambda. Here's an 
example:
+- nil, which exits the hydra.
+- a single sexp, which will be wrapped in an interactive lambda.
+
+Here's an example of the last option:
 
 ```cl
 (defhydra hydra-launcher (:color blue)
@@ -270,40 +398,27 @@ to a head. This sexp will be wrapped in an interactive 
lambda. Here's an example
 (global-set-key (kbd "C-c r") 'hydra-launcher/body)
 ```
 
-## Define Hydra heads that don't show up in the hint at all
-
-This can be done by setting the head's hint explicitly to `nil`, instead of 
the usual string.
-
-## Use a dedicated window for Hydra hints
+### `head-hint`
 
-Since version `0.10.0`, setting `hydra-lv` to `t` (the default setting) will 
make it use a dedicated
-window right above the Echo Area for hints. This has the advantage that you 
can immediately see
-any `message` output from the functions that you call, since Hydra no longer 
uses `message` to display
-the hint. You can still have the old behavior by setting `hydra-lv` to `nil`.
+In case of a large body docstring, you usually don't want the head hint to 
show up, since
+you've already documented it the the body docstring.
+You can set the head hint to `nil` to do this.
 
-## Color table
+Example:
 
+```cl
+(defhydra hydra-zoom (global-map "<f2>")
+  "
+Press _g_ to zoom in.
+"
+  ("g" text-scale-increase nil)
+  ("l" text-scale-decrease "out"))
+```
 
-    | Body Color | Head Inherited | Executing NON-HEADS   | Executing HEADS |
-    |------------+----------------+-----------------------+-----------------|
-    | amaranth   | red            | Disallow and Continue | Continue        |
-    | teal       | blue           | Disallow and Continue | Quit            |
-    | pink       | red            | Allow and Continue    | Continue        |
-    | red        | red            | Allow and Quit        | Continue        |
-    | blue       | blue           | Allow and Quit        | Quit            |
-
-## Color to toggle correspondence
+### `head-plist`
 
-By popular demand, an alternative syntax has been implemented that translates 
to colors without
-using them in the syntax. `:exit` can be used both in body (heads will 
inherit) and in heads
-(possible to override body). `:exit` is nil by default, corresponding to `red` 
head; you don't need
-to set it explicitly to nil.  `:foreign-keys` can be used only in body and can 
be either nil (default),
-`warn` or `run`.
+Here's a list of body keys that can be overridden in each head:
 
-    | color    | toggle                     |
-    |----------+----------------------------|
-    | red      |                            |
-    | blue     | :exit t                    |
-    | amaranth | :foreign-keys warn         |
-    | teal     | :foreign-keys warn :exit t |
-    | pink     | :foreign-keys run          |
+- `:exit`
+- `:color`
+- `:bind`
diff --git a/packages/hydra/hydra-examples.el b/packages/hydra/hydra-examples.el
index 50773b0..872814b 100644
--- a/packages/hydra/hydra-examples.el
+++ b/packages/hydra/hydra-examples.el
@@ -85,9 +85,10 @@
 
 ;;** Example 4: toggle rarely used modes
 (when (bound-and-true-p hydra-examples-verbatim)
+  (defvar whitespace-mode nil)
   (global-set-key
    (kbd "C-c C-v")
-   (defhydra hydra-toggle (:color blue)
+   (defhydra hydra-toggle-simple (:color blue)
      "toggle"
      ("a" abbrev-mode "abbrev")
      ("d" toggle-debug-on-error "debug")
@@ -96,7 +97,7 @@
      ("w" whitespace-mode "whitespace")
      ("q" nil "cancel"))))
 
-;; Note that in this case, `defhydra' returns the `hydra-toggle/body'
+;; Note that in this case, `defhydra' returns the `hydra-toggle-simple/body'
 ;; symbol, which is then passed to `global-set-key'.
 ;;
 ;; Another new thing is that both the keymap and the body prefix are
@@ -160,26 +161,26 @@
 ;; This example will bind "C-x `" in `global-map', but it will not
 ;; bind "C-x j" and "C-x k".
 ;; You can still "C-x `jjk" though.
+
 ;;** Example 7: toggle with Ruby-style docstring
-(when (bound-and-true-p hydra-examples-verbatim)
-  (defhydra hydra-toggle (:color pink)
-    "
+(defvar whitespace-mode nil)
+(defhydra hydra-toggle (:color pink)
+  "
 _a_ abbrev-mode:       %`abbrev-mode
 _d_ debug-on-error:    %`debug-on-error
 _f_ auto-fill-mode:    %`auto-fill-function
-_g_ golden-ratio-mode: %`golden-ratio-mode
 _t_ truncate-lines:    %`truncate-lines
 _w_ whitespace-mode:   %`whitespace-mode
 
 "
-    ("a" abbrev-mode nil)
-    ("d" toggle-debug-on-error nil)
-    ("f" auto-fill-mode nil)
-    ("g" golden-ratio-mode nil)
-    ("t" toggle-truncate-lines nil)
-    ("w" whitespace-mode nil)
-    ("q" nil "quit"))
-  (global-set-key (kbd "C-c C-v") 'hydra-toggle/body))
+  ("a" abbrev-mode nil)
+  ("d" toggle-debug-on-error nil)
+  ("f" auto-fill-mode nil)
+  ("t" toggle-truncate-lines nil)
+  ("w" whitespace-mode nil)
+  ("q" nil "quit"))
+;; Recommended binding:
+;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
 
 ;; Here, using e.g. "_a_" translates to "a" with proper face.
 ;; More interestingly:
@@ -187,46 +188,49 @@ _w_ whitespace-mode:   %`whitespace-mode
 ;;     "foobar %`abbrev-mode" means roughly (format "foobar %S" abbrev-mode)
 ;;
 ;; This means that you actually see the state of the mode that you're changing.
+
 ;;** Example 8: the whole menu for `Buffer-menu-mode'
-(defhydra hydra-buffer-menu (:color pink)
+(defhydra hydra-buffer-menu (:color pink
+                             :hint nil)
   "
-  Mark               Unmark             Actions            Search
--------------------------------------------------------------------------      
                  (__)
+^Mark^             ^Unmark^           ^Actions^          ^Search
+^^^^^^^^-----------------------------------------------------------------      
                  (__)
 _m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch       
                  (oo)
 _s_: save          _U_: unmark up     _b_: bury          _I_: isearch          
            /------\\/
-_d_: delete                           _g_: refresh       _O_: multi-occur      
           / |    ||
-_D_: delete up                        _T_: files only: % 
-28`Buffer-menu-files-only      *  /\\---/\\
-_~_: modified                                                                  
             ~~   ~~
+_d_: delete        ^ ^                _g_: refresh       _O_: multi-occur      
           / |    ||
+_D_: delete up     ^ ^                _T_: files only: % 
-28`Buffer-menu-files-only^^    *  /\\---/\\
+_~_: modified      ^ ^                ^ ^                ^^                    
             ~~   ~~
 "
-  ("m" Buffer-menu-mark nil)
-  ("u" Buffer-menu-unmark nil)
-  ("U" Buffer-menu-backup-unmark nil)
-  ("d" Buffer-menu-delete nil)
-  ("D" Buffer-menu-delete-backwards nil)
-  ("s" Buffer-menu-save nil)
-  ("~" Buffer-menu-not-modified nil)
-  ("x" Buffer-menu-execute nil)
-  ("b" Buffer-menu-bury nil)
-  ("g" revert-buffer nil)
-  ("T" Buffer-menu-toggle-files-only nil)
-  ("O" Buffer-menu-multi-occur nil :color blue)
-  ("I" Buffer-menu-isearch-buffers nil :color blue)
-  ("R" Buffer-menu-isearch-buffers-regexp nil :color blue)
+  ("m" Buffer-menu-mark)
+  ("u" Buffer-menu-unmark)
+  ("U" Buffer-menu-backup-unmark)
+  ("d" Buffer-menu-delete)
+  ("D" Buffer-menu-delete-backwards)
+  ("s" Buffer-menu-save)
+  ("~" Buffer-menu-not-modified)
+  ("x" Buffer-menu-execute)
+  ("b" Buffer-menu-bury)
+  ("g" revert-buffer)
+  ("T" Buffer-menu-toggle-files-only)
+  ("O" Buffer-menu-multi-occur :color blue)
+  ("I" Buffer-menu-isearch-buffers :color blue)
+  ("R" Buffer-menu-isearch-buffers-regexp :color blue)
   ("c" nil "cancel")
   ("v" Buffer-menu-select "select" :color blue)
   ("o" Buffer-menu-other-window "other-window" :color blue)
   ("q" quit-window "quit" :color blue))
 ;; Recommended binding:
 ;; (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
+
 ;;** Example 9: s-expressions in the docstring
 ;; You can inline s-expresssions into the docstring like this:
 (when (bound-and-true-p hydra-examples-verbatim)
-  (eval-after-load 'dired
-    (defhydra hydra-marked-items (dired-mode-map "")
-      "
+  (require 'dired)
+  (defhydra hydra-marked-items (dired-mode-map "")
+    "
 Number of marked items: %(length (dired-get-marked-files))
 "
-      ("m" dired-mark "mark"))))
+    ("m" dired-mark "mark")))
 
 ;; This results in the following dynamic docstring:
 ;;
@@ -235,7 +239,55 @@ Number of marked items: %(length (dired-get-marked-files))
 ;;
 ;; You can use `format'-style width specs, e.g. % 10(length nil).
 
-;;* Windmove helpers
+;;** Example 10: apropos family
+(defhydra hydra-apropos (:color blue
+                         :hint nil)
+  "
+_a_propos        _c_ommand
+_d_ocumentation  _l_ibrary
+_v_ariable       _u_ser-option
+^ ^          valu_e_"
+  ("a" apropos)
+  ("d" apropos-documentation)
+  ("v" apropos-variable)
+  ("c" apropos-command)
+  ("l" apropos-library)
+  ("u" apropos-user-option)
+  ("e" apropos-value))
+;; Recommended binding:
+;; (global-set-key (kbd "C-c h") 'hydra-apropos/body)
+
+;;** Example 11: rectangle-mark-mode
+(defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1)
+                           :color pink
+                           :post (deactivate-mark))
+  "
+  ^_k_^     _d_elete    _s_tring     |\\     _,,,--,,_
+_h_   _l_   _o_k        _y_ank       /,`.-'`'   ._  \-;;,_
+  ^_j_^     _n_ew-copy  _r_eset     |,4-  ) )_   .;.(  `'-'
+^^^^        _e_xchange  _u_ndo     '---''(_/._)-'(_\_)
+^^^^        ^ ^         _p_aste
+"
+  ("h" backward-char nil)
+  ("l" forward-char nil)
+  ("k" previous-line nil)
+  ("j" next-line nil)
+  ("e" hydra-ex-point-mark nil)
+  ("n" copy-rectangle-as-kill nil)
+  ("d" delete-rectangle nil)
+  ("r" (if (region-active-p)
+           (deactivate-mark)
+         (rectangle-mark-mode 1)) nil)
+  ("y" yank-rectangle nil)
+  ("u" undo nil)
+  ("s" string-rectangle nil)
+  ("p" kill-rectangle nil)
+  ("o" nil nil))
+
+;; Recommended binding:
+;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body)
+
+;;* Helpers
 (require 'windmove)
 
 (defun hydra-move-splitter-left (arg)
@@ -270,5 +322,15 @@ Number of marked items: %(length (dired-get-marked-files))
       (shrink-window arg)
     (enlarge-window arg)))
 
+(defvar rectangle-mark-mode)
+(defun hydra-ex-point-mark ()
+  "Exchange point and mark."
+  (interactive)
+  (if rectangle-mark-mode
+      (exchange-point-and-mark)
+    (let ((mk (mark)))
+      (rectangle-mark-mode 1)
+      (goto-char mk))))
+
 (provide 'hydra-examples)
 ;;; hydra-examples.el ends here
diff --git a/packages/hydra/hydra-init.el b/packages/hydra/hydra-init.el
new file mode 100644
index 0000000..80b4159
--- /dev/null
+++ b/packages/hydra/hydra-init.el
@@ -0,0 +1,29 @@
+;;; hydra-test.el --- bare hydra init
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+(add-to-list 'load-path default-directory)
+(require 'hydra)
+(setq hydra-examples-verbatim t)
+(require 'hydra-examples)
+(require 'hydra-test)
+(mapc #'byte-compile-file '("hydra.el"))
+(switch-to-buffer "*Compile-Log*")
+(ert t)
diff --git a/packages/hydra/hydra-ox.el b/packages/hydra/hydra-ox.el
index 4053081..5f1a5c9 100644
--- a/packages/hydra/hydra-ox.el
+++ b/packages/hydra/hydra-ox.el
@@ -27,11 +27,11 @@
 (require 'org)
 
 (defhydradio hydra-ox ()
-  (body-only)
-  (export-scope [buffer subtree])
-  (async-export)
-  (visible-only)
-  (force-publishing))
+  (body-only "Export only the body.")
+  (export-scope "Export scope." [buffer subtree])
+  (async-export "When non-nil, export async.")
+  (visible-only "When non-nil, export visible only")
+  (force-publishing "Toggle force publishing"))
 
 (defhydra hydra-ox-html (:color blue)
   "ox-html"
diff --git a/packages/hydra/hydra-test.el b/packages/hydra/hydra-test.el
index 754984d..b908ac0 100644
--- a/packages/hydra/hydra-test.el
+++ b/packages/hydra/hydra-test.el
@@ -64,6 +64,7 @@ Call the head: `first-error'."
                                            (107 . hydra-error/previous-error)
                                            (106 . hydra-error/next-error)
                                            (104 . hydra-error/first-error)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -115,6 +116,7 @@ Call the head: `next-error'."
                                            (107 . hydra-error/previous-error)
                                            (106 . hydra-error/next-error)
                                            (104 . hydra-error/first-error)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -166,6 +168,7 @@ Call the head: `previous-error'."
                                            (107 . hydra-error/previous-error)
                                            (106 . hydra-error/next-error)
                                            (104 . hydra-error/first-error)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -223,35 +226,35 @@ The body can be accessed via `hydra-error/body'."
                (setq hydra-last
                      (hydra-set-transient-map
                       (setq hydra-curr-map
-                            (quote
-                             (keymap (7 . hydra-keyboard-quit)
-                                     (32 . hydra-repeat)
-                                     (107 . hydra-error/previous-error)
-                                     (106 . hydra-error/next-error)
-                                     (104 . hydra-error/first-error)
-                                     (kp-subtract . hydra--negative-argument)
-                                     (kp-9 . hydra--digit-argument)
-                                     (kp-8 . hydra--digit-argument)
-                                     (kp-7 . hydra--digit-argument)
-                                     (kp-6 . hydra--digit-argument)
-                                     (kp-5 . hydra--digit-argument)
-                                     (kp-4 . hydra--digit-argument)
-                                     (kp-3 . hydra--digit-argument)
-                                     (kp-2 . hydra--digit-argument)
-                                     (kp-1 . hydra--digit-argument)
-                                     (kp-0 . hydra--digit-argument)
-                                     (57 . hydra--digit-argument)
-                                     (56 . hydra--digit-argument)
-                                     (55 . hydra--digit-argument)
-                                     (54 . hydra--digit-argument)
-                                     (53 . hydra--digit-argument)
-                                     (52 . hydra--digit-argument)
-                                     (51 . hydra--digit-argument)
-                                     (50 . hydra--digit-argument)
-                                     (49 . hydra--digit-argument)
-                                     (48 . hydra--digit-argument)
-                                     (45 . hydra--negative-argument)
-                                     (21 . hydra--universal-argument))))
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (32 . hydra-repeat)
+                                           (107 . hydra-error/previous-error)
+                                           (106 . hydra-error/next-error)
+                                           (104 . hydra-error/first-error)
+                                           (switch-frame . 
hydra--handle-switch-frame)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
                       t (lambda nil (hydra-cleanup))))
                (setq prefix-arg current-prefix-arg)))))))
 
@@ -349,35 +352,35 @@ The body can be accessed via `hydra-toggle/body'."
                (setq hydra-last
                      (hydra-set-transient-map
                       (setq hydra-curr-map
-                            (quote
-                             (keymap (7 . hydra-keyboard-quit)
-                                     (113 . hydra-toggle/nil)
-                                     (97 . hydra-toggle/abbrev-mode)
-                                     (102 . hydra-toggle/auto-fill-mode)
-                                     (116 . hydra-toggle/toggle-truncate-lines)
-                                     (kp-subtract . hydra--negative-argument)
-                                     (kp-9 . hydra--digit-argument)
-                                     (kp-8 . hydra--digit-argument)
-                                     (kp-7 . hydra--digit-argument)
-                                     (kp-6 . hydra--digit-argument)
-                                     (kp-5 . hydra--digit-argument)
-                                     (kp-4 . hydra--digit-argument)
-                                     (kp-3 . hydra--digit-argument)
-                                     (kp-2 . hydra--digit-argument)
-                                     (kp-1 . hydra--digit-argument)
-                                     (kp-0 . hydra--digit-argument)
-                                     (57 . hydra--digit-argument)
-                                     (56 . hydra--digit-argument)
-                                     (55 . hydra--digit-argument)
-                                     (54 . hydra--digit-argument)
-                                     (53 . hydra--digit-argument)
-                                     (52 . hydra--digit-argument)
-                                     (51 . hydra--digit-argument)
-                                     (50 . hydra--digit-argument)
-                                     (49 . hydra--digit-argument)
-                                     (48 . hydra--digit-argument)
-                                     (45 . hydra--negative-argument)
-                                     (21 . hydra--universal-argument))))
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (113 . hydra-toggle/nil)
+                                           (97 . hydra-toggle/abbrev-mode)
+                                           (102 . hydra-toggle/auto-fill-mode)
+                                           (116 . 
hydra-toggle/toggle-truncate-lines)
+                                           (switch-frame . 
hydra--handle-switch-frame)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
                       t (lambda nil (hydra-cleanup))))
                (setq prefix-arg current-prefix-arg)))))))
 
@@ -396,8 +399,26 @@ The body can be accessed via `hydra-toggle/body'."
        ("k" previous-line)
        ("q" nil "quit")))
     '(progn
+      (defun hydra-vi/hydra-keyboard-quit nil "Create a hydra with no body and 
the heads:
+
+\"\":    `hydra-keyboard-quit',
+\"j\":    `next-line',
+\"k\":    `previous-line',
+\"q\":    `nil'
+
+The body can be accessed via `hydra-vi/body'.
+
+Call the head: `hydra-keyboard-quit'."
+             (interactive)
+             (set-cursor-color "#e52b50")
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function hydra-keyboard-quit))
+               (set-cursor-color "#ffffff")))
       (defun hydra-vi/next-line nil "Create a hydra with no body and the heads:
 
+\"\":    `hydra-keyboard-quit',
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    `nil'
@@ -410,49 +431,51 @@ Call the head: `next-line'."
              (hydra-disable)
              (catch (quote hydra-disable)
                (condition-case err (prog1 t (call-interactively (function 
next-line)))
-                 ((quit error) (message "%S" err)
+                 ((quit error)
+                  (message "%S" err)
                   (unless hydra-lv (sit-for 0.8))
                   nil))
                (when hydra-is-helpful (hydra-vi/hint))
                (setq hydra-last
                      (hydra-set-transient-map
                       (setq hydra-curr-map
-                            (quote
-                             (keymap (t lambda nil (interactive)
-                                        (message "An amaranth Hydra can only 
exit through a blue head")
-                                        (hydra-set-transient-map 
hydra-curr-map t)
-                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
-                                              (hydra-vi/hint)))
-                                     (7 . hydra-keyboard-quit)
-                                     (113 . hydra-vi/nil)
-                                     (107 . hydra-vi/previous-line)
-                                     (106 . hydra-vi/next-line)
-                                     (kp-subtract . hydra--negative-argument)
-                                     (kp-9 . hydra--digit-argument)
-                                     (kp-8 . hydra--digit-argument)
-                                     (kp-7 . hydra--digit-argument)
-                                     (kp-6 . hydra--digit-argument)
-                                     (kp-5 . hydra--digit-argument)
-                                     (kp-4 . hydra--digit-argument)
-                                     (kp-3 . hydra--digit-argument)
-                                     (kp-2 . hydra--digit-argument)
-                                     (kp-1 . hydra--digit-argument)
-                                     (kp-0 . hydra--digit-argument)
-                                     (57 . hydra--digit-argument)
-                                     (56 . hydra--digit-argument)
-                                     (55 . hydra--digit-argument)
-                                     (54 . hydra--digit-argument)
-                                     (53 . hydra--digit-argument)
-                                     (52 . hydra--digit-argument)
-                                     (51 . hydra--digit-argument)
-                                     (50 . hydra--digit-argument)
-                                     (49 . hydra--digit-argument)
-                                     (48 . hydra--digit-argument)
-                                     (45 . hydra--negative-argument)
-                                     (21 . hydra--universal-argument))))
+                            (quote (keymap (t lambda nil (interactive)
+                                              (message "An amaranth Hydra can 
only exit through a blue head")
+                                              (hydra-set-transient-map 
hydra-curr-map t)
+                                              (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                                    (hydra-vi/hint)))
+                                           (113 . hydra-vi/nil)
+                                           (107 . hydra-vi/previous-line)
+                                           (106 . hydra-vi/next-line)
+                                           (7 . hydra-vi/hydra-keyboard-quit)
+                                           (switch-frame . 
hydra--handle-switch-frame)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
                       t (lambda nil (hydra-cleanup))))))
       (defun hydra-vi/previous-line nil "Create a hydra with no body and the 
heads:
 
+\"\":    `hydra-keyboard-quit',
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    `nil'
@@ -465,49 +488,51 @@ Call the head: `previous-line'."
              (hydra-disable)
              (catch (quote hydra-disable)
                (condition-case err (prog1 t (call-interactively (function 
previous-line)))
-                 ((quit error) (message "%S" err)
+                 ((quit error)
+                  (message "%S" err)
                   (unless hydra-lv (sit-for 0.8))
                   nil))
                (when hydra-is-helpful (hydra-vi/hint))
                (setq hydra-last
                      (hydra-set-transient-map
                       (setq hydra-curr-map
-                            (quote
-                             (keymap (t lambda nil (interactive)
-                                        (message "An amaranth Hydra can only 
exit through a blue head")
-                                        (hydra-set-transient-map 
hydra-curr-map t)
-                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
-                                              (hydra-vi/hint)))
-                                     (7 . hydra-keyboard-quit)
-                                     (113 . hydra-vi/nil)
-                                     (107 . hydra-vi/previous-line)
-                                     (106 . hydra-vi/next-line)
-                                     (kp-subtract . hydra--negative-argument)
-                                     (kp-9 . hydra--digit-argument)
-                                     (kp-8 . hydra--digit-argument)
-                                     (kp-7 . hydra--digit-argument)
-                                     (kp-6 . hydra--digit-argument)
-                                     (kp-5 . hydra--digit-argument)
-                                     (kp-4 . hydra--digit-argument)
-                                     (kp-3 . hydra--digit-argument)
-                                     (kp-2 . hydra--digit-argument)
-                                     (kp-1 . hydra--digit-argument)
-                                     (kp-0 . hydra--digit-argument)
-                                     (57 . hydra--digit-argument)
-                                     (56 . hydra--digit-argument)
-                                     (55 . hydra--digit-argument)
-                                     (54 . hydra--digit-argument)
-                                     (53 . hydra--digit-argument)
-                                     (52 . hydra--digit-argument)
-                                     (51 . hydra--digit-argument)
-                                     (50 . hydra--digit-argument)
-                                     (49 . hydra--digit-argument)
-                                     (48 . hydra--digit-argument)
-                                     (45 . hydra--negative-argument)
-                                     (21 . hydra--universal-argument))))
+                            (quote (keymap (t lambda nil (interactive)
+                                              (message "An amaranth Hydra can 
only exit through a blue head")
+                                              (hydra-set-transient-map 
hydra-curr-map t)
+                                              (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                                    (hydra-vi/hint)))
+                                           (113 . hydra-vi/nil)
+                                           (107 . hydra-vi/previous-line)
+                                           (106 . hydra-vi/next-line)
+                                           (7 . hydra-vi/hydra-keyboard-quit)
+                                           (switch-frame . 
hydra--handle-switch-frame)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
                       t (lambda nil (hydra-cleanup))))))
       (defun hydra-vi/nil nil "Create a hydra with no body and the heads:
 
+\"\":    `hydra-keyboard-quit',
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    `nil'
@@ -530,6 +555,7 @@ Call the head: `nil'."
                              11 12 (face hydra-face-blue))))))
       (defun hydra-vi/body nil "Create a hydra with no body and the heads:
 
+\"\":    `hydra-keyboard-quit',
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    `nil'
@@ -543,39 +569,39 @@ The body can be accessed via `hydra-vi/body'."
                (setq hydra-last
                      (hydra-set-transient-map
                       (setq hydra-curr-map
-                            (quote
-                             (keymap (t lambda nil (interactive)
-                                        (message "An amaranth Hydra can only 
exit through a blue head")
-                                        (hydra-set-transient-map 
hydra-curr-map t)
-                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
-                                              (hydra-vi/hint)))
-                                     (7 . hydra-keyboard-quit)
-                                     (113 . hydra-vi/nil)
-                                     (107 . hydra-vi/previous-line)
-                                     (106 . hydra-vi/next-line)
-                                     (kp-subtract . hydra--negative-argument)
-                                     (kp-9 . hydra--digit-argument)
-                                     (kp-8 . hydra--digit-argument)
-                                     (kp-7 . hydra--digit-argument)
-                                     (kp-6 . hydra--digit-argument)
-                                     (kp-5 . hydra--digit-argument)
-                                     (kp-4 . hydra--digit-argument)
-                                     (kp-3 . hydra--digit-argument)
-                                     (kp-2 . hydra--digit-argument)
-                                     (kp-1 . hydra--digit-argument)
-                                     (kp-0 . hydra--digit-argument)
-                                     (57 . hydra--digit-argument)
-                                     (56 . hydra--digit-argument)
-                                     (55 . hydra--digit-argument)
-                                     (54 . hydra--digit-argument)
-                                     (53 . hydra--digit-argument)
-                                     (52 . hydra--digit-argument)
-                                     (51 . hydra--digit-argument)
-                                     (50 . hydra--digit-argument)
-                                     (49 . hydra--digit-argument)
-                                     (48 . hydra--digit-argument)
-                                     (45 . hydra--negative-argument)
-                                     (21 . hydra--universal-argument))))
+                            (quote (keymap (t lambda nil (interactive)
+                                              (message "An amaranth Hydra can 
only exit through a blue head")
+                                              (hydra-set-transient-map 
hydra-curr-map t)
+                                              (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                                    (hydra-vi/hint)))
+                                           (113 . hydra-vi/nil)
+                                           (107 . hydra-vi/previous-line)
+                                           (106 . hydra-vi/next-line)
+                                           (7 . hydra-vi/hydra-keyboard-quit)
+                                           (switch-frame . 
hydra--handle-switch-frame)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
                       t (lambda nil (hydra-cleanup))))
                (setq prefix-arg current-prefix-arg)))))))
 
@@ -837,6 +863,7 @@ Call the head: `(text-scale-set 0)'."
                       (setq hydra-curr-map
                             (quote (keymap (7 . hydra-keyboard-quit)
                                            (114 . hydra-zoom/lambda-r)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -897,6 +924,7 @@ The body can be accessed via `hydra-zoom/body'."
                       (setq hydra-curr-map
                             (quote (keymap (7 . hydra-keyboard-quit)
                                            (114 . hydra-zoom/lambda-r)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -957,6 +985,7 @@ Call the head: `(text-scale-set 0)'."
                       (setq hydra-curr-map
                             (quote (keymap (7 . hydra-keyboard-quit)
                                            (114 . hydra-zoom/lambda-r)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
@@ -1017,6 +1046,7 @@ The body can be accessed via `hydra-zoom/body'."
                       (setq hydra-curr-map
                             (quote (keymap (7 . hydra-keyboard-quit)
                                            (114 . hydra-zoom/lambda-r)
+                                           (switch-frame . 
hydra--handle-switch-frame)
                                            (kp-subtract . 
hydra--negative-argument)
                                            (kp-9 . hydra--digit-argument)
                                            (kp-8 . hydra--digit-argument)
diff --git a/packages/hydra/hydra.el b/packages/hydra/hydra.el
index dcdf03b..a3e8b9b 100644
--- a/packages/hydra/hydra.el
+++ b/packages/hydra/hydra.el
@@ -188,6 +188,7 @@ Vanquishable only through a blue head.")
     (define-key map [kp-8] 'hydra--digit-argument)
     (define-key map [kp-9] 'hydra--digit-argument)
     (define-key map [kp-subtract] 'hydra--negative-argument)
+    (define-key map [switch-frame] 'hydra--handle-switch-frame)
     map)
   "Keymap that all Hydras inherit.  See `universal-argument-map'.")
 
@@ -195,6 +196,12 @@ Vanquishable only through a blue head.")
   (make-sparse-keymap)
   "Keymap of the current Hydra called.")
 
+(defun hydra--handle-switch-frame (evt)
+  "Quit hydra and call old switch-frame event handler."
+  (interactive "e")
+  (hydra-keyboard-quit)
+  (funcall (lookup-key (current-global-map) [switch-frame]) evt))
+
 (defun hydra--universal-argument (arg)
   "Forward to (`universal-argument' ARG)."
   (interactive "P")
@@ -252,13 +259,21 @@ should be a single statement.  Wrap it in an interactive 
lambda."
        (interactive)
        ,x)))
 
+(defun hydra-plist-get-default (plist prop default)
+  "Extract a value from a property list.
+PLIST is a property list, which is a list of the form
+\(PROP1 VALUE1 PROP2 VALUE2...).
+
+Return the value corresponding to PROP, or DEFAULT if PROP is not
+one of the properties on the list."
+  (if (memq prop plist)
+      (plist-get plist prop)
+    default))
+
 (defun hydra--head-property (h prop &optional default)
   "Return for Hydra head H the value of property PROP.
 Return DEFAULT if PROP is not in H."
-  (let ((plist (cl-cdddr h)))
-    (if (memq prop h)
-        (plist-get plist prop)
-      default)))
+  (hydra-plist-get-default (cl-cdddr h) prop default))
 
 (defun hydra--aggregate-color (head-color body-color)
   "Return the resulting head color for HEAD-COLOR and BODY-COLOR."
@@ -372,6 +387,8 @@ BODY is the second argument to `defhydra'"
   (hydra-disable)
   (hydra-cleanup)
   (cancel-timer hydra-timer)
+  (unless hydra-lv
+    (message ""))
   nil)
 
 (defun hydra-disable ()
@@ -464,7 +481,7 @@ The expressions can be auto-expanded according to NAME."
         offset)
     (while (setq start
                  (string-match
-                  "\\(?:%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_\\( 
?-?[0-9]*\\)\\([a-z-~A-Z0-9/|?<>={}]+\\)_\\)"
+                  "\\(?:%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_\\( 
?-?[0-9]*\\)\\([a-z-~A-Z;:0-9/|?<>={}]+\\)_\\)"
                   docstring start))
       (cond ((eq ?_ (aref (match-string 0 docstring) 0))
              (let* ((key (match-string 4 docstring))
@@ -482,7 +499,8 @@ The expressions can be auto-expanded according to NAME."
 
             ((eq ?` (aref (match-string 2 docstring) 0))
              (push (hydra--unalias-var
-                    (substring (match-string 2 docstring) 1) prefix) varlist)
+                    (substring (match-string 2 docstring) 1) prefix)
+                   varlist)
              (setq docstring
                    (replace-match
                     (concat "%" (match-string 1 docstring) "S")
@@ -490,13 +508,14 @@ The expressions can be auto-expanded according to NAME."
 
             (t
              (let* ((spec (match-string 1 docstring))
-                    (lspec (length spec)))
+                    (lspec (length spec))
+                    (me2 (match-end 2)))
                (setq offset
                      (with-temp-buffer
                        (insert (substring docstring (+ 1 start (length spec))))
                        (goto-char (point-min))
                        (push (read (current-buffer)) varlist)
-                       (point)))
+                       (- (point) (point-min))))
                (when (or (zerop lspec)
                          (/= (aref spec (1- (length spec))) ?s))
                  (setq spec (concat spec "S")))
@@ -504,8 +523,7 @@ The expressions can be auto-expanded according to NAME."
                      (concat
                       (substring docstring 0 start)
                       "%" spec
-                      (substring docstring
-                                 (+ (match-end 2) offset -2))))))))
+                      (substring docstring (+ me2 offset -1))))))))
     (if (eq ?\n (aref docstring 0))
         `(concat (format ,(substring docstring 1) ,@(nreverse varlist))
                  ,rest)
@@ -595,7 +613,10 @@ OTHER-POST is an optional extension to the :post key of 
BODY."
                                   `(lambda () (hydra-cleanup)))))
                       ,(or other-post
                            (when body-timeout
-                             `(hydra-timeout ,body-timeout))))))))))
+                             (list 'hydra-timeout
+                                   body-timeout
+                                   (when body-post
+                                     (hydra--make-callable 
body-post))))))))))))
 
 (defun hydra-pink-fallback ()
   "On intercepting a non-head, try to run it."
@@ -615,33 +636,55 @@ OTHER-POST is an optional extension to the :post key of 
BODY."
           (message "Pink Hydra can't currently handle prefixes, continuing"))
       (message "Pink Hydra could not resolve: %S" keys))))
 
+(defun hydra--modify-keymap (keymap def)
+  "In KEYMAP, add DEF to each sub-keymap."
+  (cl-labels
+      ((recur (map)
+         (if (atom map)
+             map
+           (if (eq (car map) 'keymap)
+               (cons 'keymap
+                     (cons
+                      def
+                      (recur (cdr map))))
+             (cons
+              (recur (car map))
+              (recur (cdr map)))))))
+    (recur keymap)))
+
 (defun hydra--handle-nonhead (keymap name body heads)
   "Setup KEYMAP for intercepting non-head bindings.
 NAME, BODY and HEADS are parameters to `defhydra'."
   (let ((body-color (hydra--body-color body))
         (body-post (plist-get (cddr body) :post)))
-    (when (and body-post (symbolp body-post))
-      (setq body-post `(funcall #',body-post)))
-    (when hydra-keyboard-quit
-      (define-key keymap hydra-keyboard-quit #'hydra-keyboard-quit))
+    (if body-post
+        (when (symbolp body-post)
+          (setq body-post `(funcall #',body-post)))
+      (when hydra-keyboard-quit
+        (define-key keymap hydra-keyboard-quit #'hydra-keyboard-quit)))
     (when (memq body-color '(amaranth pink teal))
-      (if (cl-some `(lambda (h)
-                      (memq (hydra--head-color h body) '(blue teal)))
+      (if (cl-some (lambda (h)
+                     (memq (hydra--head-color h body) '(blue teal)))
                    heads)
           (progn
-            (define-key keymap [t]
-              `(lambda ()
-                 (interactive)
-                 ,(cond
-                   ((memq body-color '(amaranth teal))
-                    '(message "An amaranth Hydra can only exit through a blue 
head"))
-                   (t
-                    '(hydra-pink-fallback)))
-                 (hydra-set-transient-map hydra-curr-map t)
-                 (when hydra-is-helpful
-                   (unless hydra-lv
-                     (sit-for 0.8))
-                   (,(intern (format "%S/hint" name)))))))
+            (setcdr
+             keymap
+             (cdr
+              (hydra--modify-keymap
+               keymap
+               (cons t
+                     `(lambda ()
+                        (interactive)
+                        ,(cond
+                          ((memq body-color '(amaranth teal))
+                           '(message "An amaranth Hydra can only exit through 
a blue head"))
+                          (t
+                           '(hydra-pink-fallback)))
+                        (hydra-set-transient-map hydra-curr-map t)
+                        (when hydra-is-helpful
+                          (unless hydra-lv
+                            (sit-for 0.8))
+                          (,(intern (format "%S/hint" name))))))))))
         (unless (eq body-color 'teal)
           (error
            "An %S Hydra must have at least one blue head in order to exit"
@@ -758,16 +801,18 @@ NAMES should be defined by `defhydradio' or similar."
   "Timer for `hydra-timeout'.")
 
 (defun hydra-timeout (secs &optional function)
-  "In SECS seconds call FUNCTION.
-FUNCTION defaults to `hydra-disable'.
+  "In SECS seconds call FUNCTION, then `hydra-keyboard-quit'.
 Cancel the previous `hydra-timeout'."
   (cancel-timer hydra-timer)
   (setq hydra-timer (timer-create))
   (timer-set-time hydra-timer
-                  (timer-relative-time nil secs))
+                  (timer-relative-time (current-time) secs))
   (timer-set-function
    hydra-timer
-   (or function #'hydra-keyboard-quit))
+   `(lambda ()
+      ,(when function
+             `(funcall ,function))
+      (hydra-keyboard-quit)))
   (timer-activate hydra-timer))
 
 ;;* Macros
@@ -833,60 +878,68 @@ result of `defhydra'."
          (setq docstring "hydra")))
   (when (keywordp (car body))
     (setq body (cons nil (cons nil body))))
-  (dolist (h heads)
-    (let ((len (length h))
-          (cmd-name (hydra--head-name h name)))
-      (cond ((< len 2)
-             (error "Each head should have at least two items: %S" h))
-            ((= len 2)
-             (setcdr (cdr h) `("" :cmd-name ,cmd-name)))
-            (t
-             (let ((hint (cl-caddr h)))
-               (unless (or (null hint)
-                           (stringp hint))
-                 (setcdr (cdr h) (cons "" (cddr h))))
-               (setcdr (cddr h) `(:cmd-name ,cmd-name ,@(cl-cdddr h))))))))
-  (let* ((keymap (copy-keymap hydra-base-map))
-         (body-name (intern (format "%S/body" name)))
-         (body-key (unless (hydra--callablep body)
-                     (cadr body)))
-         (body-color (hydra--body-color body))
-         (body-pre (plist-get (cddr body) :pre))
-         (body-body-pre (plist-get (cddr body) :body-pre))
-         (body-post (plist-get (cddr body) :post))
-         (method (or (plist-get body :bind)
-                     (car body)))
-         (doc (hydra--doc body-key body-name heads))
-         (heads-nodup (hydra--delete-duplicates heads)))
-    (mapc
-     (lambda (x)
-       (define-key keymap (kbd (car x))
-         (plist-get (cl-cdddr x) :cmd-name)))
-     heads)
-    (when (and body-pre (symbolp body-pre))
-      (setq body-pre `(funcall #',body-pre)))
-    (when (and body-body-pre (symbolp body-body-pre))
-      (setq body-body-pre `(funcall #',body-body-pre)))
-    (when (and body-post (symbolp body-post))
-      (setq body-post `(funcall #',body-post)))
-    (hydra--handle-nonhead keymap name body heads)
-    `(progn
-       ,@(mapcar
-          (lambda (head)
-            (hydra--make-defun name body doc head keymap
-                               body-pre body-post))
-          heads-nodup)
-       ,@(unless (or (null body-key)
-                     (null method)
-                     (hydra--callablep method))
-                 `((unless (keymapp (lookup-key ,method (kbd ,body-key)))
-                     (define-key ,method (kbd ,body-key) nil))))
-       ,@(delq nil
-               (cl-mapcar
-                (lambda (head)
-                  (let ((name (hydra--head-property head :cmd-name)))
-                    (when (cadr head)
-                      (when (or body-key method)
+  (let ((keymap (copy-keymap hydra-base-map))
+        (body-name (intern (format "%S/body" name)))
+        (body-key (cadr body))
+        (body-color (hydra--body-color body))
+        (body-pre (plist-get (cddr body) :pre))
+        (body-body-pre (plist-get (cddr body) :body-pre))
+        (body-post (plist-get (cddr body) :post))
+        (method (or (plist-get body :bind)
+                    (car body))))
+    (when body-post
+      (when (symbolp body-post)
+        (setq body-post `(funcall #',body-post)))
+      (setq heads (cons (list hydra-keyboard-quit #'hydra-keyboard-quit nil 
:exit t)
+                        heads)))
+    (dolist (h heads)
+      (let ((len (length h))
+            (cmd-name (hydra--head-name h name)))
+        (cond ((< len 2)
+               (error "Each head should have at least two items: %S" h))
+              ((= len 2)
+               (setcdr (cdr h)
+                       (list
+                        (hydra-plist-get-default (cddr body) :hint "")
+                        :cmd-name cmd-name)))
+              (t
+               (let ((hint (cl-caddr h)))
+                 (unless (or (null hint)
+                             (stringp hint))
+                   (setcdr (cdr h) (cons
+                                    (hydra-plist-get-default (cddr body) :hint 
"")
+                                    (cddr h))))
+                 (setcdr (cddr h) `(:cmd-name ,cmd-name ,@(cl-cdddr h))))))))
+    (let ((doc (hydra--doc body-key body-name heads))
+          (heads-nodup (hydra--delete-duplicates heads)))
+      (mapc
+       (lambda (x)
+         (define-key keymap (kbd (car x))
+           (plist-get (cl-cdddr x) :cmd-name)))
+       heads)
+      (when (and body-pre (symbolp body-pre))
+        (setq body-pre `(funcall #',body-pre)))
+      (when (and body-body-pre (symbolp body-body-pre))
+        (setq body-body-pre `(funcall #',body-body-pre)))
+      (hydra--handle-nonhead keymap name body heads)
+      `(progn
+         ,@(mapcar
+            (lambda (head)
+              (hydra--make-defun name body doc head keymap
+                                 body-pre body-post))
+            heads-nodup)
+         ,@(unless (or (null body-key)
+                       (null method)
+                       (hydra--callablep method))
+                   `((unless (keymapp (lookup-key ,method (kbd ,body-key)))
+                       (define-key ,method (kbd ,body-key) nil))))
+         ,@(delq nil
+                 (cl-mapcar
+                  (lambda (head)
+                    (let ((name (hydra--head-property head :cmd-name)))
+                      (when (and (cadr head)
+                                 (not (eq (cadr head) 'hydra-keyboard-quit))
+                                 (or body-key method))
                         (let ((bind (hydra--head-property head :bind 'default))
                               (final-key
                                (if body-key
@@ -909,15 +962,15 @@ result of `defhydra'."
                                            (function ,name)))
 
                                 (t
-                                 (error "Invalid :bind property %S" 
head))))))))
-                heads))
-       (defun ,(intern (format "%S/hint" name)) ()
-         ,(hydra--message name body docstring heads))
-       ,(hydra--make-defun
-         name body doc '(nil body)
-         keymap
-         (or body-body-pre body-pre) body-post
-         '(setq prefix-arg current-prefix-arg)))))
+                                 (error "Invalid :bind property %S" head)))))))
+                  heads))
+         (defun ,(intern (format "%S/hint" name)) ()
+           ,(hydra--message name body docstring heads))
+         ,(hydra--make-defun
+           name body doc '(nil body)
+           keymap
+           (or body-body-pre body-pre) body-post
+           '(setq prefix-arg current-prefix-arg))))))
 
 (defmacro defhydradio (name body &rest heads)
   "Create radios with prefix NAME.
@@ -982,7 +1035,7 @@ DOC defaults to TOGGLE-NAME split and capitalized."
               (while (< i l)
                 (if (equal (aref range i) val)
                     (throw 'done (1+ i))
-                  (incf i)))
+                  (cl-incf i)))
               (error "Val not in range for %S" sym)))
     (set sym
          (aref range
diff --git a/packages/hydra/lv.el b/packages/hydra/lv.el
index 7b19074..ee5a739 100644
--- a/packages/hydra/lv.el
+++ b/packages/hydra/lv.el
@@ -41,7 +41,6 @@
   (if (window-live-p lv-wnd)
       lv-wnd
     (let ((ori (selected-window))
-          (golden-ratio-mode nil)
           buf)
       (prog1 (setq lv-wnd
                    (select-window
@@ -50,7 +49,7 @@
         (if (setq buf (get-buffer "*LV*"))
             (switch-to-buffer buf)
           (switch-to-buffer "*LV*")
-          (setq truncate-lines nil)
+          (set-window-hscroll lv-wnd 0)
           (setq mode-line-format nil)
           (setq cursor-type nil)
           (set-window-dedicated-p lv-wnd t)
@@ -59,13 +58,17 @@
 
 (defun lv-message (format-string &rest args)
   "Set LV window contents to (`format' FORMAT-STRING ARGS)."
-  (let ((ori (selected-window))
-        (str (apply #'format format-string args))
-        deactivate-mark)
+  (let* ((ori (selected-window))
+         (str (apply #'format format-string args))
+         (n-lines (cl-count ?\n str))
+         deactivate-mark
+         golden-ratio-mode)
     (select-window (lv-window))
     (unless (string= (buffer-string) str)
       (delete-region (point-min) (point-max))
       (insert str)
+      (setq-local window-min-height n-lines)
+      (setq truncate-lines (> n-lines 1))
       (fit-window-to-buffer nil nil 1))
     (goto-char (point-min))
     (select-window ori)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]