|
|
;;; 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.;;;; 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)
;;* 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"))) (hydra-set-property 'hydra-vi :verbosity 1))
;; 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)(declare-function dired-mark "dired")(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(require 'rect)(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^^^^ ^ ^ _x_kill"
("h" rectangle-backward-char nil) ("l" rectangle-forward-char nil) ("k" rectangle-previous-line nil) ("j" rectangle-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) ("x" kill-rectangle nil) ("o" nil nil))
;; Recommended binding:;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body)
;;** Example 12: org-agenda-view(defun org-agenda-cts () (and (eq major-mode 'org-agenda-mode) (let ((args (get-text-property (min (1- (point-max)) (point)) 'org-last-args))) (nth 2 args))))
(defhydra hydra-org-agenda-view (:hint none) "
_d_: ?d? day _g_: time grid=?g? _a_: arch-trees_w_: ?w? week _[_: inactive _A_: arch-files_t_: ?t? fortnight _f_: follow=?f? _r_: clock report=?r?_m_: ?m? month _e_: entry text=?e? _D_: include diary=?D?_y_: ?y? year _q_: quit _L__l__c_: log = ?l?" ("SPC" org-agenda-reset-view) ("d" org-agenda-day-view (if (eq 'day (org-agenda-cts)) "[x]" "[ ]")) ("w" org-agenda-week-view (if (eq 'week (org-agenda-cts)) "[x]" "[ ]")) ("t" org-agenda-fortnight-view (if (eq 'fortnight (org-agenda-cts)) "[x]" "[ ]")) ("m" org-agenda-month-view (if (eq 'month (org-agenda-cts)) "[x]" "[ ]")) ("y" org-agenda-year-view (if (eq 'year (org-agenda-cts)) "[x]" "[ ]")) ("l" org-agenda-log-mode (format "% -3S" org-agenda-show-log)) ("L" (org-agenda-log-mode '(4))) ("c" (org-agenda-log-mode 'clockcheck)) ("f" org-agenda-follow-mode (format "% -3S" org-agenda-follow-mode)) ("a" org-agenda-archives-mode) ("A" (org-agenda-archives-mode 'files)) ("r" org-agenda-clockreport-mode (format "% -3S" org-agenda-clockreport-mode)) ("e" org-agenda-entry-text-mode (format "% -3S" org-agenda-entry-text-mode)) ("g" org-agenda-toggle-time-grid (format "% -3S" org-agenda-use-time-grid)) ("D" org-agenda-toggle-diary (format "% -3S" org-agenda-include-diary)) ("!" org-agenda-toggle-deadlines) ("[" (let ((org-agenda-include-inactive-timestamps t)) (org-agenda-check-type t 'timeline 'agenda) (org-agenda-redo) (message "Display now includes inactive timestamps as well"))) ("q" (message "Abort") :exit t) ("v" nil))
;; Recommended binding:;; (define-key org-agenda-mode-map "v" 'hydra-org-agenda-view/body)
;;** Example 13: automatic columns(defhydra hydra-movement () ("j" next-line "down" :column "Vertical") ("k" previous-line "up") ("l" forward-char "forward" :column "Horizontal") ("h" backward-char "back"))
;;* Helpers(require 'windmove)
(defun hydra-move-splitter-left (arg) "Move window splitter left." (interactive "p") (if (let ((windmove-wrap-around)) (windmove-find-other-window 'right)) (shrink-window-horizontally arg) (enlarge-window-horizontally arg)))
(defun hydra-move-splitter-right (arg) "Move window splitter right." (interactive "p") (if (let ((windmove-wrap-around)) (windmove-find-other-window 'right)) (enlarge-window-horizontally arg) (shrink-window-horizontally arg)))
(defun hydra-move-splitter-up (arg) "Move window splitter up." (interactive "p") (if (let ((windmove-wrap-around)) (windmove-find-other-window 'up)) (enlarge-window arg) (shrink-window arg)))
(defun hydra-move-splitter-down (arg) "Move window splitter down." (interactive "p") (if (let ((windmove-wrap-around)) (windmove-find-other-window 'up)) (shrink-window arg) (enlarge-window arg)))
(defvar rectangle-mark-mode)(defun hydra-ex-point-mark () "Exchange point and mark." (interactive) (if rectangle-mark-mode (rectangle-exchange-point-and-mark) (let ((mk (mark))) (rectangle-mark-mode 1) (goto-char mk))))
(provide 'hydra-examples)
;; Local Variables:;; no-byte-compile: t;; End:;;; hydra-examples.el ends here
|