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

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

[elpa] externals/hydra 7081ee6d44 46/46: Merge commit 'f27fce1b2f0a9162e


From: Stefan Monnier
Subject: [elpa] externals/hydra 7081ee6d44 46/46: Merge commit 'f27fce1b2f0a9162e159557bdeb2c0c94defb4d2' into externals/hydra
Date: Tue, 25 Oct 2022 22:27:23 -0400 (EDT)

branch: externals/hydra
commit 7081ee6d443dbf2b58e77fa7357c90e495173a2f
Merge: 4532f40ae4 f27fce1b2f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>

    Merge commit 'f27fce1b2f0a9162e159557bdeb2c0c94defb4d2' into externals/hydra
---
 README.md         |  13 +-
 doc/Changelog.org |  69 +++++
 hydra-examples.el |  11 +-
 hydra-test.el     | 783 ++++++++++++++++++++++++++++++++----------------------
 hydra.el          | 469 ++++++++++++++++++++------------
 lv.el             |   3 +
 6 files changed, 866 insertions(+), 482 deletions(-)

diff --git a/README.md b/README.md
index d2237d8118..35aedcacfa 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,8 @@
+# Hydra
+
 [![Build 
Status](https://travis-ci.org/abo-abo/hydra.svg?branch=master)](https://travis-ci.org/abo-abo/hydra)
+[![MELPA](https://melpa.org/packages/hydra-badge.svg)](https://melpa.org/#/hydra)
+[![MELPA 
Stable](https://stable.melpa.org/packages/hydra-badge.svg)](https://stable.melpa.org/#/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.
@@ -326,6 +330,9 @@ 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.
 
+### `:base-map`
+Use this option if you want to override `hydra-base-map` for the current hydra.
+
 ## `awesome-docstring`
 
 This can be a simple string used to build the final hydra hint.  However, if 
you start it with a
@@ -399,7 +406,7 @@ Here's an example of the last option:
 ### `head-hint`
 
 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've already documented it in the body docstring.
 You can set the head hint to `nil` to do this.
 
 Example:
@@ -420,3 +427,7 @@ Here's a list of body keys that can be overridden in each 
head:
 - `:exit`
 - `:color`
 - `:bind`
+- `:column`
+
+Use `:column` feature to have an aligned rectangular docstring without 
defining it manually.
+See 
[hydra-examples.el](https://github.com/abo-abo/hydra/blob/05871dd6c8af7b2268bd1a10eb9f8a3e423209cd/hydra-examples.el#L337)
 for an example code.
diff --git a/doc/Changelog.org b/doc/Changelog.org
new file mode 100644
index 0000000000..429a7ddd8c
--- /dev/null
+++ b/doc/Changelog.org
@@ -0,0 +1,69 @@
+* 0.15.0
+** New Features
+
+*** defhydra
+
+**** New :base-map option in body plist
+In case your hydra conficts with el:hydra-base-map, you can now override it.
+
+Example:
+#+begin_src elisp
+(defhydra hydra-numbers (:base-map (make-sparse-keymap))
+  "test"
+  ("0" (message "zero"))
+  ("1" (message "one")))
+#+end_src
+See [[https://github.com/abo-abo/hydra/issues/285][#285]].
+
+**** Make no docstring equivalent to :hint nil
+Example:
+#+begin_src elisp
+(defhydra hydra-clock (:color blue)
+  ("q" nil "quit" :column "Clock")
+  ("c" org-clock-cancel "cancel" :color pink :column "Do")
+  ("d" org-clock-display "display")
+  ("e" org-clock-modify-effort-estimate "effort")
+  ("i" org-clock-in "in")
+  ("j" org-clock-goto "jump")
+  ("o" org-clock-out "out")
+  ("r" org-clock-report "report"))
+#+end_src
+See [[https://github.com/abo-abo/hydra/issues/291][#291]].
+
+**** Declare /params and /docstring
+See [[https://github.com/abo-abo/hydra/issues/185][#185]].
+
+**** Sexp hints are now supported for :columns
+Example
+#+begin_src elisp
+(defhydra hydra-test ()
+  "Test"
+  ("j" next-line (format-time-string "%H:%M:%S" (current-time)) :column "One")
+  ("k" previous-line (format-time-string "%H:%M:%S" (current-time)))
+  ("l" backward-char "back" :column "Two"))
+#+end_src
+See [[https://github.com/abo-abo/hydra/issues/311][#311]].
+
+
+*** defhydra+
+New macro. Allows to add heads to an existing hydra.
+
+Example:
+#+begin_src elisp
+(defhydra hydra-extendable ()
+  "extendable"
+  ("j" next-line "down"))
+
+(defhydra+ hydra-extendable ()
+  ("k" previous-line "up"))
+#+end_src
+See [[https://github.com/abo-abo/hydra/issues/185][#185]].
+
+*** el:hydra-hint-display-type
+Customize what to use to display the hint:
+- el:message
+- el:lv-message
+- posframe
+
+el:hydra-lv is now obsolete.
+See [[https://github.com/abo-abo/hydra/issues/317][#317]].
diff --git a/hydra-examples.el b/hydra-examples.el
index 70f75b0ea4..5262ec60cb 100644
--- a/hydra-examples.el
+++ b/hydra-examples.el
@@ -270,7 +270,7 @@ _v_ariable       _u_ser-option
 _h_   _l_   _o_k        _y_ank
   ^_j_^     _n_ew-copy  _r_eset
 ^^^^        _e_xchange  _u_ndo
-^^^^        ^ ^         _p_aste
+^^^^        ^ ^         _x_kill
 "
   ("h" rectangle-backward-char nil)
   ("l" rectangle-forward-char nil)
@@ -285,7 +285,7 @@ _h_   _l_   _o_k        _y_ank
   ("y" yank-rectangle nil)
   ("u" undo nil)
   ("s" string-rectangle nil)
-  ("p" kill-rectangle nil)
+  ("x" kill-rectangle nil)
   ("o" nil nil))
 
 ;; Recommended binding:
@@ -333,6 +333,13 @@ _y_: ?y? year       _q_: quit           _L__l__c_: log = 
?l?"
 ;; Recommended binding:
 ;; (define-key org-agenda-mode-map "v" 'hydra-org-agenda-view/body)
 
+;;** Example 13: automatic columns
+(defhydra hydra-movement ()
+  ("j" next-line "down" :column "Vertical")
+  ("k" previous-line "up")
+  ("l" forward-char "forward" :column "Horizontal")
+  ("h" backward-char "back"))
+
 ;;* Helpers
 (require 'windmove)
 
diff --git a/hydra-test.el b/hydra-test.el
index 4618d6b103..66f5c6e6ea 100644
--- a/hydra-test.el
+++ b/hydra-test.el
@@ -40,6 +40,35 @@
        ("k" previous-error "prev")
        ("SPC" hydra-repeat "rep" :bind nil)))
     '(progn
+      (set
+       (defvar hydra-error/params nil
+         "Params of hydra-error.")
+       (quote (global-map "M-g")))
+      (set
+       (defvar hydra-error/docstring nil
+         "Docstring of hydra-error.")
+       "error")
+      (set
+       (defvar hydra-error/heads nil
+         "Heads for hydra-error.")
+       (quote
+        (("h"
+          first-error
+          "first"
+          :exit nil)
+         ("j"
+          next-error
+          "next"
+          :exit nil)
+         ("k"
+          previous-error
+          "prev"
+          :exit nil)
+         ("SPC"
+          hydra-repeat
+          "rep"
+          :bind nil
+          :exit nil))))
       (set
        (defvar hydra-error/keymap nil
          "Keymap for hydra-error.")
@@ -72,27 +101,6 @@
          (48 . hydra--digit-argument)
          (45 . hydra--negative-argument)
          (21 . hydra--universal-argument))))
-      (set
-       (defvar hydra-error/heads nil
-         "Heads for hydra-error.")
-       (quote
-        (("h"
-          first-error
-          "first"
-          :exit nil)
-         ("j"
-          next-error
-          "next"
-          :exit nil)
-         ("k"
-          previous-error
-          "prev"
-          :exit nil)
-         ("SPC"
-          hydra-repeat
-          "rep"
-          :bind nil
-          :exit nil))))
       (set
        (defvar hydra-error/hint nil
          "Dynamic hint for hydra-error.")
@@ -104,17 +112,18 @@
            31 32 (face hydra-face-red)
            42 45 (face hydra-face-red)))))
       (defun hydra-error/first-error nil
-        "Create a hydra with a \"M-g\" body and the heads:
+        "Call the head `first-error' in the \"hydra-error\" hydra.
+
+The heads for the associated hydra are:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
 \"k\":    `previous-error',
 \"SPC\":    `hydra-repeat'
 
-The body can be accessed via `hydra-error/body'.
-
-Call the head: `first-error'."
+The body can be accessed via `hydra-error/body', which is bound to \"M-g\"."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore t))
           (hydra-keyboard-quit)
@@ -128,8 +137,7 @@ Call the head: `first-error'."
                (function first-error)))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-error/hint
          (quote hydra-error))
@@ -140,17 +148,18 @@ Call the head: `first-error'."
            nil)
          nil))
       (defun hydra-error/next-error nil
-        "Create a hydra with a \"M-g\" body and the heads:
+        "Call the head `next-error' in the \"hydra-error\" hydra.
+
+The heads for the associated hydra are:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
 \"k\":    `previous-error',
 \"SPC\":    `hydra-repeat'
 
-The body can be accessed via `hydra-error/body'.
-
-Call the head: `next-error'."
+The body can be accessed via `hydra-error/body', which is bound to \"M-g\"."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore t))
           (hydra-keyboard-quit)
@@ -164,8 +173,7 @@ Call the head: `next-error'."
                (function next-error)))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-error/hint
          (quote hydra-error))
@@ -176,17 +184,18 @@ Call the head: `next-error'."
            nil)
          nil))
       (defun hydra-error/previous-error nil
-        "Create a hydra with a \"M-g\" body and the heads:
+        "Call the head `previous-error' in the \"hydra-error\" hydra.
+
+The heads for the associated hydra are:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
 \"k\":    `previous-error',
 \"SPC\":    `hydra-repeat'
 
-The body can be accessed via `hydra-error/body'.
-
-Call the head: `previous-error'."
+The body can be accessed via `hydra-error/body', which is bound to \"M-g\"."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore t))
           (hydra-keyboard-quit)
@@ -200,8 +209,7 @@ Call the head: `previous-error'."
                (function previous-error)))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-error/hint
          (quote hydra-error))
@@ -225,15 +233,18 @@ Call the head: `previous-error'."
        (quote
         hydra-error/previous-error))
       (defun hydra-error/body nil
-        "Create a hydra with a \"M-g\" body and the heads:
+        "Call the body in the \"hydra-error\" hydra.
+
+The heads for the associated hydra are:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
 \"k\":    `previous-error',
 \"SPC\":    `hydra-repeat'
 
-The body can be accessed via `hydra-error/body'."
+The body can be accessed via `hydra-error/body', which is bound to \"M-g\"."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore nil))
           (hydra-keyboard-quit)
@@ -262,6 +273,35 @@ The body can be accessed via `hydra-error/body'."
        ("a" abbrev-mode "abbrev")
        ("q" nil "cancel")))
     '(progn
+      (set
+       (defvar hydra-toggle/params nil
+         "Params of hydra-toggle.")
+       (quote
+        (nil
+         nil
+         :exit t
+         :foreign-keys nil)))
+      (set
+       (defvar hydra-toggle/docstring nil
+         "Docstring of hydra-toggle.")
+       "toggle")
+      (set
+       (defvar hydra-toggle/heads nil
+         "Heads for hydra-toggle.")
+       (quote
+        (("t"
+          toggle-truncate-lines
+          "truncate"
+          :exit t)
+         ("f"
+          auto-fill-mode
+          "fill"
+          :exit t)
+         ("a"
+          abbrev-mode
+          "abbrev"
+          :exit t)
+         ("q" nil "cancel" :exit t))))
       (set
        (defvar hydra-toggle/keymap nil
          "Keymap for hydra-toggle.")
@@ -294,23 +334,6 @@ The body can be accessed via `hydra-error/body'."
          (48 . hydra--digit-argument)
          (45 . hydra--negative-argument)
          (21 . hydra--universal-argument))))
-      (set
-       (defvar hydra-toggle/heads nil
-         "Heads for hydra-toggle.")
-       (quote
-        (("t"
-          toggle-truncate-lines
-          "truncate"
-          :exit t)
-         ("f"
-          auto-fill-mode
-          "fill"
-          :exit t)
-         ("a"
-          abbrev-mode
-          "abbrev"
-          :exit t)
-         ("q" nil "cancel" :exit t))))
       (set
        (defvar hydra-toggle/hint nil
          "Dynamic hint for hydra-toggle.")
@@ -322,17 +345,18 @@ The body can be accessed via `hydra-error/body'."
            35 36 (face hydra-face-blue)
            48 49 (face hydra-face-blue)))))
       (defun hydra-toggle/toggle-truncate-lines-and-exit nil
-        "Create a hydra with no body and the heads:
+        "Call the head `toggle-truncate-lines' in the \"hydra-toggle\" hydra.
+
+The heads for the associated hydra are:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    nil
 
-The body can be accessed via `hydra-toggle/body'.
-
-Call the head: `toggle-truncate-lines'."
+The body can be accessed via `hydra-toggle/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
@@ -344,17 +368,18 @@ Call the head: `toggle-truncate-lines'."
            (function
             toggle-truncate-lines))))
       (defun hydra-toggle/auto-fill-mode-and-exit nil
-        "Create a hydra with no body and the heads:
+        "Call the head `auto-fill-mode' in the \"hydra-toggle\" hydra.
+
+The heads for the associated hydra are:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    nil
 
-The body can be accessed via `hydra-toggle/body'.
-
-Call the head: `auto-fill-mode'."
+The body can be accessed via `hydra-toggle/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
@@ -365,17 +390,18 @@ Call the head: `auto-fill-mode'."
           (hydra--call-interactively-remap-maybe
            (function auto-fill-mode))))
       (defun hydra-toggle/abbrev-mode-and-exit nil
-        "Create a hydra with no body and the heads:
+        "Call the head `abbrev-mode' in the \"hydra-toggle\" hydra.
+
+The heads for the associated hydra are:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    nil
 
-The body can be accessed via `hydra-toggle/body'.
-
-Call the head: `abbrev-mode'."
+The body can be accessed via `hydra-toggle/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
@@ -386,23 +412,26 @@ Call the head: `abbrev-mode'."
           (hydra--call-interactively-remap-maybe
            (function abbrev-mode))))
       (defun hydra-toggle/nil nil
-        "Create a hydra with no body and the heads:
+        "Call the head `nil' in the \"hydra-toggle\" hydra.
+
+The heads for the associated hydra are:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    nil
 
-The body can be accessed via `hydra-toggle/body'.
-
-Call the head: nil."
+The body can be accessed via `hydra-toggle/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
               (quote hydra-toggle/body)))
       (defun hydra-toggle/body nil
-        "Create a hydra with no body and the heads:
+        "Call the body in the \"hydra-toggle\" hydra.
+
+The heads for the associated hydra are:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
@@ -411,6 +440,7 @@ Call the head: nil."
 
 The body can be accessed via `hydra-toggle/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore nil))
           (hydra-keyboard-quit)
@@ -443,6 +473,30 @@ The body can be accessed via `hydra-toggle/body'."
        ("k" previous-line)
        ("q" nil "quit")))
     '(progn
