-
-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Distinguish red and blue hydra heads
* hydra.el (hydra-face-red): New face. (hydra-face-blue): New face. (hydra--color): Each head now has a color: red is persistent, blue is single-use. Head color inherits body color if it's not explicitly overridden. Body color is red unless explicitly stated. (hydra--face): Return face that corresponds to color. (hydra--hint): New function, moved out of `defhydra'. (hydra-disable): New function, moved out of `defhydra'. (hydra--doc): New function, moved out of `defhydra'. (defhydra): Commands that will vanquish the Hydra should be colored with `hydra-face-blue'. The ones that will make the Hydra persist should be colored with `hydra-face-red'. Add autoload, move some code outside, Test HEAD's second element with `null' instead of `functionp'. * hydra-test.el (defhydra-red-error): Rename from `defhydra'. (hydra-blue-toggle): Add test. * README.md: Update. Example: (global-set-key (kbd "C-c C-v") (defhydra toggle () "toggle" ("t" toggle-truncate-lines "truncate" :color blue) ("f" auto-fill-mode "fill" :color blue) ("a" abbrev-mode "abbrev" :color blue) ("q" nil "cancel"))) Alternatively, since heads inherit color from the body: (global-set-key (kbd "C-c C-v") (defhydra toggle (:color blue) "toggle" ("a" abbrev-mode "abbrev") ("d" toggle-debug-on-error "debug") ("f" auto-fill-mode "fill") ("t" toggle-truncate-lines "truncate") ("w" whitespace-mode "whitespace") ("q" nil "cancel")))
- Loading branch information
Showing
3 changed files
with
241 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
;; Author: Oleh Krehel <[email protected]> | ||
;; Maintainer: Oleh Krehel <[email protected]> | ||
;; URL: https://github.com/abo-abo/hydra | ||
;; Version: 0.4.1 | ||
;; Version: 0.5.0 | ||
;; Keywords: bindings | ||
;; Package-Requires: ((cl-lib "0.5")) | ||
|
||
|
@@ -73,6 +73,15 @@ | |
:type 'boolean | ||
:group 'hydra) | ||
|
||
(defface hydra-face-red | ||
'((t (:foreground "#7F0055" :bold t))) | ||
"Red Hydra heads will persist indefinitely." | ||
:group 'hydra) | ||
|
||
(defface hydra-face-blue | ||
'((t (:foreground "#758BC6" :bold t))) | ||
"Blue Hydra heads will vanquish the Hydra.") | ||
|
||
(defalias 'hydra-set-transient-map | ||
(if (fboundp 'set-transient-map) | ||
'set-transient-map | ||
|
@@ -111,11 +120,70 @@ When `(keymapp METHOD)`, it becomes: | |
,@(eval heads))) | ||
|
||
(defun hydra--callablep (x) | ||
"Test if X looks like it's callable." | ||
"Test if X is callable." | ||
(or (functionp x) | ||
(and (consp x) | ||
(memq (car x) '(function quote))))) | ||
|
||
(defun hydra--color (h body-color) | ||
"Return the color of a Hydra head H with BODY-COLOR." | ||
(if (null (cadr h)) | ||
'blue | ||
(let ((plist (if (stringp (cl-caddr h)) | ||
(cl-cdddr h) | ||
(cddr h)))) | ||
(or (plist-get plist :color) body-color)))) | ||
|
||
(defun hydra--face (h body-color) | ||
"Return the face for a Hydra head H with BODY-COLOR." | ||
(cl-case (hydra--color h body-color) | ||
(blue 'hydra-face-blue) | ||
(red 'hydra-face-red) | ||
(t (error "Unknown color for %S" h)))) | ||
|
||
(defun hydra--hint (docstring heads) | ||
"Generate a hint from DOCSTRING and HEADS. | ||
It's intended for the echo area, when a Hydra is active." | ||
(format "%s: %s." | ||
docstring | ||
(mapconcat | ||
(lambda (h) | ||
(format | ||
(if (stringp (cl-caddr h)) | ||
(concat "[%s]: " (cl-caddr h)) | ||
"%s") | ||
(propertize | ||
(car h) 'face | ||
(hydra--face h body-color)))) | ||
heads ", "))) | ||
|
||
(defun hydra-disable () | ||
"Disable the current Hydra." | ||
(if (functionp hydra-last) | ||
(funcall hydra-last) | ||
(while (and (consp (car emulation-mode-map-alists)) | ||
(consp (caar emulation-mode-map-alists)) | ||
(equal (cl-cdaar emulation-mode-map-alists) ',keymap)) | ||
(setq emulation-mode-map-alists | ||
(cdr emulation-mode-map-alists))))) | ||
|
||
(defun hydra--doc (body-key body-name heads) | ||
"Generate a part of Hydra docstring. | ||
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") | ||
(mapconcat | ||
(lambda (x) | ||
(format "\"%s\": `%S'" (car x) (cadr x))) | ||
heads ",\n") | ||
(format "The body can be accessed via `%S'." body-name))) | ||
|
||
;;;###autoload | ||
(defmacro defhydra (name body &optional docstring &rest heads) | ||
"Create a hydra named NAME with a prefix BODY. | ||
|
@@ -124,7 +192,7 @@ defined here. | |
BODY should be either: | ||
(BODY-MAP &optional BODY-KEY) | ||
(BODY-MAP &optional BODY-KEY &rest PLIST) | ||
or: | ||
(lambda (KEY CMD) ...) | ||
|
@@ -135,10 +203,15 @@ 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)." | ||
HEADS is a list of (KEY CMD &optional HINT &rest PLIST). | ||
PLIST in both cases recognizes only the :color key so far, which | ||
in turn can be either red or blue." | ||
(unless (stringp docstring) | ||
(setq heads (cons docstring heads)) | ||
(setq docstring "hydra")) | ||
(when (keywordp (car body)) | ||
(setq body (cons nil (cons nil body)))) | ||
(let* ((keymap (make-sparse-keymap)) | ||
(names (mapcar | ||
(lambda (x) | ||
|
@@ -148,43 +221,25 @@ HEADS is a list of (KEY CMD &optional HINT)." | |
(body-name (intern (format "%S/body" name))) | ||
(body-key (unless (hydra--callablep body) | ||
(cadr body))) | ||
(body-color (if (hydra--callablep body) | ||
'red | ||
(or (plist-get (cddr body) :color) | ||
'red))) | ||
(method (if (hydra--callablep body) | ||
body | ||
(car body))) | ||
(hint (format "%s: %s." | ||
docstring | ||
(mapconcat | ||
(lambda (h) | ||
(format | ||
(if (cl-caddr h) | ||
(concat "[%s]: " (cl-caddr h)) | ||
"%s") | ||
(propertize (car h) 'face 'font-lock-keyword-face))) | ||
heads ", "))) | ||
(doc (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") | ||
(mapconcat | ||
(lambda (x) | ||
(format "\"%s\": `%S'" (car x) (cadr x))) | ||
heads ",\n") | ||
(format "The body can be accessed via `%S'." body-name)))) | ||
(hint (hydra--hint docstring heads)) | ||
(doc (hydra--doc body-key body-name heads))) | ||
`(progn | ||
,@(cl-mapcar | ||
(lambda (head name) | ||
`(defun ,name () | ||
,(format "%s\n\nCall the head: `%S'." doc (cadr head)) | ||
(interactive) | ||
,@(if (null (cadr head)) | ||
`((if (functionp hydra-last) | ||
(funcall hydra-last) | ||
(while (and (consp (car emulation-mode-map-alists)) | ||
(consp (caar emulation-mode-map-alists)) | ||
(equal (cl-cdaar emulation-mode-map-alists) ',keymap)) | ||
(setq emulation-mode-map-alists | ||
(cdr emulation-mode-map-alists))))) | ||
,@(if (eq (hydra--color head body-color) 'blue) | ||
`((hydra-disable) | ||
,@(unless (null (cadr head)) | ||
`((call-interactively #',(cadr head))))) | ||
`((call-interactively #',(cadr head)) | ||
(when hydra-is-helpful | ||
(message ,hint)) | ||
|