[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
- [elpa] master updated (2452ff7 -> 84c0e7b), Oleh Krehel, 2015/01/30
- [elpa] master b5615dc 3/8: hydra-examples.el: Update commentary, Oleh Krehel, 2015/01/30
- [elpa] master bb9f582 5/8: When calling `prefix/nil', make sure there's something to disable, Oleh Krehel, 2015/01/30
- [elpa] master 785f837 6/8: hydra.el (defhydra): Use `clear-temporary-overlay-map', Oleh Krehel, 2015/01/30
- [elpa] master 659694c 1/8: hydra.el (defhydra): new macro to create hydras., Oleh Krehel, 2015/01/30
- [elpa] master 06b63f1 7/8: Bump version, Oleh Krehel, 2015/01/30
- [elpa] master 2ff0671 2/8: Add automated testing, Oleh Krehel, 2015/01/30
- [elpa] master 4d4f726 4/8: README.md: update, Oleh Krehel, 2015/01/30
- [elpa] master 84c0e7b 8/8: Merge commit '06b63f1d718d12d15aaf9459b492944203764d2f' from hydra,
Oleh Krehel <=