+      (set
+       (defvar hydra-vi/params nil
+         "Params of hydra-vi.")
+       (quote
+        (nil
+         nil
+         :exit nil
+         :foreign-keys warn
+         :post (set-cursor-color "#ffffff")
+         :pre (set-cursor-color "#e52b50"))))
+      (set
+       (defvar hydra-vi/docstring nil
+         "Docstring of hydra-vi.")
+       "vi")
+      (set
+       (defvar hydra-vi/heads nil
+         "Heads for hydra-vi.")
+       (quote
+        (("j" next-line "" :exit nil)
+         ("k"
+          previous-line
+          ""
+          :exit nil)
+         ("q" nil "quit" :exit t))))
       (set
        (defvar hydra-vi/keymap nil
          "Keymap for hydra-vi.")
@@ -474,16 +528,6 @@ The body can be accessed via `hydra-toggle/body'."
          (48 . hydra--digit-argument)
          (45 . hydra--negative-argument)
          (21 . hydra--universal-argument))))
-      (set
-       (defvar hydra-vi/heads nil
-         "Heads for hydra-vi.")
-       (quote
-        (("j" next-line "" :exit nil)
-         ("k"
-          previous-line
-          ""
-          :exit nil)
-         ("q" nil "quit" :exit t))))
       (set
        (defvar hydra-vi/hint nil
          "Dynamic hint for hydra-vi.")
@@ -494,16 +538,17 @@ The body can be accessed via `hydra-toggle/body'."
            7 8 (face hydra-face-amaranth)
            11 12 (face hydra-face-teal)))))
       (defun hydra-vi/next-line nil
-        "Create a hydra with no body and the heads:
+        "Call the head `next-line' in the \"hydra-vi\" hydra.
+
+The heads for the associated hydra are:
 
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    nil
 
-The body can be accessed via `hydra-vi/body'.
-
-Call the head: `next-line'."
+The body can be accessed via `hydra-vi/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (set-cursor-color "#e52b50")
         (let ((hydra--ignore t))
@@ -518,8 +563,7 @@ Call the head: `next-line'."
                (function next-line)))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-vi/hint
          (quote hydra-vi))
@@ -530,16 +574,17 @@ Call the head: `next-line'."
            (set-cursor-color "#ffffff"))
          (quote warn)))
       (defun hydra-vi/previous-line nil
-        "Create a hydra with no body and the heads:
+        "Call the head `previous-line' in the \"hydra-vi\" hydra.
+
+The heads for the associated hydra are:
 
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    nil
 
-The body can be accessed via `hydra-vi/body'.
-
-Call the head: `previous-line'."
+The body can be accessed via `hydra-vi/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (set-cursor-color "#e52b50")
         (let ((hydra--ignore t))
@@ -554,8 +599,7 @@ Call the head: `previous-line'."
                (function previous-line)))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-vi/hint
          (quote hydra-vi))
@@ -566,23 +610,26 @@ Call the head: `previous-line'."
            (set-cursor-color "#ffffff"))
          (quote warn)))
       (defun hydra-vi/nil nil
-        "Create a hydra with no body and the heads:
+        "Call the head `nil' in the \"hydra-vi\" hydra.
+
+The heads for the associated hydra are:
 
 \"j\":    `next-line',
 \"k\":    `previous-line',
 \"q\":    nil
 
-The body can be accessed via `hydra-vi/body'.
-
-Call the head: nil."
+The body can be accessed via `hydra-vi/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (set-cursor-color "#e52b50")
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
               (quote hydra-vi/body)))
       (defun hydra-vi/body nil
-        "Create a hydra with no body and the heads:
+        "Call the body in the \"hydra-vi\" hydra.
+
+The heads for the associated hydra are:
 
 \"j\":    `next-line',
 \"k\":    `previous-line',
@@ -590,6 +637,7 @@ Call the head: nil."
 
 The body can be accessed via `hydra-vi/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (set-cursor-color "#e52b50")
         (let ((hydra--ignore nil))
@@ -618,6 +666,32 @@ The body can be accessed via `hydra-vi/body'."
        ("0" (text-scale-set 0) :bind nil :exit t)
        ("1" (text-scale-set 0) nil :bind nil :exit t)))
     '(progn
