[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 659694c 1/8: hydra.el (defhydra): new macro to create hydr
From: |
Oleh Krehel |
Subject: |
[elpa] master 659694c 1/8: hydra.el (defhydra): new macro to create hydras. |
Date: |
Fri, 30 Jan 2015 16:18:49 +0000 |
branch: master
commit 659694cc4b73697f4bf0f9329dba0129cf8695a8
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>
hydra.el (defhydra): new macro to create hydras.
* hydra.el (hydra--callablep): New function.
(hydra-create): Write down in terms of `defhydra'.
(defhydra): New macro.
`defhydra' uses more parameters than `hydra-create' and looks more like
a `defun':
(defhydra hydra-windmove (global-map "C-M-o")
"windmove"
("h" windmove-left)
("j" windmove-down)
("k" windmove-up)
("l" windmove-right)
("o"))
(defhydra hydra-zoom (global-map "<f2>")
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out"))
(defhydra lispy-knight ()
"knight"
("j" lispy-knight-down)
("k" lispy-knight-up)
("z"))
Important advantages:
- Hydra body can be omitted. If you do this, you can bind the functions
that `defhydra' produced (in the example above, `lispy-knight/body')
yourself. It can be useful e.g. if you want to call these functions
conditionally.
- Each Hydra gets a nice name, like `hydra-windmove/windmove-left'
instead of the old `hydra-C-M-o-windmove-left'.
- Hydra hint (base) can now be customized.
---
hydra.el | 106 ++++++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 76 insertions(+), 30 deletions(-)
diff --git a/hydra.el b/hydra.el
index 5ef69ee..e82d95f 100644
--- a/hydra.el
+++ b/hydra.el
@@ -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)
@@ -127,34 +177,30 @@ When `(keymapp METHOD)`, it becomes:
(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 <=
- [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, 2015/01/30