]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/hydra/hydra-examples.el
Merge commit '1380f8c1a51f31514125a08f632d017cdfb8e26e' from hydra
[gnu-emacs-elpa] / packages / hydra / hydra-examples.el
index c1b02dfdc145afc46cca76761ffec2eb030ca9b5..c20299771b54ff0e8fa7f0ab568cd7e3c8225cc3 100644 (file)
 
 ;;; Commentary:
 ;;
-;; These are the sample Hydras that you can use.
+;; These are the sample Hydras.
+;;
+;; If you want to use them plainly, set `hydra-examples-verbatim' to t
+;; before requiring this file. But it's probably better to only look
+;; at them and use them as templates for building your own.
 
 ;;; 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.")
+;;* Examples
+;;** Example 1: text scale
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-zoom (global-map "<f2>")
+    "zoom"
+    ("g" text-scale-increase "in")
+    ("l" text-scale-decrease "out")))
+
+;; This example generates three commands:
+;;
+;;     `hydra-zoom/text-scale-increase'
+;;     `hydra-zoom/text-scale-decrease'
+;;     `hydra-zoom/body'
+;;
+;; In addition, two of them are bound like this:
+;;
+;;     (global-set-key (kbd "<f2> g") 'hydra-zoom/text-scale-increase)
+;;     (global-set-key (kbd "<f2> l") 'hydra-zoom/text-scale-decrease)
+;;
+;; Note that you can substitute `global-map' with e.g. `emacs-lisp-mode-map' if you need.
+;; The functions generated will be the same, except the binding code will change to:
+;;
+;;     (define-key emacs-lisp-mode-map [f2 103]
+;;       (function hydra-zoom/text-scale-increase))
+;;     (define-key emacs-lisp-mode-map [f2 108]
+;;       (function hydra-zoom/text-scale-decrease))
+
+;;** Example 2: move window splitter
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-splitter (global-map "C-M-s")
+    "splitter"
+    ("h" hydra-move-splitter-left)
+    ("j" hydra-move-splitter-down)
+    ("k" hydra-move-splitter-up)
+    ("l" hydra-move-splitter-right)))
+
+;;** Example 3: jump to error
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-error (global-map "M-g")
+    "goto-error"
+    ("h" first-error "first")
+    ("j" next-error "next")
+    ("k" previous-error "prev")
+    ("v" recenter-top-bottom "recenter")
+    ("q" nil "quit")))
+
+;; This example introduces only one new thing: since the command
+;; passed to the "q" head is nil, it will quit the Hydra without doing
+;; anything. Heads that quit the Hydra instead of continuing are
+;; referred to as having blue :color. All the other heads have red
+;; :color, unless other is specified.
+
+;;** Example 4: toggle rarely used modes
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defvar whitespace-mode nil)
+  (global-set-key
+   (kbd "C-c C-v")
+   (defhydra hydra-toggle-simple (: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"))))
+
+;; Note that in this case, `defhydra' returns the `hydra-toggle-simple/body'
+;; symbol, which is then passed to `global-set-key'.
+;;
+;; Another new thing is that both the keymap and the body prefix are
+;; skipped.  This means that `defhydra' will bind nothing - that's why
+;; `global-set-key' is necessary.
+;;
+;; One more new thing is that you can assign a :color to the body. All
+;; heads will inherit this color. The code above is very much equivalent to:
+;;
+;;     (global-set-key (kbd "C-c C-v a") 'abbrev-mode)
+;;     (global-set-key (kbd "C-c C-v d") 'toggle-debug-on-error)
+;;
+;; The differences are:
+;;
+;; * You get a hint immediately after "C-c C-v"
+;; * You can cancel and call a command immediately, e.g. "C-c C-v C-n"
+;;   is equivalent to "C-n" with Hydra approach, while it will error
+;;   that "C-c C-v C-n" isn't bound with the usual approach.
+
+;;** Example 5: mini-vi
+(defun hydra-vi/pre ()
+  (set-cursor-color "#e52b50"))
+
+(defun hydra-vi/post ()
+  (set-cursor-color "#ffffff"))
+
+(when (bound-and-true-p hydra-examples-verbatim)
+  (global-set-key
+   (kbd "C-z")
+   (defhydra hydra-vi (:pre hydra-vi/pre :post hydra-vi/post :color amaranth)
+     "vi"
+     ("l" forward-char)
+     ("h" backward-char)
+     ("j" next-line)
+     ("k" previous-line)
+     ("m" set-mark-command "mark")
+     ("a" move-beginning-of-line "beg")
+     ("e" move-end-of-line "end")
+     ("d" delete-region "del" :color blue)
+     ("y" kill-ring-save "yank" :color blue)
+     ("q" nil "quit"))))
+
+;; This example introduces :color amaranth. It's similar to red,
+;; except while you can quit red with any binding which isn't a Hydra
+;; head, you can quit amaranth only with a blue head. So you can quit
+;; this mode only with "d", "y", "q" or "C-g".
+;;
+;; Another novelty are the :pre and :post handlers. :pre will be
+;; called before each command, while :post will be called when the
+;; Hydra quits. In this case, they're used to override the cursor
+;; color while Hydra is active.
 
+;;** Example 6: selective global bind
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-next-error (global-map "C-x")
+    "next-error"
+    ("`" next-error "next")
+    ("j" next-error "next" :bind nil)
+    ("k" previous-error "previous" :bind nil)))
+
+;; This example will bind "C-x `" in `global-map', but it will not
+;; bind "C-x j" and "C-x k".
+;; You can still "C-x `jjk" though.
+
+;;** Example 7: toggle with Ruby-style docstring
+(defvar whitespace-mode nil)
+(defhydra hydra-toggle (:color pink)
+  "
+_a_ abbrev-mode:       %`abbrev-mode
+_d_ debug-on-error:    %`debug-on-error
+_f_ auto-fill-mode:    %`auto-fill-function
+_t_ truncate-lines:    %`truncate-lines
+_w_ whitespace-mode:   %`whitespace-mode
+
+"
+  ("a" abbrev-mode nil)
+  ("d" toggle-debug-on-error nil)
+  ("f" auto-fill-mode nil)
+  ("t" toggle-truncate-lines nil)
+  ("w" whitespace-mode nil)
+  ("q" nil "quit"))
+;; Recommended binding:
+;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
+
+;; Here, using e.g. "_a_" translates to "a" with proper face.
+;; More interestingly:
+;;
+;;     "foobar %`abbrev-mode" means roughly (format "foobar %S" abbrev-mode)
+;;
+;; This means that you actually see the state of the mode that you're changing.
+
+;;** Example 8: the whole menu for `Buffer-menu-mode'
+(defhydra hydra-buffer-menu (:color pink
+                             :hint nil)
+  "
+^Mark^             ^Unmark^           ^Actions^          ^Search
+^^^^^^^^-----------------------------------------------------------------                        (__)
+_m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch                         (oo)
+_s_: save          _U_: unmark up     _b_: bury          _I_: isearch                      /------\\/
+_d_: delete        ^ ^                _g_: refresh       _O_: multi-occur                 / |    ||
+_D_: delete up     ^ ^                _T_: files only: % -28`Buffer-menu-files-only^^    *  /\\---/\\
+_~_: modified      ^ ^                ^ ^                ^^                                 ~~   ~~
+"
+  ("m" Buffer-menu-mark)
+  ("u" Buffer-menu-unmark)
+  ("U" Buffer-menu-backup-unmark)
+  ("d" Buffer-menu-delete)
+  ("D" Buffer-menu-delete-backwards)
+  ("s" Buffer-menu-save)
+  ("~" Buffer-menu-not-modified)
+  ("x" Buffer-menu-execute)
+  ("b" Buffer-menu-bury)
+  ("g" revert-buffer)
+  ("T" Buffer-menu-toggle-files-only)
+  ("O" Buffer-menu-multi-occur :color blue)
+  ("I" Buffer-menu-isearch-buffers :color blue)
+  ("R" Buffer-menu-isearch-buffers-regexp :color blue)
+  ("c" nil "cancel")
+  ("v" Buffer-menu-select "select" :color blue)
+  ("o" Buffer-menu-other-window "other-window" :color blue)
+  ("q" quit-window "quit" :color blue))
+;; Recommended binding:
+;; (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
+
+;;** Example 9: s-expressions in the docstring
+;; You can inline s-expresssions into the docstring like this:
+(defvar dired-mode-map)
+(when (bound-and-true-p hydra-examples-verbatim)
+  (require 'dired)
+  (defhydra hydra-marked-items (dired-mode-map "")
+    "
+Number of marked items: %(length (dired-get-marked-files))
+"
+    ("m" dired-mark "mark")))
+
+;; This results in the following dynamic docstring:
+;;
+;;     (format "Number of marked items: %S\n"
+;;             (length (dired-get-marked-files)))
+;;
+;; You can use `format'-style width specs, e.g. % 10(length nil).
+
+;;** Example 10: apropos family
+(defhydra hydra-apropos (:color blue
+                         :hint nil)
+  "
+_a_propos        _c_ommand
+_d_ocumentation  _l_ibrary
+_v_ariable       _u_ser-option
+^ ^          valu_e_"
+  ("a" apropos)
+  ("d" apropos-documentation)
+  ("v" apropos-variable)
+  ("c" apropos-command)
+  ("l" apropos-library)
+  ("u" apropos-user-option)
+  ("e" apropos-value))
+;; Recommended binding:
+;; (global-set-key (kbd "C-c h") 'hydra-apropos/body)
+
+;;** Example 11: rectangle-mark-mode
+(defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1)
+                           :color pink
+                           :post (deactivate-mark))
+  "
+  ^_k_^     _d_elete    _s_tring
+_h_   _l_   _o_k        _y_ank
+  ^_j_^     _n_ew-copy  _r_eset
+^^^^        _e_xchange  _u_ndo
+^^^^        ^ ^         _p_aste
+"
+  ("h" backward-char nil)
+  ("l" forward-char nil)
+  ("k" previous-line nil)
+  ("j" next-line nil)
+  ("e" hydra-ex-point-mark nil)
+  ("n" copy-rectangle-as-kill nil)
+  ("d" delete-rectangle nil)
+  ("r" (if (region-active-p)
+           (deactivate-mark)
+         (rectangle-mark-mode 1)) nil)
+  ("y" yank-rectangle nil)
+  ("u" undo nil)
+  ("s" string-rectangle nil)
+  ("p" kill-rectangle nil)
+  ("o" nil nil))
+
+;; Recommended binding:
+;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body)
+
+;;* Helpers
 (require 'windmove)
 
-(defun hydra-move-splitter-left ()
+(defun hydra-move-splitter-left (arg)
   "Move window splitter left."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'right))
-      (shrink-window-horizontally 1)
-    (enlarge-window-horizontally 1)))
+      (shrink-window-horizontally arg)
+    (enlarge-window-horizontally arg)))
 
-(defun hydra-move-splitter-right ()
+(defun hydra-move-splitter-right (arg)
   "Move window splitter right."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'right))
-      (enlarge-window-horizontally 1)
-    (shrink-window-horizontally 1)))
+      (enlarge-window-horizontally arg)
+    (shrink-window-horizontally arg)))
 
-(defun hydra-move-splitter-up ()
+(defun hydra-move-splitter-up (arg)
   "Move window splitter up."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'up))
-      (enlarge-window 1)
-    (shrink-window 1)))
+      (enlarge-window arg)
+    (shrink-window arg)))
 
-(defun hydra-move-splitter-down ()
+(defun hydra-move-splitter-down (arg)
   "Move window splitter down."
-  (interactive)
+  (interactive "p")
   (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.")
+      (shrink-window arg)
+    (enlarge-window arg)))
 
-(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.")
-
-(defvar hydra-example-windmove
-  '(("h" windmove-left)
-    ("j" windmove-down)
-    ("k" windmove-up)
-    ("l" windmove-right))
-  "A four-headed hydra for `windmove'.")
+(defvar rectangle-mark-mode)
+(defun hydra-ex-point-mark ()
+  "Exchange point and mark."
+  (interactive)
+  (if rectangle-mark-mode
+      (exchange-point-and-mark)
+    (let ((mk (mark)))
+      (rectangle-mark-mode 1)
+      (goto-char mk))))
 
 (provide 'hydra-examples)
 ;;; hydra-examples.el ends here