+      (set
+       (defvar hydra-zoom/params nil
+         "Params of hydra-zoom.")
+       (quote (nil nil)))
+      (set
+       (defvar hydra-zoom/docstring nil
+         "Docstring of hydra-zoom.")
+       "zoom")
+      (set
+       (defvar hydra-zoom/heads nil
+         "Heads for hydra-zoom.")
+       (quote
+        (("r"
+          (text-scale-set 0)
+          "reset"
+          :exit nil)
+         ("0"
+          (text-scale-set 0)
+          ""
+          :bind nil
+          :exit t)
+         ("1"
+          (text-scale-set 0)
+          nil
+          :bind nil
+          :exit t))))
       (set
        (defvar hydra-zoom/keymap nil
          "Keymap for hydra-zoom.")
@@ -647,24 +721,6 @@ The body can be accessed via `hydra-vi/body'."
          (48 . hydra-zoom/lambda-0-and-exit)
          (45 . hydra--negative-argument)
          (21 . hydra--universal-argument))))
-      (set
-       (defvar hydra-zoom/heads nil
-         "Heads for hydra-zoom.")
-       (quote
-        (("r"
-          (text-scale-set 0)
-          "reset"
-          :exit nil)
-         ("0"
-          (text-scale-set 0)
-          ""
-          :bind nil
-          :exit t)
-         ("1"
-          (text-scale-set 0)
-          nil
-          :bind nil
-          :exit t))))
       (set
        (defvar hydra-zoom/hint nil
          "Dynamic hint for hydra-zoom.")
@@ -674,16 +730,17 @@ The body can be accessed via `hydra-vi/body'."
            7 8 (face hydra-face-red)
            9 10 (face hydra-face-blue)))))
       (defun hydra-zoom/lambda-r nil
-        "Create a hydra with no body and the heads:
+        "Call the head `(text-scale-set 0)' in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
 \"1\":    `(text-scale-set 0)'
 
-The body can be accessed via `hydra-zoom/body'.
-
-Call the head: `(text-scale-set 0)'."
+The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore t))
           (hydra-keyboard-quit)
@@ -697,8 +754,7 @@ Call the head: `(text-scale-set 0)'."
                (text-scale-set 0))))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-zoom/hint
          (quote hydra-zoom))
@@ -709,16 +765,17 @@ Call the head: `(text-scale-set 0)'."
            nil)
          nil))
       (defun hydra-zoom/lambda-0-and-exit nil
-        "Create a hydra with no body and the heads:
+        "Call the head `(text-scale-set 0)' in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
 \"1\":    `(text-scale-set 0)'
 
-The body can be accessed via `hydra-zoom/body'.
-
-Call the head: `(text-scale-set 0)'."
+The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
@@ -729,7 +786,9 @@ Call the head: `(text-scale-set 0)'."
            (interactive)
            (text-scale-set 0)))))
       (defun hydra-zoom/body nil
-        "Create a hydra with no body and the heads:
+        "Call the body in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
@@ -737,6 +796,7 @@ Call the head: `(text-scale-set 0)'."
 
 The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore nil))
           (hydra-keyboard-quit)
@@ -764,6 +824,32 @@ The body can be accessed via `hydra-zoom/body'."
        ("0" (text-scale-set 0) :bind nil :exit t)
        ("1" (text-scale-set 0) nil :bind nil)))
     '(progn
+      (set
+       (defvar hydra-zoom/params nil
+         "Params of hydra-zoom.")
+       (quote (nil nil)))
+      (set
+       (defvar hydra-zoom/docstring nil
+         "Docstring of hydra-zoom.")
+       "zoom")
+      (set
+       (defvar hydra-zoom/heads nil
+         "Heads for hydra-zoom.")
+       (quote
+        (("r"
+          (text-scale-set 0)
+          "reset"
+          :exit nil)
+         ("0"
+          (text-scale-set 0)
+          ""
+          :bind nil
+          :exit t)
+         ("1"
+          (text-scale-set 0)
+          nil
+          :bind nil
+          :exit nil))))
       (set
        (defvar hydra-zoom/keymap nil
          "Keymap for hydra-zoom.")
@@ -793,24 +879,6 @@ The body can be accessed via `hydra-zoom/body'."
          (48 . hydra-zoom/lambda-0-and-exit)
          (45 . hydra--negative-argument)
          (21 . hydra--universal-argument))))
-      (set
-       (defvar hydra-zoom/heads nil
-         "Heads for hydra-zoom.")
-       (quote
-        (("r"
-          (text-scale-set 0)
-          "reset"
-          :exit nil)
-         ("0"
-          (text-scale-set 0)
-          ""
-          :bind nil
-          :exit t)
-         ("1"
-          (text-scale-set 0)
-          nil
-          :bind nil
-          :exit nil))))
       (set
        (defvar hydra-zoom/hint nil
          "Dynamic hint for hydra-zoom.")
@@ -820,16 +888,17 @@ The body can be accessed via `hydra-zoom/body'."
            7 8 (face hydra-face-red)
            9 10 (face hydra-face-blue)))))
       (defun hydra-zoom/lambda-r nil
-        "Create a hydra with no body and the heads:
+        "Call the head `(text-scale-set 0)' in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
 \"1\":    `(text-scale-set 0)'
 
-The body can be accessed via `hydra-zoom/body'.
-
-Call the head: `(text-scale-set 0)'."
+The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore t))
           (hydra-keyboard-quit)
@@ -843,8 +912,7 @@ Call the head: `(text-scale-set 0)'."
                (text-scale-set 0))))
           ((quit error)
            (message
-            (error-message-string err))
-           (unless hydra-lv (sit-for 0.8))))
+            (error-message-string err))))
         (hydra-show-hint
          hydra-zoom/hint
          (quote hydra-zoom))
@@ -855,16 +923,17 @@ Call the head: `(text-scale-set 0)'."
            nil)
          nil))
       (defun hydra-zoom/lambda-0-and-exit nil
-        "Create a hydra with no body and the heads:
+        "Call the head `(text-scale-set 0)' in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
 \"1\":    `(text-scale-set 0)'
 
-The body can be accessed via `hydra-zoom/body'.
-
-Call the head: `(text-scale-set 0)'."
+The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
@@ -875,7 +944,9 @@ Call the head: `(text-scale-set 0)'."
            (interactive)
            (text-scale-set 0)))))
       (defun hydra-zoom/body nil
-        "Create a hydra with no body and the heads:
+        "Call the body in the \"hydra-zoom\" hydra.
+
+The heads for the associated hydra are:
 
 \"r\":    `(text-scale-set 0)',
 \"0\":    `(text-scale-set 0)',
@@ -883,6 +954,7 @@ Call the head: `(text-scale-set 0)'."
 
 The body can be accessed via `hydra-zoom/body'."
         (interactive)
+        (require (quote hydra))
         (hydra-default-pre)
         (let ((hydra--ignore nil))
           (hydra-keyboard-quit)
@@ -1018,10 +1090,14 @@ _f_ auto-fill-mode:    %`auto-fill-function
     ("t" toggle-truncate-lines nil)
     ("w" whitespace-mode nil)
     ("q" nil "quit"))))
-           '(concat (format "%s abbrev-mode:       %S
+           '(format
+             "%s abbrev-mode:       %S
 %s debug-on-error:    %S
 %s auto-fill-mode:    %S
-" "{a}" abbrev-mode "{d}" debug-on-error "{f}" auto-fill-function) "[{q}]: 
quit."))))
+[{q}]: quit."
+             "{a}" abbrev-mode
+             "{d}" debug-on-error
+             "{f}" auto-fill-function))))
 
 (ert-deftest hydra-format-2 ()
   (should (equal
@@ -1033,7 +1109,7 @@ _f_ auto-fill-mode:    %`auto-fill-function
               "\n  bar %s`foo\n"
               '(("a" (quote t) "" :cmd-name bar/lambda-a :exit nil)
                 ("q" nil "" :cmd-name bar/nil :exit t))))
