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

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

[elpa] master 32b8352 36/36: Merge commit '943636fe4a35298d9d234222bc452


From: Oleh Krehel
Subject: [elpa] master 32b8352 36/36: Merge commit '943636fe4a35298d9d234222bc4520dec9ef2305' from hydra
Date: Sat, 22 Jul 2017 11:22:26 -0400 (EDT)

branch: master
commit 32b8352c57238a370661f9bac9bb2e933163848d
Merge: 231ac7f 943636f
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>

    Merge commit '943636fe4a35298d9d234222bc4520dec9ef2305' from hydra
---
 packages/hydra/hydra-examples.el |  49 +++++-
 packages/hydra/hydra-ox.el       |   8 +-
 packages/hydra/hydra-test.el     | 362 +++++++++++++++++++++++++++------------
 packages/hydra/hydra.el          | 322 +++++++++++++++++++++++++++++-----
 packages/hydra/lv.el             |   4 +-
 5 files changed, 584 insertions(+), 161 deletions(-)

diff --git a/packages/hydra/hydra-examples.el b/packages/hydra/hydra-examples.el
index 9264feb..70f75b0 100644
--- a/packages/hydra/hydra-examples.el
+++ b/packages/hydra/hydra-examples.el
@@ -138,7 +138,8 @@
      ("e" move-end-of-line "end")
      ("d" delete-region "del" :color blue)
      ("y" kill-ring-save "yank" :color blue)
-     ("q" nil "quit"))))
+     ("q" nil "quit")))
+  (hydra-set-property 'hydra-vi :verbosity 1))
 
 ;; This example introduces :color amaranth. It's similar to red,
 ;; except while you can quit red with any binding which isn't a Hydra
@@ -290,6 +291,48 @@ _h_   _l_   _o_k        _y_ank
 ;; Recommended binding:
 ;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body)
 
