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

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

[elpa] master f31d537 26/27: Add 'packages/hydra/' from commit 'cfac8bd9


From: Oleh Krehel
Subject: [elpa] master f31d537 26/27: Add 'packages/hydra/' from commit 'cfac8bd9e73ea1e219250867b22881354fc2d56e'
Date: Sat, 24 Jan 2015 20:36:38 +0000

branch: master
commit f31d537957ab67e08369b5be314e66a89ace3600
Merge: 685c83b cfac8bd
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>

    Add 'packages/hydra/' from commit 'cfac8bd9e73ea1e219250867b22881354fc2d56e'
    
    git-subtree-dir: packages/hydra
    git-subtree-mainline: 685c83b6320396e3cc6d7b4eb79d7481fe059416
    git-subtree-split: cfac8bd9e73ea1e219250867b22881354fc2d56e
---
 packages/hydra/README.md         |   77 +++++++++++++++++++
 packages/hydra/hydra-examples.el |   85 +++++++++++++++++++++
 packages/hydra/hydra.el          |  154 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 316 insertions(+), 0 deletions(-)

diff --git a/packages/hydra/README.md b/packages/hydra/README.md
new file mode 100644
index 0000000..f7ddd40
--- /dev/null
+++ b/packages/hydra/README.md
@@ -0,0 +1,77 @@
+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.
+
+Once you summon the Hydra through the prefixed binding (the body + any
+one head), all heads can be called in succession with only a short
+extension.
+
+The Hydra is vanquished once Hercules, any binding that isn't the
+Hydra's head, arrives.  Note that Hercules, besides vanquishing the
+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:
+
+    (require 'hydra-examples)
+    (hydra-create "C-M-y" hydra-example-move-window-splitter)
+    (hydra-create "M-g" hydra-example-goto-error)
+
+You can expand the examples in-place, it still looks elegant:
+
+    (hydra-create "<f2>"
+      '(("g" text-scale-increase)
+        ("l" text-scale-decrease)))
+
+See the [introductory blog 
post](http://oremacs.com/2015/01/20/introducing-hydra/) for more information.
+
+![hydra](http://oremacs.com/download/Hydra.png)
+
+## 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)
+```
+
+## Can Hydras can be helpful?
+
+They can, if
+
+```cl
+(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:
+
+```
+(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.")
+```
+
+With this, you'll see `hydra: [g]: zoom in, [l]: zoom 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
new file mode 100644
index 0000000..c07bd8e
--- /dev/null
+++ b/packages/hydra/hydra-examples.el
@@ -0,0 +1,85 @@
+;;; hydra-examples.el --- Some applications for Hydra
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; These are the sample Hydras that you can use.
+
+;;; Code:
+
+(require 'hydra)
+
+(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.")
+
+(require 'windmove)
+
+(defun hydra-move-splitter-left ()
+  "Move window splitter left."
+  (interactive)
+  (if (let ((windmove-wrap-around))
+        (windmove-find-other-window 'right))
+      (shrink-window-horizontally 1)
+    (enlarge-window-horizontally 1)))
+
+(defun hydra-move-splitter-right ()
+  "Move window splitter right."
+  (interactive)
+  (if (let ((windmove-wrap-around))
+        (windmove-find-other-window 'right))
+      (enlarge-window-horizontally 1)
+    (shrink-window-horizontally 1)))
+
+(defun hydra-move-splitter-up ()
+  "Move window splitter up."
+  (interactive)
+  (if (let ((windmove-wrap-around))
+        (windmove-find-other-window 'up))
+      (enlarge-window 1)
+    (shrink-window 1)))
+
+(defun hydra-move-splitter-down ()
+  "Move window splitter down."
+  (interactive)
+  (if (let ((windmove-wrap-around))
+        (windmove-find-other-window 'up))
+      (shrink-window 1)
+    (enlarge-window 1)))
+
+(defvar hydra-example-move-window-splitter
+  '(("h" hydra-move-splitter-left)
+    ("j" hydra-move-splitter-down)
+    ("k" hydra-move-splitter-up)
+    ("l" hydra-move-splitter-right))
+  "A four-headed hydra for the window splitter manipulation.
+Works best if you have not more than 4 windows.")
+
+(defvar hydra-example-goto-error
+  '(("h" first-error "first")
+    ("j" next-error "next")
+    ("k" previous-error "prev"))
+  "A three-headed hydra for jumping between \"errors\".
+Useful for e.g. `occur', `rgrep' and the like.")
+
+(provide 'hydra-examples)
+;;; hydra-examples.el ends here
diff --git a/packages/hydra/hydra.el b/packages/hydra/hydra.el
new file mode 100644
index 0000000..932cea2
--- /dev/null
+++ b/packages/hydra/hydra.el
@@ -0,0 +1,154 @@
+;;; hydra.el --- Make bindings that stick around
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel <address@hidden>
+;; Maintainer: Oleh Krehel <address@hidden>
+;; URL: https://github.com/abo-abo/hydra
+;; Version: 0.3.0
+;; Keywords: bindings
+;; Package-Requires: ((cl-lib "0.5"))
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This package can be used to tie related commands into a family of
+;; short bindings with a common prefix - a Hydra.
+;;
+;; Once you summon the Hydra (through the prefixed binding), all the
+;; heads can be called in succession with only a short extension.
+;; The Hydra is vanquished once Hercules, any binding that isn't the
+;; Hydra's head, arrives.  Note that Hercules, besides vanquishing the
+;; 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 automagically.
+;;
+;; Here's how to use the examples bundled with Hydra:
+;;
+;;    (require 'hydra-examples)
+;;    (hydra-create "C-M-y" hydra-example-move-window-splitter)
+;;    (hydra-create "M-g" hydra-example-goto-error)
+;;
+;; You can expand the examples in-place, it still looks elegant:
+;;
+;;     (hydra-create "<f2>"
+;;       '(("g" text-scale-increase "zoom in")
+;;         ("l" text-scale-decrease "zoom out")))
+;;
+;; The third element of each list is the optional doc string that will
+;; be displayed in the echo area when `hydra-is-helpful' is t.
+
+;;; Code:
+(require 'cl-lib)
+
+(defgroup hydra nil
+  "Make bindings that stick around."
+  :group 'bindings
+  :prefix "hydra-")
+
+(defcustom hydra-is-helpful t
+  "When t, display a hint with possible bindings in the echo area."
+  :type 'boolean
+  :group 'hydra)
+
+(defalias 'hydra-set-transient-map
+  (if (fboundp 'set-transient-map)
+      'set-transient-map
+    'set-temporary-overlay-map))
+
+(defvar hydra-last nil
+  "The result of the last `hydra-set-transient-map' call.")
+
+;;;###autoload
+(defmacro hydra-create (body heads &optional method)
+  "Create a hydra with a BODY prefix and HEADS with METHOD.
+This will result in `global-set-key' statements with the keys
+being the concatenation of BODY and each head in HEADS.  HEADS is
+an list of (KEY FUNCTION &optional HINT).
+
+After one of the HEADS is called via BODY+KEY, it and the other
+HEADS can be called with only KEY (no need for BODY).  This state
+is broken once any key binding that is not in HEADS is called.
+
+METHOD is a lambda takes two arguments: a KEY and a COMMAND.
+It defaults to `global-set-key'.
+When `(keymapp METHOD)`, it becomes:
+
+    (lambda (key command) (define-key METHOD key command))"
+  (declare (indent 1))
+  (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)))))
+                 heads))
+         (hint (format "hydra: %s."
+                       (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 a \"%s\" body and the heads:\n\n%s."
+               body
+               (mapconcat
+                (lambda (x)
+                  (format "\"%s\":    `%S'" (car x) (cadr x)))
+                heads ",\n")))
+         map
+         (method
+          (cond ((null method)
+                 (unless (keymapp (global-key-binding (kbd body)))
+                   (global-set-key (kbd body) nil))
+                 'global-set-key)
+                ((keymapp (setq map (eval method)))
+                 (unless (keymapp (lookup-key map (kbd body)))
+                   (define-key map (kbd body) nil))
+                 `(lambda (key command)
+                    (define-key ,method key command)))
+                (t
+                 method))))
+    `(progn
+       ,@(cl-mapcar
+          (lambda (head name)
+            `(defun ,name ()
+               ,(format "%s\n\nCall the head: `%S'." doc (cadr head))
+               (interactive)
+               ,@(if (null (cadr head))
+                     '((funcall hydra-last))
+                     `((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)) ()
+         ,doc
+         (interactive)
+         (when hydra-is-helpful
+           (message ,hint))
+         (setq hydra-last (hydra-set-transient-map ',keymap t)))
+       ,@(cl-mapcar
+          (lambda (head name)
+            `(,method ,(vconcat (kbd body) (kbd (car head))) #',name))
+          heads names))))
+
+(provide 'hydra)
+;;; hydra.el ends here



reply via email to

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