-           '(concat (format "  bar %s\n" foo) "{a}, [q]."))))
+           '(format "  bar %s\n{a}, [q]." foo))))
 
 (ert-deftest hydra-format-3 ()
   (should (equal
@@ -1044,7 +1120,7 @@ _f_ auto-fill-mode:    %`auto-fill-function
               nil
               "\n_<SPC>_   ^^ace jump\n"
               '(("<SPC>" ace-jump-char-mode nil :cmd-name 
bar/ace-jump-char-mode))))
-           '(concat (format "%s   ace jump\n" "{<SPC>}") ""))))
+           '(format "%s   ace jump\n" "{<SPC>}"))))
 
 (ert-deftest hydra-format-4 ()
   (should
@@ -1053,39 +1129,35 @@ _f_ auto-fill-mode:    %`auto-fill-function
            '(nil nil :hint nil)
            "\n_j_,_k_"
            '(("j" nil nil :exit t) ("k" nil nil :exit t)))
-          '(concat (format "%s,%s"
-                    #("j" 0 1 (face hydra-face-blue))
-                    #("k" 0 1 (face hydra-face-blue))) ""))))
+          '(format "%s,%s"
+            #("j" 0 1 (face hydra-face-blue))
+            #("k" 0 1 (face hydra-face-blue))))))
 
 (ert-deftest hydra-format-5 ()
   (should
    (equal (hydra--format
            nil nil "\n_-_: mark          _u_: unmark\n"
-           '(("-" Buffer-menu-mark)
-             ("u" Buffer-menu-unmark)))
-          '(concat
-           (format
+           '(("-" Buffer-menu-mark nil)
+             ("u" Buffer-menu-unmark nil)))
+          '(format
             "%s: mark          %s: unmark\n"
             #("-" 0 1 (face hydra-face-red))
-            #("u" 0 1 (face hydra-face-red)))
-            ""))))
+            #("u" 0 1 (face hydra-face-red))))))
 
 (ert-deftest hydra-format-6 ()
   (should
    (equal (hydra--format
            nil nil "\n[_]_] forward [_[_] backward\n"
-           '(("]" forward-char)
-             ("[" backward-char)))
-          '(concat
-            (format
-             "[%s] forward [%s] backward\n"
-             #("]"
-               0 1 (face
-                    hydra-face-red))
-             #("["
-               0 1 (face
-                    hydra-face-red)))
-            ""))))
+           '(("]" forward-char nil)
+             ("[" backward-char nil)))
+          '(format
+            "[%s] forward [%s] backward\n"
+            #("]"
+              0 1 (face
+                   hydra-face-red))
+            #("["
+              0 1 (face
+                   hydra-face-red))))))
 
 (ert-deftest hydra-format-7 ()
   (should
@@ -1104,12 +1176,10 @@ _f_ auto-fill-mode:    %`auto-fill-function
    (equal
     (hydra--format nil nil "\n_%_ forward\n"
                    '(("%" forward-char nil :exit nil)))
-    '(concat
-      (format
-       "%s forward\n"
-       #("%%"
-         0 2 (face hydra-face-red)))
-      ""))))
+    '(format
+      "%s forward\n"
+      #("%%"
+        0 2 (face hydra-face-red))))))
 
 (ert-deftest hydra-format-8 ()
   (should
@@ -1126,11 +1196,28 @@ _f_ auto-fill-mode:    %`auto-fill-function
    (equal
     (hydra--format nil '(nil nil :hint nil) "\n_f_(foo)"
                    '(("f" forward-char nil :exit nil)))
+    '(format
+      "%s(foo)"
+      #("f" 0 1 (face hydra-face-red))))))
+
+(ert-deftest hydra-format-10 ()
+  (should
+   (equal
+    (hydra--format nil '(nil nil) "Test:"
+                   '(("j" next-line (format-time-string "%H:%M:%S" 
(current-time))
+                      :exit nil)))
     '(concat
-      (format
-       "%s(foo)"
-       #("f" 0 1 (face hydra-face-red)))
-      ""))))
+      (format "Test:\n")
+      (mapconcat
+       (function
+        hydra--eval-and-format)
+       (quote
+        ((#("j" 0 1 (face hydra-face-red))
+           format-time-string
+           "%H:%M:%S"
+           (current-time))))
+       ", ")
+      "."))))
 
 (ert-deftest hydra-format-with-sexp-1 ()
   (should (equal
@@ -1140,12 +1227,12 @@ _f_ auto-fill-mode:    %`auto-fill-function
               'hydra-toggle nil
               "\n_n_ narrow-or-widen-dwim %(progn (message 
\"checking\")(buffer-narrowed-p))asdf\n"
               '(("n" narrow-to-region nil) ("q" nil "cancel" :exit t))))
-           '(concat (format "%s narrow-or-widen-dwim %Sasdf\n"
-                     "{n}"
-                     (progn
-                       (message "checking")
-                       (buffer-narrowed-p)))
-             "[[q]]: cancel."))))
+           '(format
+             "%s narrow-or-widen-dwim %Sasdf\n[[q]]: cancel."
+             "{n}"
+             (progn
+               (message "checking")
+               (buffer-narrowed-p))))))
 
 (ert-deftest hydra-format-with-sexp-2 ()
   (should (equal
@@ -1155,72 +1242,72 @@ _f_ auto-fill-mode:    %`auto-fill-function
               'hydra-toggle nil
               "\n_n_ narrow-or-widen-dwim %s(progn (message 
\"checking\")(buffer-narrowed-p))asdf\n"
               '(("n" narrow-to-region nil) ("q" nil "cancel" :exit t))))
-           '(concat (format "%s narrow-or-widen-dwim %sasdf\n"
-                     "{n}"
-                     (progn
-                       (message "checking")
-                       (buffer-narrowed-p)))
-             "[[q]]: cancel."))))
+           '(format
+             "%s narrow-or-widen-dwim %sasdf\n[[q]]: cancel."
+             "{n}"
+             (progn
+               (message "checking")
+               (buffer-narrowed-p))))))
 
 (ert-deftest hydra-compat-colors-2 ()
   (should
    (equal
-    (macroexpand
-     '(defhydra hydra-test (:color amaranth)
-       ("a" fun-a)
-       ("b" fun-b :color blue)
-       ("c" fun-c :color blue)
-       ("d" fun-d :color blue)
-       ("e" fun-e :color blue)
-       ("f" fun-f :color blue)))
-    (macroexpand
-     '(defhydra hydra-test (:color teal)
-       ("a" fun-a :color red)
-       ("b" fun-b)
-       ("c" fun-c)
-       ("d" fun-d)
-       ("e" fun-e)
-       ("f" fun-f))))))
+    (cddr (macroexpand
+           '(defhydra hydra-test (:color amaranth)
+             ("a" fun-a)
+             ("b" fun-b :color blue)
+             ("c" fun-c :color blue)
+             ("d" fun-d :color blue)
+             ("e" fun-e :color blue)
+             ("f" fun-f :color blue))))
+    (cddr (macroexpand
+           '(defhydra hydra-test (:color teal)
+             ("a" fun-a :color red)
+             ("b" fun-b)
+             ("c" fun-c)
+             ("d" fun-d)
+             ("e" fun-e)
+             ("f" fun-f)))))))
 
 (ert-deftest hydra-compat-colors-3 ()
   (should
    (equal
-    (macroexpand
-     '(defhydra hydra-test ()
-       ("a" fun-a)
-       ("b" fun-b :color blue)
-       ("c" fun-c :color blue)
-       ("d" fun-d :color blue)
-       ("e" fun-e :color blue)
-       ("f" fun-f :color blue)))
-    (macroexpand
-     '(defhydra hydra-test (:color blue)
-       ("a" fun-a :color red)
-       ("b" fun-b)
-       ("c" fun-c)
-       ("d" fun-d)
-       ("e" fun-e)
-       ("f" fun-f))))))
+    (cddr (macroexpand
+           '(defhydra hydra-test ()
+             ("a" fun-a)
+             ("b" fun-b :color blue)
+             ("c" fun-c :color blue)
+             ("d" fun-d :color blue)
+             ("e" fun-e :color blue)
+             ("f" fun-f :color blue))))
+    (cddr (macroexpand
+           '(defhydra hydra-test (:color blue)
+             ("a" fun-a :color red)
+             ("b" fun-b)
+             ("c" fun-c)
+             ("d" fun-d)
+             ("e" fun-e)
+             ("f" fun-f)))))))
 
 (ert-deftest hydra-compat-colors-4 ()
   (should
    (equal
-    (macroexpand
-     '(defhydra hydra-test ()
-       ("a" fun-a)
-       ("b" fun-b :exit t)
-       ("c" fun-c :exit t)
-       ("d" fun-d :exit t)
-       ("e" fun-e :exit t)
-       ("f" fun-f :exit t)))
-    (macroexpand
-     '(defhydra hydra-test (:exit t)
-       ("a" fun-a :exit nil)
-       ("b" fun-b)
-       ("c" fun-c)
-       ("d" fun-d)
-       ("e" fun-e)
-       ("f" fun-f))))))
+    (cddr (macroexpand
+           '(defhydra hydra-test ()
+             ("a" fun-a)
+             ("b" fun-b :exit t)
+             ("c" fun-c :exit t)
+             ("d" fun-d :exit t)
+             ("e" fun-e :exit t)
+             ("f" fun-f :exit t))))
+    (cddr (macroexpand
+           '(defhydra hydra-test (:exit t)
+             ("a" fun-a :exit nil)
+             ("b" fun-b)
+             ("c" fun-c)
+             ("d" fun-d)
+             ("e" fun-e)
+             ("f" fun-f)))))))
 
 (ert-deftest hydra--pad ()
   (should (equal (hydra--pad '(a b c) 3)
@@ -1378,7 +1465,7 @@ _w_ Worf:                      % -8`hydra-tng/worf^^    
_h_ Set phasers to
   (should (equal (eval
                   (cadr
                    (nth 2
-                        (nth 3
+                        (nth 5
                              (macroexpand
                               '(defhydra hydra-info (:color blue
                                                      :columns 3)
@@ -1437,6 +1524,29 @@ t: info-to"
                    314 315 (face hydra-face-blue)
                    322 323 (face hydra-face-blue)))))
 
+(ert-deftest hydra-columns-2 ()
+  (should (equal (eval
+                  (cadr
+                   (nth 2
+                        (nth 5
+                             (macroexpand
+                              '(defhydra hydra-foo (:color blue)
+                                "Silly hydra"
+                                ("x" forward-char "forward" :column "sideways")
+                                ("y" backward-char "back")
+                                ("a" next-line "down" :column "vertical")
+                                ("b" previous-line "up")))))))
+                 #("Silly hydra:
+sideways    | vertical
+----------- | -----------
+x: forward  | a: down
+y: back     | b: up
+"
+                   62 63 (face hydra-face-blue)
+                   76 77 (face hydra-face-blue)
+                   84 85 (face hydra-face-blue)
+                   98 99 (face hydra-face-blue)))))
+
 ;; checked:
 ;; basic rendering
 ;; column compatibility with ruby style and no colum specified
@@ -1446,42 +1556,41 @@ t: info-to"
   (should (equal (eval
                   (cadr
                    (nth 2
-                        (nth 3
+                        (nth 5
                              (macroexpand
                               '(defhydra hydra-rectangle (:body-pre 
(rectangle-mark-mode 1)
-                                                                    :color pink
-                                                                    :post 
(deactivate-mark))
-                                 "
+                                                          :color pink
+                                                          :post 
(deactivate-mark))
+                                "
   ^_k_^         ()()
 _h_   _l_       (O)(o)
   ^_j_^         (  O )
 ^^^^            (’’)(’’)
 ^^^^
 "
-                                 ("h" backward-char nil)
-                                 ("l" forward-char nil)
-                                 ("k" previous-line nil)
-                                 ("j" next-line nil)
-                                 ("Of" 5x5 "outside of table 1")
-                                 ("e" exchange-point-and-mark "exchange" 
:column "firstcol")
-                                 ("n" copy-rectangle-as-kill "new-copy")
-                                 ("d" delete-rectangle "delete")
-                                 ("r" (if (region-active-p)
-                                          (deactivate-mark)
-                                        (rectangle-mark-mode 1)) "reset" 
:column "secondcol")
-                                 ("y" yank-rectangle "yank")
-                                 ("u" undo "undo")
-                                 ("s" string-rectangle "string")
-                                 ("p" kill-rectangle "paste")
-                                 ("o" nil "ok" :column "firstcol")
-                                 ("Os" 5x5-bol "outside of table 2" :column 
nil)
-                                 ("Ot" 5x5-eol "outside of table 3")))))))
+                                ("h" backward-char nil)
+                                ("l" forward-char nil)
+                                ("k" previous-line nil)
+                                ("j" next-line nil)
+                                ("Of" 5x5 "outside of table 1")
+                                ("e" exchange-point-and-mark "exchange" 
:column "firstcol")
+                                ("n" copy-rectangle-as-kill "new-copy")
+                                ("d" delete-rectangle "delete")
+                                ("r" (if (region-active-p)
+                                         (deactivate-mark)
+                                       (rectangle-mark-mode 1)) "reset" 
:column "secondcol")
+                                ("y" yank-rectangle "yank")
+                                ("u" undo "undo")
+                                ("s" string-rectangle "string")
+                                ("p" kill-rectangle "paste")
+                                ("o" nil "ok" :column "firstcol")
+                                ("Os" 5x5-bol "outside of table 2" :column nil)
+                                ("Ot" 5x5-eol "outside of table 3")))))))
                  #("  k         ()()
 h   l       (O)(o)
   j         (  O )
             (’’)(’’)
 
-
 firstcol    | secondcol
 ----------- | ------------
 e: exchange | r: reset
@@ -1494,49 +1603,48 @@ o: ok       | s: string
                    17 18 (face hydra-face-pink)
                    21 22 (face hydra-face-pink)
                    38 39 (face hydra-face-pink)
-                   129 130 (face hydra-face-pink)
-                   143 144 (face hydra-face-pink)
-                   152 153 (face hydra-face-pink)
-                   166 167 (face hydra-face-pink)
-                   174 175 (face hydra-face-pink)
-                   188 189 (face hydra-face-pink)
-                   196 197 (face hydra-face-blue)
-                   210 211 (face hydra-face-pink)
-                   234 235 (face hydra-face-pink)
-                   244 246 (face hydra-face-pink)
-                   270 272 (face hydra-face-pink)
-                   296 298 (face hydra-face-pink)))))
+                   128 129 (face hydra-face-pink)
+                   142 143 (face hydra-face-pink)
+                   151 152 (face hydra-face-pink)
+                   165 166 (face hydra-face-pink)
+                   173 174 (face hydra-face-pink)
+                   187 188 (face hydra-face-pink)
+                   195 196 (face hydra-face-blue)
+                   209 210 (face hydra-face-pink)
+                   233 234 (face hydra-face-pink)
+                   243 245 (face hydra-face-pink)
+                   269 271 (face hydra-face-pink)
+                   295 297 (face hydra-face-pink)))))
 
 ;; check column order is the same as they appear in defhydra
 (ert-deftest hydra-column-order ()
   (should (equal (eval
                   (cadr
                    (nth 2
-                        (nth 3
+                        (nth 5
                              (macroexpand
                               '(defhydra hydra-window-order
-                                 (:color red :hint nil :timeout 4)
-                                 ("z" ace-window "ace" :color blue :column 
"Switch")
-                                 ("h" windmove-left "← window")
-                                 ("j" windmove-down "↓ window")
-                                 ("l" windmove-right "→ window")
-                                 ("s" split-window-below "split window" :color 
blue :column "Split Management")
-                                 ("v" split-window-right "split window 
vertically" :color blue)
-                                 ("d" delete-window "delete current window")
-                                 ("f" follow-mode "toogle follow mode")
-                                 ("u" winner-undo "undo window conf" :column 
"Undo/Redo")
-                                 ("r" winner-redo "redo window conf")
-                                 ("b" balance-windows "balance window height" 
:column "1-Sizing")
-                                 ("m" maximize-window "maximize current 
window")
-                                 ("k" windmove-up "↑ window" :column "Switch")
-                                 ("M" minimize-window "maximize current 
window" :column "1-Sizing")
-                                 ("q" nil "quit menu" :color blue :column 
nil)))))))
-                 #("hydra:
-Switch      | Split Management           | Undo/Redo           | 1-Sizing
+                                (:color red :timeout 4)
+                                ("z" ace-window "ace" :color blue :column 
"Switch")
+                                ("h" windmove-left "← window")
+                                ("j" windmove-down "↓ window")
+                                ("l" windmove-right "→ window")
+                                ("s" split-window-below "split window" :color 
blue :column "Split Management")
+                                ("v" split-window-right "split window 
vertically" :color blue)
+                                ("d" delete-window "delete current window")
+                                ("f" follow-mode "toogle follow mode")
+                                ("u" winner-undo "undo window conf" :column 
"Undo/Redo")
+                                ("r" winner-redo "redo window conf")
+                                ("b" balance-windows "balance window height" 
:column "1-Sizing")
+                                ("m" maximize-window "maximize current window")
+                                ("k" windmove-up "↑ window" :column "Switch")
+                                ("M" minimize-window "minimize current window" 
:column "1-Sizing")
+                                ("q" nil "quit menu" :color blue :column 
nil)))))))
+                 #("Switch      | Split Management           | Undo/Redo       
    | 1-Sizing
 ----------- | -------------------------- | ------------------- | 
--------------------------
 z: ace      | s: split window            | u: undo window conf | b: balance 
window height
 h: ← window | v: split window vertically | r: redo window conf | m: maximize 
current window
-j: ↓ window | d: delete current window   |                     | M: maximize 
current window
+j: ↓ window | d: delete current window   |                     | M: minimize 
current window
 l: → window | f: toogle follow mode      |                     |
 k: ↑ window |                            |                     |
 [q]: quit menu."
@@ -1556,6 +1664,59 @@ k: ↑ window |                            |               
      |
                    512 513 (face hydra-face-red)
                    578 579 (face hydra-face-blue)))))
 
+(ert-deftest hydra-column-sexp ()
+  (should (equal
+           (eval (nth 5
+                      (macroexpand
+                       '(defhydra hydra-toggle-stuff ()
+                         "Toggle"
+                         ("d" toggle-debug-on-error "debug-on-error" :column 
"Misc")
+                         ("a" abbrev-mode
+                          (format "abbrev: %s"
+                           (if (bound-and-true-p abbrev-mode)
+                               "[x]"
+                             "[ ]")))))))
+           '(concat
+             (format "Toggle:\n")
+             "Misc"
+             "\n"
+             "-----------------"
+             "\n"
+             #("d: debug-on-error"
+               0 1 (face hydra-face-red))
+             "\n"
+             (format
+              "%1s: %-15s"
+              #("a" 0 1 (face hydra-face-red))
+              (format
+               "abbrev: %s"
+               (if (bound-and-true-p abbrev-mode)
+                   "[x]"
+                 "[ ]")))
+             "\n"))))
+
+(defhydra hydra-extendable ()
+  "extendable"
+  ("j" next-line "down"))
+
+(ert-deftest hydra-extend ()
+  (should (equal (macroexpand
+                  '(defhydra+ hydra-extendable ()
+                    ("k" previous-line "up")))
+                 (macroexpand
+                  '(defhydra hydra-extendable ()
+                    "extendable"
+                    ("j" next-line "down")
+                    ("k" previous-line "up")))))
+  (should (equal (macroexpand
+                  '(defhydra+ hydra-extendable ()
+                    ("k" previous-line "up" :exit t)))
+                 (macroexpand
+                  '(defhydra hydra-extendable ()
+                    "extendable"
+                    ("j" next-line "down")
+                    ("k" previous-line "up" :exit t))))))
+
 (provide 'hydra-test)
 
 ;;; hydra-test.el ends here
diff --git a/hydra.el b/hydra.el
index c837e0fd6e..f28fdae7ce 100644
--- a/hydra.el
+++ b/hydra.el
@@ -1,13 +1,13 @@
 ;;; hydra.el --- Make bindings that stick around. -*- lexical-binding: t -*-
 
-;; Copyright (C) 2015  Free Software Foundation, Inc.
+;; Copyright (C) 2015-2019  Free Software Foundation, Inc.
 
 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
 ;; Maintainer: Oleh Krehel <ohwoeowho@gmail.com>
 ;; URL: https://github.com/abo-abo/hydra
-;; Version: 0.14.0
+;; Version: 0.15.0
 ;; Keywords: bindings
-;; Package-Requires: ((cl-lib "0.5"))
+;; Package-Requires: ((cl-lib "0.5") (lv "0"))
 
 ;; This file is part of GNU Emacs.
 
@@ -207,6 +207,38 @@ the body or the head."
   :type 'sexp
   :group 'hydra)
 
+(declare-function posframe-show "posframe")
+(declare-function posframe-hide "posframe")
+(declare-function posframe-poshandler-window-center "posframe")
+
+(defun hydra-posframe-show (str)
+  (require 'posframe)
+  (posframe-show
+   " *hydra-posframe*"
+   :string str
+   :poshandler #'posframe-poshandler-window-center))
+
+(defun hydra-posframe-hide ()
+  (posframe-hide " *hydra-posframe*"))
+
+(defvar hydra-hint-display-alist
+  (list (list 'lv #'lv-message #'lv-delete-window)
+        (list 'message #'message (lambda () (message "")))
+        (list 'posframe #'hydra-posframe-show #'hydra-posframe-hide))
+  "Store the functions for `hydra-hint-display-type'.")
+
+(defcustom hydra-hint-display-type 'lv
+  "The utility to show hydra hint"
+  :type '(choice
+          (const message)
+          (const lv)
+          (const posframe))
+  :group 'hydra)
+
+(define-obsolete-variable-alias
+    'hydra-lv 'hydra-hint-display-type "0.14.0"
+    "Use either `hydra-hint-display-type' or `hydra-set-property' :verbosity.")
+
 (defcustom hydra-lv t
   "When non-nil, `lv-message' (not `message') will be used to display hints."
   :type 'boolean)
@@ -441,6 +473,21 @@ Return DEFAULT if PROP is not in H."
        ((blue teal) t)
        (t nil)))))
 
+(defun hydra--normalize-body (body)
+  "Put BODY in a normalized format.
+Add :exit and :foreign-keys if they are not there.
+Remove :color key. And sort the plist alphabetically."
+  (let ((plist (cddr body)))
+    (plist-put plist :exit (hydra--body-exit body))
+    (plist-put plist :foreign-keys (hydra--body-foreign-keys body))
+    (let* ((alist0 (cl-loop for (k v) on plist
+                      by #'cddr collect (cons k v)))
+           (alist1 (assq-delete-all :color alist0))
+           (alist2 (cl-sort alist1 #'string<
+                            :key (lambda (x) (symbol-name (car x))))))
+      (append (list (car body) (cadr body))
+              (cl-mapcan (lambda (x) (list (car x) (cdr x))) alist2)))))
+
 (defalias 'hydra--imf #'list)
 
 (defun hydra-default-pre ()
@@ -471,9 +518,8 @@ Return DEFAULT if PROP is not in H."
   (setq hydra-curr-map nil)
   (unless (and hydra--ignore
                (null hydra--work-around-dedicated))
-    (if hydra-lv
-        (lv-delete-window)
-      (message "")))
+    (funcall
+     (nth 2 (assoc hydra-hint-display-type hydra-hint-display-alist))))
   nil)
 
 (defvar hydra-head-format "[%s]: "
@@ -483,16 +529,25 @@ Return DEFAULT if PROP is not in H."
   "The function for formatting key-doc pairs.")
 
 (defun hydra-key-doc-function-default (key key-width doc doc-width)
-  "Doc"
   (cond
-   ((equal key " ") (format (format "%%-%ds" (+ 3 key-width doc-width)) doc))
-   (t (format (format "%%%ds: %%%ds" key-width (- -1 doc-width)) key doc))))
+    ((equal key " ") (format (format "%%-%ds" (+ 3 key-width doc-width)) doc))
+    ((listp doc)
+     `(format ,(format "%%%ds: %%%ds" key-width (- -1 doc-width)) ,key ,doc))
+    (t (format (format "%%%ds: %%%ds" key-width (- -1 doc-width)) key doc))))
 
 (defun hydra--to-string (x)
   (if (stringp x)
       x
     (eval x)))
 
+(defun hydra--eval-and-format (x)
+  (let ((str (hydra--to-string (cdr x))))
+    (format
+     (if (> (length str) 0)
+         (concat hydra-head-format str)
+       "%s")
+     (car x))))
+
 (defun hydra--hint-heads-wocol (body heads)
   "Generate a hint for the echo area.
 BODY, and HEADS are parameters to `defhydra'.
@@ -501,14 +556,13 @@ Works for heads without a property :column."
     (dolist (h heads)
       (let ((val (assoc (cadr h) alist))
             (pstr (hydra-fontify-head h body)))
-        (unless (null (cl-caddr h))
-          (if val
-              (setf (cadr val)
-                    (concat (cadr val) " " pstr))
-            (push
-             (cons (cadr h)
-                   (cons pstr (cl-caddr h)))
-             alist)))))
+        (if val
+            (setf (cadr val)
+                  (concat (cadr val) " " pstr))
+          (push
+           (cons (cadr h)
+                 (cons pstr (cl-caddr h)))
+           alist))))
     (let ((keys (nreverse (mapcar #'cdr alist)))
           (n-cols (plist-get (cddr body) :columns))
           res)
@@ -537,13 +591,7 @@ Works for heads without a property :column."
 
               `(concat
                 (mapconcat
-                 (lambda (x)
-                   (let ((str (hydra--to-string (cdr x))))
-                     (format
-                      (if (> (length str) 0)
-                          (concat hydra-head-format str)
-                        "%s")
-                      (car x))))
+                 #'hydra--eval-and-format
                  ',keys
                  ", ")
                 ,(if keys "." ""))))
@@ -557,11 +605,16 @@ Works for heads without a property :column."
 BODY, and HEADS are parameters to `defhydra'."
   (let* ((sorted-heads (hydra--sort-heads (hydra--normalize-heads heads)))
          (heads-w-col (cl-remove-if-not (lambda (heads) (hydra--head-property 
(nth 0 heads) :column)) sorted-heads))
-         (heads-wo-col (cl-remove-if (lambda (heads) (hydra--head-property 
(nth 0 heads) :column)) sorted-heads)))
-    (concat (when heads-w-col
-              (concat "\n" (hydra--hint-from-matrix body 
(hydra--generate-matrix heads-w-col))))
-            (when heads-wo-col
-              (hydra--hint-heads-wocol body (car heads-wo-col))))))
+         (heads-wo-col (cl-remove-if (lambda (heads) (hydra--head-property 
(nth 0 heads) :column)) sorted-heads))
+         (hint-w-col (when heads-w-col
+                       (hydra--hint-from-matrix body (hydra--generate-matrix 
heads-w-col))))
+         (hint-wo-col (when heads-wo-col
+                        (hydra--hint-heads-wocol body (car heads-wo-col)))))
+    (if (null hint-w-col)
+        hint-wo-col
+      (if (stringp hint-wo-col)
+          `(concat ,@hint-w-col ,hint-wo-col)
+        `(concat ,@hint-w-col ,@(cdr hint-wo-col))))))
 
 (defvar hydra-fontify-head-function nil
   "Possible replacement for `hydra-fontify-head-default'.")
@@ -631,7 +684,7 @@ HEAD's binding is returned as a string wrapped with [] or 
{}."
 (defconst hydra-width-spec-regex " ?-?[0-9]*?"
   "Regex for the width spec in keys and %` quoted sexps.")
 
-(defvar hydra-key-regex "\\[\\|]\\|[-[:alnum:] 
~.,;:/|?<>={}*+#%@!&^↑↓←→⌫⌦⏎'`()\"$]+?"
+(defvar hydra-key-regex "\\[\\|]\\|[-\\[:alnum:] 
~.,;:/|?<>={}*+#%@!&^↑↓←→⌫⌦⏎'`()\"$]+?"
   "Regex for the key quoted in the docstring.")
 
 (defun hydra--format (_name body docstring heads)
@@ -639,91 +692,113 @@ HEAD's binding is returned as a string wrapped with [] 
or {}."
 \"%`...\" expressions are extracted into \"%S\".
 _NAME, BODY, DOCSTRING and HEADS are parameters of `defhydra'.
 The expressions can be auto-expanded according to NAME."
-  (setq docstring (hydra--strip-align-markers docstring))
-  (setq docstring (replace-regexp-in-string "___" "_β_" docstring))
-  (let ((rest (if (eq (plist-get (cddr body) :hint) 'none)
-                  ""
-                (hydra--hint body heads)))
-        (start 0)
-        varlist
-        offset)
-    (while (setq start
-                 (string-match
-                  (format
-                   "\\(?:%%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:[_?]\\(%s\\)\\(%s\\)[_?]\\)"
-                   hydra-width-spec-regex
-                   hydra-key-regex)
-                  docstring start))
-      (cond ((eq ?? (aref (match-string 0 docstring) 0))
-             (let* ((key (match-string 4 docstring))
-                    (head (assoc key heads)))
-               (if head
-                   (progn
-                     (push (nth 2 head) varlist)
-                     (setq docstring
-                           (replace-match
-                            (or
-                             hydra-doc-format-spec
-                             (concat "%" (match-string 3 docstring) "s"))
-                            t nil docstring)))
-                 (setq start (match-end 0))
-                 (warn "Unrecognized key: ?%s?" key))))
-            ((eq ?_ (aref (match-string 0 docstring) 0))
-             (let* ((key (match-string 4 docstring))
-                    (key (if (equal key "β") "_" key))
-                    normal-key
-                    (head (or (assoc key heads)
-                              (when (setq normal-key
-                                          (cdr (assoc
-                                                key 
hydra-docstring-keys-translate-alist)))
-                                (assoc normal-key heads)))))
-               (if head
-                   (progn
-                     (push (hydra-fontify-head (if normal-key
-                                                   (cons key (cdr head))
-                                                 head)
-                                               body)
-                           varlist)
-                     (let ((replacement
-                            (or
-                             hydra-key-format-spec
-                             (concat "%" (match-string 3 docstring) "s"))))
+  (unless (memq 'elisp--witness--lisp (mapcar #'cadr heads))
+    (setq docstring (hydra--strip-align-markers docstring))
+    (setq docstring (replace-regexp-in-string "___" "_β_" docstring))
+    (let ((rest (if (eq (plist-get (cddr body) :hint) 'none)
+                    ""
+                  (hydra--hint body heads)))
+          (start 0)
+          (inner-regex (format "\\(%s\\)\\(%s\\)" hydra-width-spec-regex 
hydra-key-regex))
+          varlist
+          offset)
+      (while (setq start
+                   (string-match
+                    (format
+                     "\\(?:%%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_%s_\\)\\|\\(?:[?]%s[?]\\)"
+                     inner-regex
+                     inner-regex)
+                    docstring start))
+        (cond ((eq ?? (aref (match-string 0 docstring) 0))
+               (let* ((key (match-string 6 docstring))
+                      (head (assoc key heads)))
+                 (if head
+                     (progn
+                       (push (nth 2 head) varlist)
                        (setq docstring
-                             (replace-match replacement t nil docstring))
-                       (setq start (+ start (length replacement)))))
-                 (setq start (match-end 0))
-                 (warn "Unrecognized key: _%s_" key))))
-
-            (t
-             (let* ((varp (if (eq ?` (aref (match-string 2 docstring) 0)) 1 0))
-                    (spec (match-string 1 docstring))
-                    (lspec (length spec)))
-               (setq offset
-                     (with-temp-buffer
-                       (insert (substring docstring (+ 1 start varp
-                                                       (length spec))))
-                       (goto-char (point-min))
-                       (push (read (current-buffer)) varlist)
-                       (- (point) (point-min))))
-               (when (or (zerop lspec)
-                         (/= (aref spec (1- (length spec))) ?s))
-                 (setq spec (concat spec "S")))
-               (setq docstring
-                     (concat
-                      (substring docstring 0 start)
-                      "%" spec
-                      (substring docstring (+ start offset 1 lspec varp))))))))
-    (if (eq ?\n (aref docstring 0))
-        `(concat (format ,(substring docstring 1) ,@(nreverse varlist))
-                 ,rest)
-      (let ((r `(replace-regexp-in-string
-                 " +$" ""
-                 (concat ,docstring ": "
-                         (replace-regexp-in-string
-                          "\\(%\\)" "\\1\\1" ,rest)))))
-        (if (stringp rest)
-            `(format ,(eval r))
-          `(format ,r))))))
+                             (replace-match
+                              (or
+                               hydra-doc-format-spec
+                               (concat "%" (match-string 3 docstring) "s"))
+                              t nil docstring)))
+                   (setq start (match-end 0))
+                   (warn "Unrecognized key: ?%s?" key))))
+              ((eq ?_ (aref (match-string 0 docstring) 0))
+               (let* ((key (match-string 4 docstring))
+                      (key (if (equal key "β") "_" key))
+                      normal-key
+                      (head (or (assoc key heads)
+                                (when (setq normal-key
+                                            (cdr (assoc
+                                                  key 
hydra-docstring-keys-translate-alist)))
+                                  (assoc normal-key heads)))))
+                 (if head
+                     (progn
+                       (push (hydra-fontify-head (if normal-key
+                                                     (cons key (cdr head))
+                                                   head)
+                                                 body)
+                             varlist)
+                       (let ((replacement
+                              (or
+                               hydra-key-format-spec
+                               (concat "%" (match-string 3 docstring) "s"))))
+                         (setq docstring
+                               (replace-match replacement t nil docstring))
+                         (setq start (+ start (length replacement)))))
+                   (setq start (match-end 0))
+                   (warn "Unrecognized key: _%s_" key))))
+
+              (t
+               (let* ((varp (if (eq ?` (aref (match-string 2 docstring) 0)) 1 
0))
+                      (spec (match-string 1 docstring))
+                      (lspec (length spec)))
+                 (setq offset
+                       (with-temp-buffer
+                         (insert (substring docstring (+ 1 start varp
+                                                         (length spec))))
+                         (goto-char (point-min))
+                         (push (read (current-buffer)) varlist)
+                         (- (point) (point-min))))
+                 (when (or (zerop lspec)
+                           (/= (aref spec (1- (length spec))) ?s))
+                   (setq spec (concat spec "S")))
+                 (setq docstring
+                       (concat
+                        (substring docstring 0 start)
+                        "%" spec
+                        (substring docstring (+ start offset 1 lspec 
varp))))))))
+      (hydra--format-1 docstring rest varlist))))
+
+(defun hydra--format-1 (docstring rest varlist)
+  (cond
+    ((string= docstring "")
+     rest)
+    ((listp rest)
+     (unless (string-match-p "[:\n]" docstring)
+       (setq docstring (concat docstring ":\n")))
+     (unless (or (string-match-p "\n\\'" docstring)
+                 (equal (cadr rest) "\n"))
+       (setq docstring (concat docstring "\n")))
+     `(concat (format ,(replace-regexp-in-string "\\`\n" "" docstring) 
,@(nreverse varlist))
+              ,@(cdr rest)))
+    ((eq ?\n (aref docstring 0))
+     `(format ,(concat (substring docstring 1) rest) ,@(nreverse varlist)))
+    (t
+     (let ((r `(replace-regexp-in-string
+                " +$" ""
+                (concat ,docstring
+                        ,(cond ((string-match-p "\\`\n" rest)
+                                ":")
+                               ((string-match-p "\n" rest)
+                                ":\n")
+                               (t
+                                ": "))
+                        (replace-regexp-in-string
+                         "\\(%\\)" "\\1\\1" ,rest)))))
+       (if (stringp rest)
+           `(format ,(eval r))
+         `(format ,r))))))
 
 (defun hydra--complain (format-string &rest args)
   "Forward to (`message' FORMAT-STRING ARGS) unless `hydra-verbose' is nil."
@@ -737,15 +812,15 @@ BODY-KEY is the body key binding.
 BODY-NAME is the symbol that identifies the Hydra.
 HEADS is a list of heads."
   (format
-   "Create a hydra with %s body and the heads:\n\n%s\n\n%s"
-   (if body-key
-       (format "a \"%s\"" body-key)
-     "no")
+   "The heads for the associated hydra are:\n\n%s\n\n%s%s."
    (mapconcat
     (lambda (x)
       (format "\"%s\":    `%S'" (car x) (cadr x)))
     heads ",\n")
-   (format "The body can be accessed via `%S'." body-name)))
+   (format "The body can be accessed via `%S'" body-name)
+   (if body-key
+       (format ", which is bound to \"%s\"" body-key)
+     "")))
 
 (defun hydra--call-interactively-remap-maybe (cmd)
   "`call-interactively' the given CMD or its remapped equivalent.
@@ -782,8 +857,10 @@ BODY-AFTER-EXIT is added to the end of the wrapper."
                (hydra--make-callable
                 (cadr head))))
         (doc (if (car head)
-                 (format "%s\n\nCall the head: `%S'." doc (cadr head))
-               doc))
+                 (format "Call the head `%S' in the \"%s\" hydra.\n\n%s"
+                         (cadr head) name doc)
+               (format "Call the body in the \"%s\" hydra.\n\n%s"
+                       name doc)))
         (hint (intern (format "%S/hint" name)))
         (body-foreign-keys (hydra--body-foreign-keys body))
         (body-timeout (plist-get body :timeout))