+;;** Example 12: org-agenda-view
+(defun org-agenda-cts ()
+  (and (eq major-mode 'org-agenda-mode)
+       (let ((args (get-text-property
+                    (min (1- (point-max)) (point))
+                    'org-last-args)))
+         (nth 2 args))))
+
+(defhydra hydra-org-agenda-view (:hint none)
+  "
+_d_: ?d? day        _g_: time grid=?g?  _a_: arch-trees
+_w_: ?w? week       _[_: inactive       _A_: arch-files
+_t_: ?t? fortnight  _f_: follow=?f?     _r_: clock report=?r?
+_m_: ?m? month      _e_: entry text=?e? _D_: include diary=?D?
+_y_: ?y? year       _q_: quit           _L__l__c_: log = ?l?"
+  ("SPC" org-agenda-reset-view)
+  ("d" org-agenda-day-view (if (eq 'day (org-agenda-cts)) "[x]" "[ ]"))
+  ("w" org-agenda-week-view (if (eq 'week (org-agenda-cts)) "[x]" "[ ]"))
+  ("t" org-agenda-fortnight-view (if (eq 'fortnight (org-agenda-cts)) "[x]" "[ 
]"))
+  ("m" org-agenda-month-view (if (eq 'month (org-agenda-cts)) "[x]" "[ ]"))
+  ("y" org-agenda-year-view (if (eq 'year (org-agenda-cts)) "[x]" "[ ]"))
+  ("l" org-agenda-log-mode (format "% -3S" org-agenda-show-log))
+  ("L" (org-agenda-log-mode '(4)))
+  ("c" (org-agenda-log-mode 'clockcheck))
+  ("f" org-agenda-follow-mode (format "% -3S" org-agenda-follow-mode))
+  ("a" org-agenda-archives-mode)
+  ("A" (org-agenda-archives-mode 'files))
+  ("r" org-agenda-clockreport-mode (format "% -3S" 
org-agenda-clockreport-mode))
+  ("e" org-agenda-entry-text-mode (format "% -3S" org-agenda-entry-text-mode))
+  ("g" org-agenda-toggle-time-grid (format "% -3S" org-agenda-use-time-grid))
+  ("D" org-agenda-toggle-diary (format "% -3S" org-agenda-include-diary))
+  ("!" org-agenda-toggle-deadlines)
+  ("[" (let ((org-agenda-include-inactive-timestamps t))
+         (org-agenda-check-type t 'timeline 'agenda)
+         (org-agenda-redo)
+         (message "Display now includes inactive timestamps as well")))
+  ("q" (message "Abort") :exit t)
+  ("v" nil))
+
+;; Recommended binding:
+;; (define-key org-agenda-mode-map "v" 'hydra-org-agenda-view/body)
+
 ;;* Helpers
 (require 'windmove)
 
@@ -336,4 +379,8 @@ _h_   _l_   _o_k        _y_ank
       (goto-char mk))))
 
 (provide 'hydra-examples)
+
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
 ;;; hydra-examples.el ends here
diff --git a/packages/hydra/hydra-ox.el b/packages/hydra/hydra-ox.el
index e8d48e3..a992efc 100644
--- a/packages/hydra/hydra-ox.el
+++ b/packages/hydra/hydra-ox.el
@@ -27,7 +27,13 @@
 
 (require 'hydra)
 (require 'org)
-(require 'hydra)                        ;`defhydradio' is not autoloaded!
+(declare-function org-html-export-as-html 'ox-html)
+(declare-function org-html-export-to-html 'ox-html)
+(declare-function org-latex-export-as-latex 'ox-latex)
+(declare-function org-latex-export-to-latex 'ox-latex)
+(declare-function org-latex-export-to-pdf 'ox-latex)
+(declare-function org-ascii-export-as-ascii 'ox-ascii)
+(declare-function org-ascii-export-to-ascii 'ox-ascii)
 
 (defhydradio hydra-ox ()
   (body-only "Export only the body.")
diff --git a/packages/hydra/hydra-test.el b/packages/hydra/hydra-test.el
index a988a25..4618d6b 100644
--- a/packages/hydra/hydra-test.el
+++ b/packages/hydra/hydra-test.el
@@ -121,20 +121,18 @@ Call the head: `first-error'."
           (setq hydra-curr-body-fn
                 (quote hydra-error/body)))
         (condition-case err
-                        (progn
-                          (setq this-command
-                                (quote first-error))
-                          (call-interactively
-                           (function first-error)))
-                        ((quit error)
-                         (message "%S" err)
-                         (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-error/hint))
-            (message
-             (eval hydra-error/hint))))
+            (progn
+              (setq this-command
+                    (quote first-error))
+              (hydra--call-interactively-remap-maybe
+               (function first-error)))
+          ((quit error)
+           (message
+            (error-message-string err))
+           (unless hydra-lv (sit-for 0.8))))
+        (hydra-show-hint
+         hydra-error/hint
+         (quote hydra-error))
         (hydra-set-transient-map
          hydra-error/keymap
          (lambda nil
@@ -159,20 +157,18 @@ Call the head: `next-error'."
           (setq hydra-curr-body-fn
                 (quote hydra-error/body)))
         (condition-case err
-                        (progn
-                          (setq this-command
-                                (quote next-error))
-                          (call-interactively
-                           (function next-error)))
-                        ((quit error)
-                         (message "%S" err)
-                         (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-error/hint))
-            (message
-             (eval hydra-error/hint))))
+            (progn
+              (setq this-command
+                    (quote next-error))
+              (hydra--call-interactively-remap-maybe
+               (function next-error)))
+          ((quit error)
+           (message
+            (error-message-string err))
+           (unless hydra-lv (sit-for 0.8))))
+        (hydra-show-hint
+         hydra-error/hint
+         (quote hydra-error))
         (hydra-set-transient-map
          hydra-error/keymap
          (lambda nil
@@ -197,20 +193,18 @@ Call the head: `previous-error'."
           (setq hydra-curr-body-fn
                 (quote hydra-error/body)))
         (condition-case err
-                        (progn
-                          (setq this-command
-                                (quote previous-error))
-                          (call-interactively
-                           (function previous-error)))
-                        ((quit error)
-                         (message "%S" err)
-                         (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-error/hint))
-            (message
-             (eval hydra-error/hint))))
+            (progn
+              (setq this-command
+                    (quote previous-error))
+              (hydra--call-interactively-remap-maybe
+               (function previous-error)))
+          ((quit error)
+           (message
+            (error-message-string err))
+           (unless hydra-lv (sit-for 0.8))))
+        (hydra-show-hint
+         hydra-error/hint
+         (quote hydra-error))
         (hydra-set-transient-map
          hydra-error/keymap
          (lambda nil
@@ -224,12 +218,12 @@ Call the head: `previous-error'."
         (define-key global-map (kbd "M-g")
           nil))
       (define-key global-map [134217831 104]
-        (quote hydra-error/first-error))
+       (quote hydra-error/first-error))
       (define-key global-map [134217831 106]
-        (quote hydra-error/next-error))
+       (quote hydra-error/next-error))
       (define-key global-map [134217831 107]
-        (quote
-         hydra-error/previous-error))
+       (quote
+        hydra-error/previous-error))
       (defun hydra-error/body nil
         "Create a hydra with a \"M-g\" body and the heads:
 
@@ -245,12 +239,9 @@ The body can be accessed via `hydra-error/body'."
           (hydra-keyboard-quit)
           (setq hydra-curr-body-fn
                 (quote hydra-error/body)))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-error/hint))
-            (message
-             (eval hydra-error/hint))))
+        (hydra-show-hint
+         hydra-error/hint
+         (quote hydra-error))
         (hydra-set-transient-map
          hydra-error/keymap
          (lambda nil
@@ -349,7 +340,7 @@ Call the head: `toggle-truncate-lines'."
         (progn
           (setq this-command
                 (quote toggle-truncate-lines))
-          (call-interactively
+          (hydra--call-interactively-remap-maybe
            (function
             toggle-truncate-lines))))
       (defun hydra-toggle/auto-fill-mode-and-exit nil
@@ -371,7 +362,7 @@ Call the head: `auto-fill-mode'."
         (progn
           (setq this-command
                 (quote auto-fill-mode))
-          (call-interactively
+          (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:
@@ -392,7 +383,7 @@ Call the head: `abbrev-mode'."
         (progn
           (setq this-command
                 (quote abbrev-mode))
-          (call-interactively
+          (hydra--call-interactively-remap-maybe
            (function abbrev-mode))))
       (defun hydra-toggle/nil nil
         "Create a hydra with no body and the heads:
@@ -425,12 +416,9 @@ The body can be accessed via `hydra-toggle/body'."
           (hydra-keyboard-quit)
           (setq hydra-curr-body-fn
                 (quote hydra-toggle/body)))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-toggle/hint))
-            (message
-             (eval hydra-toggle/hint))))
+        (hydra-show-hint
+         hydra-toggle/hint
+         (quote hydra-toggle))
         (hydra-set-transient-map
          hydra-toggle/keymap
          (lambda nil
@@ -526,16 +514,15 @@ Call the head: `next-line'."
             (progn
               (setq this-command
                     (quote next-line))
-              (call-interactively
+              (hydra--call-interactively-remap-maybe
                (function next-line)))
           ((quit error)
-           (message "%S" err)
+           (message
+            (error-message-string err))
            (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-vi/hint))
-            (message (eval hydra-vi/hint))))
+        (hydra-show-hint
+         hydra-vi/hint
+         (quote hydra-vi))
         (hydra-set-transient-map
          hydra-vi/keymap
          (lambda nil
@@ -563,16 +550,15 @@ Call the head: `previous-line'."
             (progn
               (setq this-command
                     (quote previous-line))
-              (call-interactively
+              (hydra--call-interactively-remap-maybe
                (function previous-line)))
           ((quit error)
-           (message "%S" err)
+           (message
+            (error-message-string err))
            (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-vi/hint))
-            (message (eval hydra-vi/hint))))
+        (hydra-show-hint
+         hydra-vi/hint
+         (quote hydra-vi))
         (hydra-set-transient-map
          hydra-vi/keymap
          (lambda nil
@@ -610,11 +596,9 @@ The body can be accessed via `hydra-vi/body'."
           (hydra-keyboard-quit)
           (setq hydra-curr-body-fn
                 (quote hydra-vi/body)))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-vi/hint))
-            (message (eval hydra-vi/hint))))
+        (hydra-show-hint
+         hydra-vi/hint
+         (quote hydra-vi))
         (hydra-set-transient-map
          hydra-vi/keymap
          (lambda nil
@@ -706,20 +690,18 @@ Call the head: `(text-scale-set 0)'."
           (setq hydra-curr-body-fn
                 (quote hydra-zoom/body)))
         (condition-case err
-            (call-interactively
+            (hydra--call-interactively-remap-maybe
              (function
               (lambda nil
                (interactive)
                (text-scale-set 0))))
           ((quit error)
-           (message "%S" err)
+           (message
+            (error-message-string err))
            (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-zoom/hint))
-            (message
-             (eval hydra-zoom/hint))))
+        (hydra-show-hint
+         hydra-zoom/hint
+         (quote hydra-zoom))
         (hydra-set-transient-map
          hydra-zoom/keymap
          (lambda nil
@@ -741,7 +723,7 @@ Call the head: `(text-scale-set 0)'."
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
               (quote hydra-zoom/body))
-        (call-interactively
+        (hydra--call-interactively-remap-maybe
          (function
           (lambda nil
            (interactive)
@@ -760,12 +742,9 @@ The body can be accessed via `hydra-zoom/body'."
           (hydra-keyboard-quit)
           (setq hydra-curr-body-fn
                 (quote hydra-zoom/body)))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-zoom/hint))
-            (message
-             (eval hydra-zoom/hint))))
+        (hydra-show-hint
+         hydra-zoom/hint
+         (quote hydra-zoom))
         (hydra-set-transient-map
          hydra-zoom/keymap
          (lambda nil
@@ -857,20 +836,18 @@ Call the head: `(text-scale-set 0)'."
           (setq hydra-curr-body-fn
                 (quote hydra-zoom/body)))
         (condition-case err
-            (call-interactively
+            (hydra--call-interactively-remap-maybe
              (function
               (lambda nil
                (interactive)
                (text-scale-set 0))))
           ((quit error)
-           (message "%S" err)
+           (message
+            (error-message-string err))
            (unless hydra-lv (sit-for 0.8))))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-zoom/hint))
-            (message
-             (eval hydra-zoom/hint))))
+        (hydra-show-hint
+         hydra-zoom/hint
+         (quote hydra-zoom))
         (hydra-set-transient-map
          hydra-zoom/keymap
          (lambda nil
@@ -892,7 +869,7 @@ Call the head: `(text-scale-set 0)'."
         (hydra-keyboard-quit)
         (setq hydra-curr-body-fn
               (quote hydra-zoom/body))
-        (call-interactively
+        (hydra--call-interactively-remap-maybe
          (function
           (lambda nil
            (interactive)
@@ -911,12 +888,9 @@ The body can be accessed via `hydra-zoom/body'."
           (hydra-keyboard-quit)
           (setq hydra-curr-body-fn
                 (quote hydra-zoom/body)))
-        (when hydra-is-helpful
-          (if hydra-lv
-              (lv-message
-               (eval hydra-zoom/hint))
-            (message
-             (eval hydra-zoom/hint))))
+        (hydra-show-hint
+         hydra-zoom/hint
+         (quote hydra-zoom))
         (hydra-set-transient-map
          hydra-zoom/keymap
          (lambda nil
@@ -1137,6 +1111,27 @@ _f_ auto-fill-mode:    %`auto-fill-function
          0 2 (face hydra-face-red)))
       ""))))
 
+(ert-deftest hydra-format-8 ()
+  (should
+   (equal
+    (hydra--format nil '(nil nil :hint nil) "test"
+                   '(("f" forward-char nil :exit nil)
+                     ("b" backward-char "back" :exit nil)))
+    '(format
+      #("test: [b]: back."
+        7 8 (face hydra-face-red))))))
+
+(ert-deftest hydra-format-9 ()
+  (should
+   (equal
+    (hydra--format nil '(nil nil :hint nil) "\n_f_(foo)"
+                   '(("f" forward-char nil :exit nil)))
+    '(concat
+      (format
+       "%s(foo)"
+       #("f" 0 1 (face hydra-face-red)))
+      ""))))
+
 (ert-deftest hydra-format-with-sexp-1 ()
   (should (equal
            (let ((hydra-fontify-head-function
@@ -1295,6 +1290,19 @@ _w_ Worf:                      % -8`hydra-tng/worf^^    
_h_ Set phasers to
   ("1" find-file)
   ("q" nil))
 
+(defun remapable-print ()
+  (interactive)
+  (insert "remapable print was called"))
+(defun remaped-print ()
+  (interactive)
+  (insert "*remaped* print was called"))
+(define-key global-map (kbd "C-=") 'remapable-print)
+(define-key global-map [remap remapable-print] 'remaped-print)
+
+(defhydra hydra-simple-with-remap (global-map "C-c")
+  ("r" remapable-print)
+  ("q" nil))
+
 (defmacro hydra-with (in &rest body)
   `(let ((temp-buffer (generate-new-buffer " *temp*")))
      (save-window-excursion
@@ -1351,6 +1359,21 @@ _w_ Worf:                      % -8`hydra-tng/worf^^    
_h_ Set phasers to
                                 (kbd "C-c g 1 RET q")))
                    "|foo\nbar")))
 
+(ert-deftest hydra-remap-lookup-1 ()
+  "try calling a remapped command while option is disabled "
+  (setq hydra-look-for-remap nil)
+  (should (string= (hydra-with "|"
+                               (execute-kbd-macro
+                                (kbd "C-c rq")))
+                   "remapable print was called|")))
+(ert-deftest hydra-remap-lookup-2 ()
+  "try calling a remapped command while option is enabled"
+  (setq hydra-look-for-remap t)
+  (should (string= (hydra-with "|"
+                               (execute-kbd-macro
+                                (kbd "C-c rq")))
+                   "*remaped* print was called|")))
+
 (ert-deftest hydra-columns-1 ()
   (should (equal (eval
                   (cadr
@@ -1414,6 +1437,125 @@ t: info-to"
                    314 315 (face hydra-face-blue)
                    322 323 (face hydra-face-blue)))))
 
+;; checked:
+;; basic rendering
+;; column compatibility with ruby style and no colum specified
+;; column declared several time
+;; nil column
+(ert-deftest hydra-column-basic ()
+  (should (equal (eval
+                  (cadr
+                   (nth 2
+                        (nth 3
+                             (macroexpand
+                              '(defhydra hydra-rectangle (:body-pre 
(rectangle-mark-mode 1)
+                                                                    :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")))))))
+                 #("  k         ()()
+h   l       (O)(o)
+  j         (  O )
+            (’’)(’’)
+
+
+firstcol    | secondcol
+----------- | ------------
+e: exchange | r: reset
+n: new-copy | y: yank
+d: delete   | u: undo
+o: ok       | s: string
+            | p: paste
+[Of]: outside of table 1, [Os]: outside of table 2, [Ot]: outside of table 3."
+                   2 3 (face hydra-face-pink)
+                   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)))))
+
+;; check column order is the same as they appear in defhydra
+(ert-deftest hydra-column-order ()
+  (should (equal (eval
+                  (cadr
+                   (nth 2
+                        (nth 3
+                             (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
+----------- | -------------------------- | ------------------- | 
--------------------------
+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
+l: → window | f: toogle follow mode      |                     |
+k: ↑ window |                            |                     |
+[q]: quit menu."
+                   173 174 (face hydra-face-blue)
+                   187 188 (face hydra-face-blue)
+                   216 217 (face hydra-face-red)
+                   238 239 (face hydra-face-red)
+                   263 264 (face hydra-face-red)
+                   277 278 (face hydra-face-blue)
+                   306 307 (face hydra-face-red)
+                   328 329 (face hydra-face-red)
+                   355 356 (face hydra-face-red)
+                   369 370 (face hydra-face-red)
+                   420 421 (face hydra-face-red)
+                   447 448 (face hydra-face-red)
+                   461 462 (face hydra-face-red)
+                   512 513 (face hydra-face-red)
+                   578 579 (face hydra-face-blue)))))
+
 (provide 'hydra-test)
 
 ;;; hydra-test.el ends here
diff --git a/packages/hydra/hydra.el b/packages/hydra/hydra.el
index 8c6ce7f..c837e0f 100644
--- a/packages/hydra/hydra.el
+++ b/packages/hydra/hydra.el
@@ -5,7 +5,7 @@
 ;; Author: Oleh Krehel <address@hidden>
 ;; Maintainer: Oleh Krehel <address@hidden>
 ;; URL: https://github.com/abo-abo/hydra
-;; Version: 0.13.5
+;; Version: 0.14.0
 ;; Keywords: bindings
 ;; Package-Requires: ((cl-lib "0.5"))
 
@@ -69,15 +69,20 @@
 ;; you can nest Hydras if you wish, with `hydra-toggle/body' possibly
 ;; becoming a blue head of another Hydra.
 ;;
-;; Initially, Hydra shipped with a simplified `hydra-create' macro, to
-;; which you could hook up the examples from hydra-examples.el.  It's
-;; better to take the examples simply as templates and use `defhydra'
-;; instead of `hydra-create', since it's more flexible.
+;; If you want to learn all intricacies of using `defhydra' without
+;; having to figure it all out from this source code, check out the
+;; wiki: https://github.com/abo-abo/hydra/wiki. There's a wealth of
+;; information there. Everyone is welcome to bring the existing pages
+;; up to date and add new ones.
+;;
+;; Additionally, the file hydra-examples.el serves to demo most of the
+;; functionality.
 
 ;;; Code:
 ;;* Requires
 (require 'cl-lib)
 (require 'lv)
+(require 'ring)
 
 (defvar hydra-curr-map nil
   "The keymap of the current Hydra called.")
@@ -95,6 +100,9 @@
   "If a Hydra head sets this to t, exit the Hydra.
 This will be done even if the head wasn't designated for exiting.")
 
+(defvar hydra-amaranth-warn-message "An amaranth Hydra can only exit through a 
blue head"
+  "Amaranth Warning message.  Shown when the user tries to press an 
unbound/non-exit key while in an amaranth head.")
+
 (defun hydra-set-transient-map (keymap on-exit &optional foreign-keys)
   "Set KEYMAP to the highest priority.
 
@@ -180,7 +188,7 @@ warn: keep KEYMAP and issue a warning instead of running 
the command."
 (defun hydra-amaranth-warn ()
   "Issue a warning that the current input was ignored."
   (interactive)
-  (message "An amaranth Hydra can only exit through a blue head"))
+  (message hydra-amaranth-warn-message))
 
 ;;* Customize
 (defgroup hydra nil
@@ -193,6 +201,12 @@ warn: keep KEYMAP and issue a warning instead of running 
the command."
   :type 'boolean
   :group 'hydra)
 
+(defcustom hydra-default-hint ""
+  "Default :hint property to use for heads when not specified in
+the body or the head."
+  :type 'sexp
+  :group 'hydra)
+
 (defcustom hydra-lv t
   "When non-nil, `lv-message' (not `message') will be used to display hints."
   :type 'boolean)
@@ -203,7 +217,19 @@ warn: keep KEYMAP and issue a warning instead of running 
the command."
 
 (defcustom hydra-key-format-spec "%s"
   "Default `format'-style specifier for _a_  syntax in docstrings.
-When nil, you can specify your own at each location like this: _ 5a_.")
+When nil, you can specify your own at each location like this: _ 5a_."
+  :type 'string)
+
+(defcustom hydra-doc-format-spec "%s"
+  "Default `format'-style specifier for ?a?  syntax in docstrings."
+  :type 'string)
+
+(defcustom hydra-look-for-remap nil
+  "When non-nil, hydra binding behaves as keymap binding with [remap].
+When calling a head with a simple command, hydra will lookup for a potential
+remap command according to the current active keymap and call it instead if
+found"
+  :type 'boolean)
 
 (make-obsolete-variable
  'hydra-key-format-spec
@@ -389,6 +415,14 @@ one of the properties on the list."
 Return DEFAULT if PROP is not in H."
   (hydra-plist-get-default (cl-cdddr h) prop default))
 
+(defun hydra--head-set-property (h prop value)
+  "In hydra Head H, set a property PROP to the value VALUE."
+  (cons (car h) (plist-put (cdr h) prop value)))
+
+(defun hydra--head-has-property (h prop)
+  "Return non nil if heads H has the property PROP."
+  (plist-member (cdr h) prop))
+
 (defun hydra--body-foreign-keys (body)
   "Return what BODY does with a non-head binding."
   (or
@@ -450,17 +484,19 @@ Return DEFAULT if PROP is not in H."
 
 (defun hydra-key-doc-function-default (key key-width doc doc-width)
   "Doc"
-  (format (format "%%%ds: %%%ds" key-width (- -1 doc-width))
-          key 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))))
 
 (defun hydra--to-string (x)
   (if (stringp x)
       x
     (eval x)))
 
-(defun hydra--hint (body heads)
+(defun hydra--hint-heads-wocol (body heads)
   "Generate a hint for the echo area.
-BODY, and HEADS are parameters to `defhydra'."
+BODY, and HEADS are parameters to `defhydra'.
+Works for heads without a property :column."
   (let (alist)
     (dolist (h heads)
       (let ((val (assoc (cadr h) alist))
@@ -516,6 +552,17 @@ BODY, and HEADS are parameters to `defhydra'."
           (eval res)
         res))))
 
+(defun hydra--hint (body heads)
+  "Generate a hint for the echo area.
+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))))))
+
 (defvar hydra-fontify-head-function nil
   "Possible replacement for `hydra-fontify-head-default'.")
 
@@ -536,18 +583,17 @@ HEAD's binding is returned as a string with a colored 
face."
     (when (and (null (cadr head))
                (not head-exit))
       (hydra--complain "nil cmd can only be blue"))
-    (propertize (if (string= (car head) "%")
-                    "%%"
-                  (car head))
-                'face
-                (or (hydra--head-property head :face)
-                    (cl-case head-color
-                      (blue 'hydra-face-blue)
-                      (red 'hydra-face-red)
-                      (amaranth 'hydra-face-amaranth)
-                      (pink 'hydra-face-pink)
-                      (teal 'hydra-face-teal)
-                      (t (error "Unknown color for %S" head)))))))
+    (propertize
+     (replace-regexp-in-string "%" "%%" (car head))
+     'face
+     (or (hydra--head-property head :face)
+         (cl-case head-color
+           (blue 'hydra-face-blue)
+           (red 'hydra-face-red)
+           (amaranth 'hydra-face-amaranth)
+           (pink 'hydra-face-pink)
+           (teal 'hydra-face-teal)
+           (t (error "Unknown color for %S" head)))))))
 
 (defun hydra-fontify-head-greyscale (head _body)
   "Produce a pretty string from HEAD and BODY.
@@ -573,6 +619,21 @@ HEAD's binding is returned as a string wrapped with [] or 
{}."
         (setq str (replace-match "" nil nil str))))
     str))
 
+(defvar hydra-docstring-keys-translate-alist
+  '(("↑" . "<up>")
+    ("↓" . "<down>")
+    ("→" . "<right>")
+    ("←" . "<left>")
+    ("⌫" . "DEL")
+    ("⌦" . "<deletechar>")
+    ("⏎" . "RET")))
+
+(defconst hydra-width-spec-regex " ?-?[0-9]*?"
+  "Regex for the width spec in keys and %` quoted sexps.")
+
+(defvar hydra-key-regex "\\[\\|]\\|[-[:alnum:] 
~.,;:/|?<>address@hidden&^↑↓←→⌫⌦⏎'`()\"$]+?"
+  "Regex for the key quoted in the docstring.")
+
 (defun hydra--format (_name body docstring heads)
   "Generate a `format' statement from STR.
 \"%`...\" expressions are extracted into \"%S\".
@@ -580,27 +641,57 @@ _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 (hydra--hint body heads))
+  (let ((rest (if (eq (plist-get (cddr body) :hint) 'none)
+                  ""
+                (hydra--hint body heads)))
         (start 0)
         varlist
         offset)
     (while (setq start
                  (string-match
-                  "\\(?:%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_\\( 
?-?[0-9]*?\\)\\(\\[\\|]\\|[-[:alnum:] ~.,;:/|?<>address@hidden&^]+?\\)_\\)"
+                  (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))
+      (cond ((eq ?? (aref (match-string 0 docstring) 0))
              (let* ((key (match-string 4 docstring))
-                    (key (if (equal key "β") "_" key))
                     (head (assoc key heads)))
                (if head
                    (progn
-                     (push (hydra-fontify-head head body) varlist)
+                     (push (nth 2 head) varlist)
                      (setq docstring
                            (replace-match
                             (or
-                             hydra-key-format-spec
+                             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
@@ -656,6 +747,16 @@ HEADS is a list of heads."
     heads ",\n")
    (format "The body can be accessed via `%S'." body-name)))
 
+(defun hydra--call-interactively-remap-maybe (cmd)
+  "`call-interactively' the given CMD or its remapped equivalent.
+Only when `hydra-look-for-remap' is non nil."
+  (let ((remapped-cmd (if hydra-look-for-remap
+                          (command-remapping `,cmd)
+                        nil)))
+    (if remapped-cmd
+        (call-interactively `,remapped-cmd)
+      (call-interactively `,cmd))))
+
 (defun hydra--call-interactively (cmd name)
   "Generate a `call-interactively' statement for CMD.
 Set `this-command' to NAME."
@@ -663,8 +764,8 @@ Set `this-command' to NAME."
            (not (memq name '(nil body))))
       `(progn
          (setq this-command ',name)
-         (call-interactively #',cmd))
-    `(call-interactively #',cmd)))
+         (hydra--call-interactively-remap-maybe #',cmd))
+    `(hydra--call-interactively-remap-maybe #',cmd)))
 
 (defun hydra--make-defun (name body doc head
                           keymap body-pre body-before-exit
@@ -711,15 +812,12 @@ BODY-AFTER-EXIT is added to the end of the wrapper."
                  `(condition-case err
                       ,(hydra--call-interactively cmd (cadr head))
                     ((quit error)
-                     (message "%S" err)
+                     (message (error-message-string err))
                      (unless hydra-lv
                        (sit-for 0.8)))))
               ,(if (and body-idle (eq (cadr head) 'body))
-                   `(hydra-idle-message ,body-idle ,hint)
-                 `(when hydra-is-helpful
-                    (if hydra-lv
-                        (lv-message (eval ,hint))
-                      (message (eval ,hint)))))
+                   `(hydra-idle-message ,body-idle ,hint ',name)
+                 `(hydra-show-hint ,hint ',name))
               (hydra-set-transient-map
                ,keymap
                (lambda () (hydra-keyboard-quit) ,body-before-exit)
@@ -729,6 +827,40 @@ BODY-AFTER-EXIT is added to the end of the wrapper."
               ,(when body-timeout
                  `(hydra-timeout ,body-timeout))))))))
 
+(defvar hydra-props-alist nil)
+
+(defun hydra-set-property (name key val)
+  "Set hydra property.
+NAME is the symbolic name of the hydra.
+KEY and VAL are forwarded to `plist-put'."
+  (let ((entry (assoc name hydra-props-alist))
+        plist)
+    (when (null entry)
+      (add-to-list 'hydra-props-alist (list name))
+      (setq entry (assoc name hydra-props-alist)))
+    (setq plist (cdr entry))
+    (setcdr entry (plist-put plist key val))))
+
+(defun hydra-get-property (name key)
+  "Get hydra property.
+NAME is the symbolic name of the hydra.
+KEY is forwarded to `plist-get'."
+  (let ((entry (assoc name hydra-props-alist)))
+    (when entry
+      (plist-get (cdr entry) key))))
+
+(defun hydra-show-hint (hint caller)
+  (let ((verbosity (plist-get (cdr (assoc caller hydra-props-alist))
+                              :verbosity)))
+    (cond ((eq verbosity 0))
+          ((eq verbosity 1)
+           (message (eval hint)))
+          (t
+           (when hydra-is-helpful
+             (if hydra-lv
+                 (lv-message (eval hint))
+               (message (eval hint))))))))
+
 (defmacro hydra--make-funcall (sym)
   "Transform SYM into a `funcall' to call it."
   `(when (and ,sym (symbolp ,sym))
@@ -858,7 +990,99 @@ NAMES should be defined by `defhydradio' or similar."
   (dolist (n names)
     (set n (aref (get n 'range) 0))))
 
-(defun hydra-idle-message (secs hint)
+;; Following functions deal with automatic docstring table generation from 
:column head property
+(defun hydra--normalize-heads (heads)
+  "Ensure each head from HEADS have a property :column.
+Set it to the same value as preceding head or nil if no previous value
+was defined."
+  (let ((current-col nil))
+    (mapcar (lambda (head)
+              (if (hydra--head-has-property head :column)
+                  (setq current-col (hydra--head-property head :column)))
+              (hydra--head-set-property head :column current-col))
+            heads)))
+
+(defun hydra--sort-heads (normalized-heads)
+  "Return a list of heads with non-nil doc grouped by column property.
+Each head of NORMALIZED-HEADS must have a column property."
+  (let* ((heads-wo-nil-doc (cl-remove-if-not (lambda (head) (nth 2 head)) 
normalized-heads))
+         (columns-list (delete-dups (mapcar (lambda (head) 
(hydra--head-property head :column))
+                                            normalized-heads)))
+         (get-col-index-fun (lambda (head) (cl-position (hydra--head-property 
head :column)
+                                                        columns-list
+                                                        :test 'equal)))
+         (heads-sorted (cl-sort heads-wo-nil-doc (lambda (it other)
+                                                   (< (funcall 
get-col-index-fun it)
+                                                      (funcall 
get-col-index-fun other))))))
+    ;; this operation partition the sorted head list into lists of heads with 
same column property
+    (cl-loop for head in heads-sorted
+       for column-name = (hydra--head-property head :column)
+       with prev-column-name = (hydra--head-property (nth 0 heads-sorted) 
:column)
+       unless (equal prev-column-name column-name) collect heads-one-column 
into heads-all-columns
+       and do (setq heads-one-column nil)
+       collect head into heads-one-column
+       do (setq prev-column-name column-name)
+       finally return (append heads-all-columns (list heads-one-column)))))
+
+(defun hydra--pad-heads (heads-groups padding-head)
+  "Return a copy of HEADS-GROUPS padded where applicable with PADDING-HEAD."
+  (cl-loop for heads-group in heads-groups
+     for this-head-group-length = (length heads-group)
+     with head-group-max-length = (apply #'max (mapcar (lambda (heads) (length 
heads)) heads-groups))
+     if (<= this-head-group-length head-group-max-length)
+     collect (append heads-group (make-list (- head-group-max-length 
this-head-group-length) padding-head))
+     into balanced-heads-groups
+     else collect heads-group into balanced-heads-groups
+     finally return balanced-heads-groups))
+
+(defun hydra--generate-matrix (heads-groups)
+  "Return a copy of HEADS-GROUPS decorated with table formating information.
+Details of modification:
+2 virtual heads acting as table header were added to each heads-group.
+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)))
+
+(defun hydra--hint-from-matrix (body heads-matrix)
+  "Generate a formated table-style docstring according to BODY and 
HEADS-MATRIX.
+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
+
+(defun hydra-idle-message (secs hint name)
   "In SECS seconds display HINT."
   (cancel-timer hydra-message-timer)
   (setq hydra-message-timer (timer-create))
@@ -867,10 +1091,7 @@ NAMES should be defined by `defhydradio' or similar."
   (timer-set-function
    hydra-message-timer
    (lambda ()
-     (when hydra-is-helpful
-       (if hydra-lv
-           (lv-message (eval hint))
-         (message (eval hint))))
+     (hydra-show-hint hint name)
      (cancel-timer hydra-message-timer)))
   (timer-activate hydra-message-timer))
 
@@ -941,6 +1162,7 @@ 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))
+  (setq heads (copy-tree heads))
   (cond ((stringp docstring))
         ((and (consp docstring)
               (memq (car docstring) '(hydra--table concat format)))
@@ -975,16 +1197,22 @@ result of `defhydra'."
                   ((= len 2)
                    (setcdr (cdr h)
                            (list
-                            (hydra-plist-get-default body-plist :hint "")))
+                            (hydra-plist-get-default
+                             body-plist :hint hydra-default-hint)))
                    (setcdr (nthcdr 2 h) (list :exit body-exit)))
                   (t
                    (let ((hint (cl-caddr h)))
                      (unless (or (null hint)
                                  (stringp hint)
-                                 (stringp (eval hint)))
-                       (setcdr (cdr h) (cons
-                                        (hydra-plist-get-default body-plist 
:hint "")
-                                        (cddr h)))))
+                                 (consp hint))
+                       (let ((inherited-hint
+                              (hydra-plist-get-default
+                               body-plist :hint hydra-default-hint)))
+                         (setcdr (cdr h) (cons
+                                          (if (eq 'none inherited-hint)
+                                              nil
+                                            inherited-hint)
+                                          (cddr h))))))
                    (let ((hint-and-plist (cddr h)))
                      (if (null (cdr hint-and-plist))
                          (setcdr hint-and-plist (list :exit body-exit))
diff --git a/packages/hydra/lv.el b/packages/hydra/lv.el
index 23d2c30..87f7e5e 100644
--- a/packages/hydra/lv.el
+++ b/packages/hydra/lv.el
@@ -65,9 +65,9 @@ Only the background color is significant."
                     (let ((ignore-window-parameters t))
                       (split-window
                        (frame-root-window) -1 'below))))
-        (if (setq buf (get-buffer "*LV*"))
+        (if (setq buf (get-buffer " *LV*"))
             (switch-to-buffer buf)
-          (switch-to-buffer "*LV*")
+          (switch-to-buffer " *LV*")
           (set-window-hscroll lv-wnd 0)
           (setq window-size-fixed t)
           (setq mode-line-format nil)



reply via email to

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