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

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

[elpa] master ca6142f: hydra: New package


From: Oleh Krehel
Subject: [elpa] master ca6142f: hydra: New package
Date: Wed, 21 Jan 2015 19:16:50 +0000

branch: master
commit ca6142fc1f277564ee9460fff911899e8ec76952
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>

    hydra: New package
---
 packages/hydra/hydra-examples.el |   85 +++++++++++++++++++++
 packages/hydra/hydra.el          |  154 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 239 insertions(+), 0 deletions(-)

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]