@@ -791,6 +868,7 @@ BODY-AFTER-EXIT is added to the end of the wrapper."
     `(defun ,cmd-name ()
        ,doc
        (interactive)
+       (require 'hydra)
        (hydra-default-pre)
        ,@(when body-pre (list body-pre))
        ,@(if (hydra--head-property head :exit)
@@ -812,9 +890,7 @@ BODY-AFTER-EXIT is added to the end of the wrapper."
                  `(condition-case err
                       ,(hydra--call-interactively cmd (cadr head))
                     ((quit error)
-                     (message (error-message-string err))
-                     (unless hydra-lv
-                       (sit-for 0.8)))))
+                     (message (error-message-string err)))))
               ,(if (and body-idle (eq (cadr head) 'body))
                    `(hydra-idle-message ,body-idle ,hint ',name)
                  `(hydra-show-hint ,hint ',name))
@@ -857,9 +933,9 @@ KEY is forwarded to `plist-get'."
            (message (eval hint)))
           (t
            (when hydra-is-helpful
-             (if hydra-lv
-                 (lv-message (eval hint))
-               (message (eval hint))))))))
+             (funcall
+              (nth 1 (assoc hydra-hint-display-type hydra-hint-display-alist))
+              (eval hint)))))))
 
 (defmacro hydra--make-funcall (sym)
   "Transform SYM into a `funcall' to call it."
@@ -1043,21 +1119,48 @@ Each head is decorated with 2 new properties 
max-doc-len and max-key-len
 representing the maximum dimension of their owning group.
  Every heads-group have equal length by adding padding heads where applicable."
   (when heads-groups
-    (cl-loop for heads-group in (hydra--pad-heads heads-groups '(" " nil " " 
:exit t))
-             for column-name = (hydra--head-property (nth 0 heads-group) 
:column)
-             for max-key-len = (apply #'max (mapcar (lambda (x) (length (car 
x))) heads-group))
-             for max-doc-len = (apply #'max
-                                      (length column-name)
-                                      (mapcar (lambda (x) (length 
(hydra--to-string (nth 2 x)))) heads-group))
-             for header-virtual-head = `(" " nil ,column-name :column 
,column-name :exit t)
-             for separator-virtual-head = `(" " nil ,(make-string (+ 2 
max-doc-len max-key-len) ?-) :column ,column-name :exit t)
-             for decorated-heads = (copy-tree (apply 'list header-virtual-head 
separator-virtual-head heads-group))
-             collect (mapcar (lambda (it)
-                               (hydra--head-set-property it :max-key-len 
max-key-len)
-                               (hydra--head-set-property it :max-doc-len 
max-doc-len))
-                             decorated-heads)
-             into decorated-heads-matrix
-             finally return decorated-heads-matrix)))
+    (let ((res nil))
+      (dolist (heads-group (hydra--pad-heads heads-groups '(" " nil " " :exit 
t)))
+        (let* ((column-name (hydra--head-property (nth 0 heads-group) :column))
+               (max-key-len (apply #'max (mapcar (lambda (x) (length (car x))) 
heads-group)))
+               (max-doc-len (apply #'max
+                                   (length column-name)
+                                   (mapcar (lambda (x) (length 
(hydra--to-string (nth 2 x)))) heads-group)))
+               (header-virtual-head `(" " nil ,column-name :column 
,column-name :exit t))
+               (separator-virtual-head `(" " nil ,(make-string (+ 2 
max-doc-len max-key-len) ?-) :column ,column-name :exit t))
+               (decorated-heads (copy-tree (apply 'list header-virtual-head 
separator-virtual-head heads-group))))
+          (push (mapcar (lambda (it)
+                          (hydra--head-set-property it :max-key-len 
max-key-len)
+                          (hydra--head-set-property it :max-doc-len 
max-doc-len))
+                        decorated-heads) res)))
+      (nreverse res))))
+
+(defun hydra-interpose (x lst)
+  "Insert X in between each element of LST."
+  (let (res y)
+    (while (setq y (pop lst))
+      (push y res)
+      (push x res))
+    (nreverse (cdr res))))
+
+(defun hydra--hint-row (heads body)
+  (let ((lst (hydra-interpose
+              "| "
+              (mapcar (lambda (head)
+                        (funcall hydra-key-doc-function
+                                 (hydra-fontify-head head body)
+                                 (let ((n (hydra--head-property head 
:max-key-len)))
+                                   (+ n (cl-count ?% (car head))))
+                                 (nth 2 head) ;; doc
+                                 (hydra--head-property head :max-doc-len)))
+                      heads))))
+    (when (stringp (car (last lst)))
+      (let ((len (length lst))
+            (new-last (replace-regexp-in-string "\s+$" "" (car (last lst)))))
+        (when (= 0 (length (setf (nth (- len 1) lst) new-last)))
+          (setf (nth (- len 2) lst) "|"))))
+    lst))
+
 
 (defun hydra--hint-from-matrix (body heads-matrix)
   "Generate a formated table-style docstring according to BODY and 
HEADS-MATRIX.
@@ -1065,22 +1168,21 @@ HEADS-MATRIX is expected to be a list of heads with 
following features:
 Each heads must have the same length
 Each head must have a property max-key-len and max-doc-len."
   (when heads-matrix
-    (cl-loop with first-heads-col = (nth 0 heads-matrix)
-             with last-row-index = (- (length first-heads-col) 1)
-             for row-index from 0 to last-row-index
-             for heads-in-row = (mapcar (lambda (heads) (nth row-index heads)) 
heads-matrix)
-             concat (concat
-                     (replace-regexp-in-string "\s+$" ""
-                                               (mapconcat (lambda (head)
-                                                            (funcall 
hydra-key-doc-function
-                                                                     
(hydra-fontify-head head body) ;; key
-                                                                     
(hydra--head-property head :max-key-len)
-                                                                     (nth 2 
head) ;; doc
-                                                                     
(hydra--head-property head :max-doc-len)))
-                                                          heads-in-row "| ")) 
"\n")
-             into matrix-image
-             finally return matrix-image)))
-;; previous functions dealt with automatic docstring table generation from 
:column head property
+    (let ((lines (hydra--hint-from-matrix-1 body heads-matrix)))
+      `(,@(apply #'append (hydra-interpose '("\n") lines))
+          "\n"))))
+
+(defun hydra--hint-from-matrix-1 (body heads-matrix)
+  (let* ((first-heads-col (nth 0 heads-matrix))
+         (last-row-index (- (length first-heads-col) 1))
+         (lines nil))
+    (dolist (row-index (number-sequence 0 last-row-index))
+      (let ((heads-in-row (mapcar
+                           (lambda (heads) (nth row-index heads))
+                           heads-matrix)))
+        (push (hydra--hint-row heads-in-row body)
+              lines)))
+    (nreverse lines)))
 
 (defun hydra-idle-message (secs hint name)
   "In SECS seconds display HINT."
@@ -1147,7 +1249,7 @@ nil.  If you don't even want the KEY to be printed, set 
HINT
 explicitly to nil.
 
 The heads inherit their PLIST from BODY-PLIST and are allowed to
-override some keys.  The keys recognized are :exit and :bind.
+override some keys.  The keys recognized are :exit, :bind, and :column.
 :exit can be:
 
 - nil (default): this head will continue the Hydra state.
@@ -1157,11 +1259,13 @@ override some keys.  The keys recognized are :exit and 
:bind.
 - nil: this head will not be bound in BODY-MAP.
 - a lambda taking KEY and CMD used to bind a head.
 
+:column is a string that sets the column for all subsequent heads.
+
 It is possible to omit both BODY-MAP and BODY-KEY if you don't
 want to bind anything.  In that case, typically you will bind the
 generated NAME/body command.  This command is also the return
 result of `defhydra'."
-  (declare (indent defun))
+  (declare (indent defun) (doc-string 3))
   (setq heads (copy-tree heads))
   (cond ((stringp docstring))
         ((and (consp docstring)
@@ -1169,15 +1273,18 @@ result of `defhydra'."
          (setq docstring (concat "\n" (eval docstring))))
         (t
          (setq heads (cons docstring heads))
-         (setq docstring "hydra")))
+         (setq docstring "")))
   (when (keywordp (car body))
     (setq body (cons nil (cons nil body))))
+  (setq body (hydra--normalize-body body))
   (condition-case-unless-debug err
-      (let* ((keymap (copy-keymap hydra-base-map))
-             (keymap-name (intern (format "%S/keymap" name)))
+      (let* ((keymap-name (intern (format "%S/keymap" name)))
              (body-name (intern (format "%S/body" name)))
              (body-key (cadr body))
              (body-plist (cddr body))
+             (base-map (or (eval (plist-get body-plist :base-map))
+                           hydra-base-map))
+             (keymap (copy-keymap base-map))
              (body-map (or (car body)
                            (plist-get body-plist :bind)))
              (body-pre (plist-get body-plist :pre))
@@ -1252,12 +1359,14 @@ result of `defhydra'."
                "An %S Hydra must have at least one blue head in order to exit"
                body-foreign-keys)))
           `(progn
-             ;; create keymap
-             (set (defvar ,keymap-name
+             (set (defvar ,(intern (format "%S/params" name))
                     nil
-                    ,(format "Keymap for %S." name))
-                  ',keymap)
-             ;; declare heads
+                    ,(format "Params of %S." name))
+                  ',body)
+             (set (defvar ,(intern (format "%S/docstring" name))
+                    nil
+                    ,(format "Docstring of %S." name))
+                  ,docstring)
              (set (defvar ,(intern (format "%S/heads" name))
                     nil
                     ,(format "Heads for %S." name))
@@ -1266,6 +1375,12 @@ result of `defhydra'."
                                 (cl-remf (cl-cdddr j) :cmd-name)
                                 j))
                             heads))
