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

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

[elpa] master 84c0e7b 8/8: Merge commit '06b63f1d718d12d15aaf9459b492944


From: Oleh Krehel
Subject: [elpa] master 84c0e7b 8/8: Merge commit '06b63f1d718d12d15aaf9459b492944203764d2f' from hydra
Date: Fri, 30 Jan 2015 16:18:52 +0000

branch: master
commit 84c0e7b34684cbf4162f80f167a1178657779d87
Merge: 2452ff7 06b63f1
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>

    Merge commit '06b63f1d718d12d15aaf9459b492944203764d2f' from hydra
---
 packages/hydra/.travis.yml       |   12 ++++
 packages/hydra/Makefile          |   12 ++++
 packages/hydra/README.md         |  101 ++++++++++++++++++++++------------
 packages/hydra/hydra-examples.el |    9 +++
 packages/hydra/hydra-test.el     |  110 +++++++++++++++++++++++++++++++++++++
 packages/hydra/hydra.el          |  113 +++++++++++++++++++++++++++-----------
 6 files changed, 289 insertions(+), 68 deletions(-)

diff --git a/packages/hydra/.travis.yml b/packages/hydra/.travis.yml
new file mode 100644
index 0000000..1f5dbc7
--- /dev/null
+++ b/packages/hydra/.travis.yml
@@ -0,0 +1,12 @@
+language: emacs-lisp
+env:
+  matrix:
+    - EMACS=emacs24
+
+before_install:
+  - sudo add-apt-repository -y ppa:cassou/emacs
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq $EMACS
+
+script:
+  - make test
diff --git a/packages/hydra/Makefile b/packages/hydra/Makefile
new file mode 100644
index 0000000..97bcea6
--- /dev/null
+++ b/packages/hydra/Makefile
@@ -0,0 +1,12 @@
+EMACS = emacs
+# EMACS = emacs-24.3
+
+.PHONY: all test clean
+
+all: test
+
+test:
+       $(EMACS) -batch -l hydra.el -l hydra-test.el -f 
ert-run-tests-batch-and-exit
+
+clean:
+       rm -f *.elc
diff --git a/packages/hydra/README.md b/packages/hydra/README.md
index f7ddd40..24c8cf7 100644
--- a/packages/hydra/README.md
+++ b/packages/hydra/README.md
@@ -1,3 +1,5 @@
+[![Build 
Status](https://travis-ci.org/abo-abo/hydra.svg?branch=master)](https://travis-ci.org/abo-abo/hydra)
+
 This is a package for GNU Emacs that can be used to tie related
 commands into a family of short bindings with a common prefix - a
 Hydra.
@@ -12,17 +14,57 @@ Hydra, will still serve his orignal purpose, calling his 
proper
 command.  This makes the Hydra very seamless, it's like a minor mode
 that disables itself auto-magically.
 
-Here's how I use the examples bundled with Hydra:
+Here's how to quickly bind the examples bundled with Hydra:
+
+```cl
+(require 'hydra-examples)
+(hydra-create "C-M-y" hydra-example-move-window-splitter)
+(hydra-create "M-g" hydra-example-goto-error)
+(hydra-create "<f2>" hydra-example-text-scale)
+```
+
+But it's much better to just take the examples as a template and write
+down everything explicitly:
+
+```cl
+(defhydra hydra-zoom (global-map "<f2>")
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out"))
+```
+
+With the example above, you can e.g.:
+
+```cl
+(key-chord-define-global "tt" 'hydra-zoom/body)
+```
+
+In fact, since `defhydra` returns the body symbol, you can even write
+it like this:
 
-    (require 'hydra-examples)
-    (hydra-create "C-M-y" hydra-example-move-window-splitter)
-    (hydra-create "M-g" hydra-example-goto-error)
+```cl
+(key-chord-define-global
+ "tt"
+ (defhydra hydra-zoom (global-map "<f2>")
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out")))
+```
 
-You can expand the examples in-place, it still looks elegant:
+If you like key chords so much that you don't want to touch the global map at 
all, you can e.g.:
 
-    (hydra-create "<f2>"
-      '(("g" text-scale-increase)
-        ("l" text-scale-decrease)))
+```
+(key-chord-define-global
+ "hh"
+ (defhydra hydra-error ()
+   "goto-error"
+   ("h" first-error "first")
+   ("j" next-error "next")
+   ("k" previous-error "prev")))
+```
+
+You can also substitute `global-map` with any other keymap, like
+`c++-mode-map` or `yas-minor-mode-map`.
 
 See the [introductory blog 
post](http://oremacs.com/2015/01/20/introducing-hydra/) for more information.
 
@@ -30,29 +72,15 @@ See the [introductory blog 
post](http://oremacs.com/2015/01/20/introducing-hydra
 
 ## Using Hydra to define bindings other than global ones
 
-You can use the third optional argument of `hydra-create` for this (it 
defaults to `global-set-key`).
 Here's an example:
 
 ```cl
-(hydra-create "C-z"
-  '(("l" forward-char)
-    ("h" backward-char)
-    ("j" next-line)
-    ("k" previous-line))
-  (lambda (key command)
-    (define-key lispy-mode-map key command)))
-```
-
-For this simple case, there's even a shortcut: if you give a keymap as the 
third argument,
-the lambda will be generated for you:
-
-```cl
-(hydra-create "C-z"
-  '(("l" forward-char)
-    ("h" backward-char)
-    ("j" next-line)
-    ("k" previous-line))
-    lispy-mode-map)
+(defhydra lispy-vi (lispy-mode-map "C-z")
+  "vi"
+  ("l" forward-char)
+  ("h" backward-char)
+  ("j" next-line)
+  ("k" previous-line))
 ```
 
 ## Can Hydras can be helpful?
@@ -63,15 +91,16 @@ They can, if
 (setq hydra-is-helpful t)
 ```
 
-In that case, you'll get a hint in the echo area consisting of current Hydra's 
heads.
-You can even add comments to the heads like this:
+This is the default setting. In this case, you'll get a hint in the
+echo area consisting of current Hydra's base comment and heads.  You
+can even add comments to the heads like this:
 
 ```
-(defvar hydra-example-text-scale
-  '(("g" text-scale-increase "zoom in")
-    ("l" text-scale-decrease "zoom out"))
-  "A two-headed hydra for text scale manipulation.")
+(defhydra hydra-zoom (global-map "<f2>")
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out"))
 ```
 
-With this, you'll see `hydra: [g]: zoom in, [l]: zoom out.` in your
-echo area, once the zoom Hydra becomes active.
+With this, you'll see `zoom: [g]: in, [l]: out.` in your echo area,
+once the zoom Hydra becomes active.
diff --git a/packages/hydra/hydra-examples.el b/packages/hydra/hydra-examples.el
index c1b02df..834db70 100644
--- a/packages/hydra/hydra-examples.el
+++ b/packages/hydra/hydra-examples.el
@@ -22,6 +22,15 @@
 ;;; Commentary:
 ;;
 ;; These are the sample Hydras that you can use.
+;;
+;; Note that the better way to create Hydras is with `defhydra':
+;;
+;; (defhydra hydra-zoom (global-map "<f2>")
+;;   "zoom"
+;;   ("g" text-scale-increase "in")
+;;   ("l" text-scale-decrease "out"))
+;;
+;; This way, you have more options, and everything is in one place.
 
 ;;; Code:
 
diff --git a/packages/hydra/hydra-test.el b/packages/hydra/hydra-test.el
new file mode 100644
index 0000000..8ee56eb
--- /dev/null
+++ b/packages/hydra/hydra-test.el
@@ -0,0 +1,110 @@
+(require 'ert)
+
+(ert-deftest defhydra ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-error (global-map "M-g")
+       "error"
+       ("h" first-error "first")
+       ("j" next-error "next")
+       ("k" previous-error "prev")))
+    '(progn
+      (defun hydra-error/first-error ()
+        "Create a hydra with a \"M-g\" body and the heads:
+
+\"h\":    `first-error',
+\"j\":    `next-error',
+\"k\":    `previous-error'
+
+The body can be accessed via `hydra-error/body'.
+
+Call the head: `first-error'."
+        (interactive)
+        (call-interactively #'first-error)
+        (when hydra-is-helpful
+          (message #("error: [h]: first, [j]: next, [k]: prev."
+                     8 9 (face font-lock-keyword-face)
+                     20 21 (face font-lock-keyword-face)
+                     31 32 (face font-lock-keyword-face))))
+        (setq hydra-last
+              (hydra-set-transient-map
+               '(keymap
+                 (107 . hydra-error/previous-error)
+                 (106 . hydra-error/next-error)
+                 (104 . hydra-error/first-error)) t)))
+
+      (defun hydra-error/next-error ()
+        "Create a hydra with a \"M-g\" body and the heads:
+
+\"h\":    `first-error',
+\"j\":    `next-error',
+\"k\":    `previous-error'
+
+The body can be accessed via `hydra-error/body'.
+
+Call the head: `next-error'."
+        (interactive)
+        (call-interactively #'next-error)
+        (when hydra-is-helpful
+          (message #("error: [h]: first, [j]: next, [k]: prev."
+                     8 9 (face font-lock-keyword-face)
+                     20 21 (face font-lock-keyword-face)
+                     31 32 (face font-lock-keyword-face))))
+        (setq hydra-last
+              (hydra-set-transient-map
+               '(keymap
+                 (107 . hydra-error/previous-error)
+                 (106 . hydra-error/next-error)
+                 (104 . hydra-error/first-error)) t)))
+      
+      (defun hydra-error/previous-error ()
+        "Create a hydra with a \"M-g\" body and the heads:
+
+\"h\":    `first-error',
+\"j\":    `next-error',
+\"k\":    `previous-error'
+
+The body can be accessed via `hydra-error/body'.
+
+Call the head: `previous-error'."
+        (interactive)
+        (call-interactively #'previous-error)
+        (when hydra-is-helpful
+          (message #("error: [h]: first, [j]: next, [k]: prev."
+                     8 9 (face font-lock-keyword-face)
+                     20 21 (face font-lock-keyword-face)
+                     31 32 (face font-lock-keyword-face))))
+        (setq hydra-last
+              (hydra-set-transient-map
+               '(keymap
+                 (107 . hydra-error/previous-error)
+                 (106 . hydra-error/next-error)
+                 (104 . hydra-error/first-error)) t)))
+      
+      (unless (keymapp (lookup-key global-map (kbd "M-g")))
+        (define-key global-map (kbd "M-g") nil))
+      (define-key global-map [134217831 104] #'hydra-error/first-error)
+      (define-key global-map [134217831 106] #'hydra-error/next-error)
+      (define-key global-map [134217831 107] #'hydra-error/previous-error)
+      
+      (defun hydra-error/body ()
+        "Create a hydra with a \"M-g\" body and the heads:
+
+\"h\":    `first-error',
+\"j\":    `next-error',
+\"k\":    `previous-error'
+
+The body can be accessed via `hydra-error/body'."
+        (interactive)
+        (when hydra-is-helpful
+          (message #("error: [h]: first, [j]: next, [k]: prev."
+                     8 9 (face font-lock-keyword-face)
+                     20 21 (face font-lock-keyword-face)
+                     31 32 (face font-lock-keyword-face))))
+        (setq hydra-last
+              (hydra-set-transient-map
+               '(keymap
+                 (107 . hydra-error/previous-error)
+                 (106 . hydra-error/next-error)
+                 (104 . hydra-error/first-error)) t)))))))
diff --git a/packages/hydra/hydra.el b/packages/hydra/hydra.el
index 5ef69ee..b7ca064 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.3.1
+;; Version: 0.4.0
 ;; Keywords: bindings
 ;; Package-Requires: ((cl-lib "0.5"))
 
@@ -90,14 +90,61 @@ When `(keymapp METHOD)`, it becomes:
 
     (lambda (key command) (define-key METHOD key command))"
   (declare (indent 1))
+  `(defhydra ,(intern
+               (concat
+                "hydra-" (replace-regexp-in-string " " "_" body)))
+       ,(cond ((hydra--callablep method)
+              method)
+             ((null method)
+              `(global-map ,body))
+             (t
+              (list method body)))
+     "hydra"
+     ,@(eval heads)))
+
+(defun hydra--callablep (x)
+  "Test if X looks like it's callable."
+  (or (functionp x)
+      (and (consp x)
+           (memq (car x) '(function quote)))))
+
+(defmacro defhydra (name body &optional docstring &rest heads)
+  "Create a hydra named NAME with a prefix BODY.
+
+NAME should be a symbol, it will be the prefix of all functions
+defined here.
+
+BODY should be either:
+
+    (BODY-MAP &optional BODY-KEY)
+or:
+
+    (lambda (KEY CMD) ...)
+
+BODY-MAP should be a keymap; `global-map' is acceptable here.
+BODY-KEY should be a string processable by `kbd'.
+
+DOCSTRING will be displayed in the echo area to identify the
+hydra.
+
+HEADS is a list of (KEY CMD &optional HINT)."
+  (unless (stringp docstring)
+    (setq heads (cons docstring heads))
+    (setq docstring "hydra"))
   (let* ((keymap (make-sparse-keymap))
-         (heads (eval heads))
          (names (mapcar
                  (lambda (x)
                    (define-key keymap (kbd (car x))
-                     (intern (format "hydra-%s-%S" body (cadr x)))))
+                     (intern (format "%S/%s" name (cadr x)))))
                  heads))
-         (hint (format "hydra: %s."
+         (body-name (intern (format "%S/body" name)))
+         (body-key (unless (hydra--callablep body)
+                     (cadr body)))
+         (method (if (hydra--callablep body)
+                     body
+                   (car body)))
+         (hint (format "%s: %s."
+                       docstring
                        (mapconcat
                         (lambda (h)
                           (format
@@ -107,12 +154,15 @@ When `(keymapp METHOD)`, it becomes:
                            (propertize (car h) 'face 'font-lock-keyword-face)))
                         heads ", ")))
          (doc (format
-               "Create a hydra with a \"%s\" body and the heads:\n\n%s."
-               body
+               "Create a hydra with %s body and the heads:\n\n%s\n\n%s"
+               (if body-key
+                   (format "a \"%s\"" body-key)
+                 "no")
                (mapconcat
                 (lambda (x)
                   (format "\"%s\":    `%S'" (car x) (cadr x)))
-                heads ",\n"))))
+                heads ",\n")
+               (format "The body can be accessed via `%S'." body-name))))
     `(progn
        ,@(cl-mapcar
           (lambda (head name)
@@ -120,41 +170,40 @@ When `(keymapp METHOD)`, it becomes:
                ,(format "%s\n\nCall the head: `%S'." doc (cadr head))
                (interactive)
                ,@(if (null (cadr head))
-                     '((funcall hydra-last))
+                     '((if (functionp hydra-last)
+                           (funcall hydra-last)
+                         (ignore-errors
+                           (funcall 'clear-temporary-overlay-map))))
                      `((call-interactively #',(cadr head))
                        (when hydra-is-helpful
                          (message ,hint))
                        (setq hydra-last
                              (hydra-set-transient-map ',keymap t))))))
           heads names)
-       (defun ,(intern (format "hydra-%s-body" body)) ()
+       ,@(unless (or (null body-key)
+                     (null method)
+                     (hydra--callablep method))
+                 `((unless (keymapp (lookup-key ,method (kbd ,body-key)))
+                     (define-key ,method (kbd ,body-key) nil))))
+       ,@(delq nil
+               (cl-mapcar
+                (lambda (head name)
+                  (unless (or (null body-key) (null method))
+                    (list
+                     (if (hydra--callablep method)
+                         'funcall
+                       'define-key)
+                     method
+                     (vconcat (kbd body-key) (kbd (car head)))
+                     (list 'function name))))
+                heads names))
+       (defun ,body-name ()
          ,doc
          (interactive)
          (when hydra-is-helpful
            (message ,hint))
-         (setq hydra-last (hydra-set-transient-map ',keymap t)))
-       ,@(cond ((null method)
-                `((unless (keymapp (global-key-binding (kbd ,body)))
-                    (global-set-key (kbd ,body) nil))))
-               ((or (functionp method)
-                    (and (consp method)
-                         (memq (car method) '(function quote))))
-                nil)
-               (t
-                `((unless (keymapp (lookup-key ,method (kbd ,body)))
-                    (define-key ,method (kbd ,body) nil)))))
-       ,@(cl-mapcar
-          (lambda (head name)
-            `(,@(cond ((null method)
-                      (list 'global-set-key))
-                      ((or (functionp method)
-                           (and (consp method)
-                                (memq (car method) '(function quote))))
-                      (list 'funcall method))
-                     (t
-                      (list 'define-key method)))
-                ,(vconcat (kbd body) (kbd (car head))) #',name))
-          heads names))))
+         (setq hydra-last
+               (hydra-set-transient-map ',keymap t))))))
 
 (provide 'hydra)
 ;;; hydra.el ends here



reply via email to

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