+             ;; create keymap
+             (set (defvar ,keymap-name
+                    nil
+                    ,(format "Keymap for %S." name))
+                  ',keymap)
+             ;; declare heads
              (set
               (defvar ,(intern (format "%S/hint" name)) nil
                 ,(format "Dynamic hint for %S." name))
@@ -1316,6 +1431,24 @@ result of `defhydra'."
      (hydra--complain "Error in defhydra %S: %s" name (cdr err))
      nil)))
 
+(defmacro defhydra+ (name body &optional docstring &rest heads)
+  "Redefine an existing hydra by adding new heads.
+Arguments are same as of `defhydra'."
+  (declare (indent defun) (doc-string 3))
+  (unless (stringp docstring)
+    (setq heads
+          (cons docstring heads))
+    (setq docstring nil))
+  `(defhydra ,name ,(or body (hydra--prop name "/params"))
+     ,(or docstring (hydra--prop name "/docstring"))
+     ,@(cl-delete-duplicates
+        (append (hydra--prop name "/heads") heads)
+        :key #'car
+        :test #'equal)))
+
+(defun hydra--prop (name prop-name)
+  (symbol-value (intern (concat (symbol-name name) prop-name))))
+
 (defmacro defhydradio (name _body &rest heads)
   "Create radios with prefix NAME.
 _BODY specifies the options; there are none currently.
diff --git a/lv.el b/lv.el
index 87f7e5e98b..7043abb126 100644
--- a/lv.el
+++ b/lv.el
@@ -54,6 +54,8 @@ Only the background color is significant."
 (defvar lv-wnd nil
   "Holds the current LV window.")
 
+(defvar display-line-numbers)
+
 (defun lv-window ()
   "Ensure that LV window is live and return it."
   (if (window-live-p lv-wnd)
@@ -72,6 +74,7 @@ Only the background color is significant."
           (setq window-size-fixed t)
           (setq mode-line-format nil)
           (setq cursor-type nil)
+          (setq display-line-numbers nil)
           (set-window-dedicated-p lv-wnd t)
           (set-window-parameter lv-wnd 'no-other-window t))
         (select-window ori)))))



reply via email to

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