]> code.delx.au - gnu-emacs-elpa/blob - packages/hydra/hydra-examples.el
Merge commit 'e0454a100541ce3f1f732b97894a3441cef3316f' from hydra
[gnu-emacs-elpa] / packages / hydra / hydra-examples.el
1 ;;; hydra-examples.el --- Some applications for Hydra
2
3 ;; Copyright (C) 2015 Free Software Foundation, Inc.
4
5 ;; Author: Oleh Krehel
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22 ;;; Commentary:
23 ;;
24 ;; These are the sample Hydras.
25 ;;
26 ;; If you want to use them plainly, set `hydra-examples-verbatim' to t
27 ;; before requiring this file. But it's probably better to only look
28 ;; at them and use them as templates for building your own.
29
30 ;;; Code:
31
32 (require 'hydra)
33
34 ;;* Examples
35 ;;** Example 1: text scale
36 (when (bound-and-true-p hydra-examples-verbatim)
37 (defhydra hydra-zoom (global-map "<f2>")
38 "zoom"
39 ("g" text-scale-increase "in")
40 ("l" text-scale-decrease "out")))
41
42 ;; This example generates three commands:
43 ;;
44 ;; `hydra-zoom/text-scale-increase'
45 ;; `hydra-zoom/text-scale-decrease'
46 ;; `hydra-zoom/body'
47 ;;
48 ;; In addition, two of them are bound like this:
49 ;;
50 ;; (global-set-key (kbd "<f2> g") 'hydra-zoom/text-scale-increase)
51 ;; (global-set-key (kbd "<f2> l") 'hydra-zoom/text-scale-decrease)
52 ;;
53 ;; Note that you can substitute `global-map' with e.g. `emacs-lisp-mode-map' if you need.
54 ;; The functions generated will be the same, except the binding code will change to:
55 ;;
56 ;; (define-key emacs-lisp-mode-map [f2 103]
57 ;; (function hydra-zoom/text-scale-increase))
58 ;; (define-key emacs-lisp-mode-map [f2 108]
59 ;; (function hydra-zoom/text-scale-decrease))
60
61 ;;** Example 2: move window splitter
62 (when (bound-and-true-p hydra-examples-verbatim)
63 (defhydra hydra-splitter (global-map "C-M-s")
64 "splitter"
65 ("h" hydra-move-splitter-left)
66 ("j" hydra-move-splitter-down)
67 ("k" hydra-move-splitter-up)
68 ("l" hydra-move-splitter-right)))
69
70 ;;** Example 3: jump to error
71 (when (bound-and-true-p hydra-examples-verbatim)
72 (defhydra hydra-error (global-map "M-g")
73 "goto-error"
74 ("h" first-error "first")
75 ("j" next-error "next")
76 ("k" previous-error "prev")
77 ("v" recenter-top-bottom "recenter")
78 ("q" nil "quit")))
79
80 ;; This example introduces only one new thing: since the command
81 ;; passed to the "q" head is nil, it will quit the Hydra without doing
82 ;; anything. Heads that quit the Hydra instead of continuing are
83 ;; referred to as having blue :color. All the other heads have red
84 ;; :color, unless other is specified.
85
86 ;;** Example 4: toggle rarely used modes
87 (when (bound-and-true-p hydra-examples-verbatim)
88 (defvar whitespace-mode nil)
89 (global-set-key
90 (kbd "C-c C-v")
91 (defhydra hydra-toggle-simple (:color blue)
92 "toggle"
93 ("a" abbrev-mode "abbrev")
94 ("d" toggle-debug-on-error "debug")
95 ("f" auto-fill-mode "fill")
96 ("t" toggle-truncate-lines "truncate")
97 ("w" whitespace-mode "whitespace")
98 ("q" nil "cancel"))))
99
100 ;; Note that in this case, `defhydra' returns the `hydra-toggle-simple/body'
101 ;; symbol, which is then passed to `global-set-key'.
102 ;;
103 ;; Another new thing is that both the keymap and the body prefix are
104 ;; skipped. This means that `defhydra' will bind nothing - that's why
105 ;; `global-set-key' is necessary.
106 ;;
107 ;; One more new thing is that you can assign a :color to the body. All
108 ;; heads will inherit this color. The code above is very much equivalent to:
109 ;;
110 ;; (global-set-key (kbd "C-c C-v a") 'abbrev-mode)
111 ;; (global-set-key (kbd "C-c C-v d") 'toggle-debug-on-error)
112 ;;
113 ;; The differences are:
114 ;;
115 ;; * You get a hint immediately after "C-c C-v"
116 ;; * You can cancel and call a command immediately, e.g. "C-c C-v C-n"
117 ;; is equivalent to "C-n" with Hydra approach, while it will error
118 ;; that "C-c C-v C-n" isn't bound with the usual approach.
119
120 ;;** Example 5: mini-vi
121 (defun hydra-vi/pre ()
122 (set-cursor-color "#e52b50"))
123
124 (defun hydra-vi/post ()
125 (set-cursor-color "#ffffff"))
126
127 (when (bound-and-true-p hydra-examples-verbatim)
128 (global-set-key
129 (kbd "C-z")
130 (defhydra hydra-vi (:pre hydra-vi/pre :post hydra-vi/post :color amaranth)
131 "vi"
132 ("l" forward-char)
133 ("h" backward-char)
134 ("j" next-line)
135 ("k" previous-line)
136 ("m" set-mark-command "mark")
137 ("a" move-beginning-of-line "beg")
138 ("e" move-end-of-line "end")
139 ("d" delete-region "del" :color blue)
140 ("y" kill-ring-save "yank" :color blue)
141 ("q" nil "quit"))))
142
143 ;; This example introduces :color amaranth. It's similar to red,
144 ;; except while you can quit red with any binding which isn't a Hydra
145 ;; head, you can quit amaranth only with a blue head. So you can quit
146 ;; this mode only with "d", "y", "q" or "C-g".
147 ;;
148 ;; Another novelty are the :pre and :post handlers. :pre will be
149 ;; called before each command, while :post will be called when the
150 ;; Hydra quits. In this case, they're used to override the cursor
151 ;; color while Hydra is active.
152
153 ;;** Example 6: selective global bind
154 (when (bound-and-true-p hydra-examples-verbatim)
155 (defhydra hydra-next-error (global-map "C-x")
156 "next-error"
157 ("`" next-error "next")
158 ("j" next-error "next" :bind nil)
159 ("k" previous-error "previous" :bind nil)))
160
161 ;; This example will bind "C-x `" in `global-map', but it will not
162 ;; bind "C-x j" and "C-x k".
163 ;; You can still "C-x `jjk" though.
164
165 ;;** Example 7: toggle with Ruby-style docstring
166 (defvar whitespace-mode nil)
167 (defhydra hydra-toggle (:color pink)
168 "
169 _a_ abbrev-mode: %`abbrev-mode
170 _d_ debug-on-error: %`debug-on-error
171 _f_ auto-fill-mode: %`auto-fill-function
172 _t_ truncate-lines: %`truncate-lines
173 _w_ whitespace-mode: %`whitespace-mode
174
175 "
176 ("a" abbrev-mode nil)
177 ("d" toggle-debug-on-error nil)
178 ("f" auto-fill-mode nil)
179 ("t" toggle-truncate-lines nil)
180 ("w" whitespace-mode nil)
181 ("q" nil "quit"))
182 ;; Recommended binding:
183 ;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
184
185 ;; Here, using e.g. "_a_" translates to "a" with proper face.
186 ;; More interestingly:
187 ;;
188 ;; "foobar %`abbrev-mode" means roughly (format "foobar %S" abbrev-mode)
189 ;;
190 ;; This means that you actually see the state of the mode that you're changing.
191
192 ;;** Example 8: the whole menu for `Buffer-menu-mode'
193 (defhydra hydra-buffer-menu (:color pink
194 :hint nil)
195 "
196 ^Mark^ ^Unmark^ ^Actions^ ^Search
197 ^^^^^^^^----------------------------------------------------------------- (__)
198 _m_: mark _u_: unmark _x_: execute _R_: re-isearch (oo)
199 _s_: save _U_: unmark up _b_: bury _I_: isearch /------\\/
200 _d_: delete ^ ^ _g_: refresh _O_: multi-occur / | ||
201 _D_: delete up ^ ^ _T_: files only: % -28`Buffer-menu-files-only^^ * /\\---/\\
202 _~_: modified ^ ^ ^ ^ ^^ ~~ ~~
203 "
204 ("m" Buffer-menu-mark)
205 ("u" Buffer-menu-unmark)
206 ("U" Buffer-menu-backup-unmark)
207 ("d" Buffer-menu-delete)
208 ("D" Buffer-menu-delete-backwards)
209 ("s" Buffer-menu-save)
210 ("~" Buffer-menu-not-modified)
211 ("x" Buffer-menu-execute)
212 ("b" Buffer-menu-bury)
213 ("g" revert-buffer)
214 ("T" Buffer-menu-toggle-files-only)
215 ("O" Buffer-menu-multi-occur :color blue)
216 ("I" Buffer-menu-isearch-buffers :color blue)
217 ("R" Buffer-menu-isearch-buffers-regexp :color blue)
218 ("c" nil "cancel")
219 ("v" Buffer-menu-select "select" :color blue)
220 ("o" Buffer-menu-other-window "other-window" :color blue)
221 ("q" quit-window "quit" :color blue))
222 ;; Recommended binding:
223 ;; (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
224
225 ;;** Example 9: s-expressions in the docstring
226 ;; You can inline s-expresssions into the docstring like this:
227 (defvar dired-mode-map)
228 (declare-function dired-mark "dired")
229 (when (bound-and-true-p hydra-examples-verbatim)
230 (require 'dired)
231 (defhydra hydra-marked-items (dired-mode-map "")
232 "
233 Number of marked items: %(length (dired-get-marked-files))
234 "
235 ("m" dired-mark "mark")))
236
237 ;; This results in the following dynamic docstring:
238 ;;
239 ;; (format "Number of marked items: %S\n"
240 ;; (length (dired-get-marked-files)))
241 ;;
242 ;; You can use `format'-style width specs, e.g. % 10(length nil).
243
244 ;;** Example 10: apropos family
245 (defhydra hydra-apropos (:color blue
246 :hint nil)
247 "
248 _a_propos _c_ommand
249 _d_ocumentation _l_ibrary
250 _v_ariable _u_ser-option
251 ^ ^ valu_e_"
252 ("a" apropos)
253 ("d" apropos-documentation)
254 ("v" apropos-variable)
255 ("c" apropos-command)
256 ("l" apropos-library)
257 ("u" apropos-user-option)
258 ("e" apropos-value))
259 ;; Recommended binding:
260 ;; (global-set-key (kbd "C-c h") 'hydra-apropos/body)
261
262 ;;** Example 11: rectangle-mark-mode
263 (require 'rect)
264 (defhydra hydra-rectangle (:body-pre (rectangle-mark-mode 1)
265 :color pink
266 :post (deactivate-mark))
267 "
268 ^_k_^ _d_elete _s_tring
269 _h_ _l_ _o_k _y_ank
270 ^_j_^ _n_ew-copy _r_eset
271 ^^^^ _e_xchange _u_ndo
272 ^^^^ ^ ^ _p_aste
273 "
274 ("h" rectangle-backward-char nil)
275 ("l" rectangle-forward-char nil)
276 ("k" rectangle-previous-line nil)
277 ("j" rectangle-next-line nil)
278 ("e" hydra-ex-point-mark nil)
279 ("n" copy-rectangle-as-kill nil)
280 ("d" delete-rectangle nil)
281 ("r" (if (region-active-p)
282 (deactivate-mark)
283 (rectangle-mark-mode 1)) nil)
284 ("y" yank-rectangle nil)
285 ("u" undo nil)
286 ("s" string-rectangle nil)
287 ("p" kill-rectangle nil)
288 ("o" nil nil))
289
290 ;; Recommended binding:
291 ;; (global-set-key (kbd "C-x SPC") 'hydra-rectangle/body)
292
293 ;;* Helpers
294 (require 'windmove)
295
296 (defun hydra-move-splitter-left (arg)
297 "Move window splitter left."
298 (interactive "p")
299 (if (let ((windmove-wrap-around))
300 (windmove-find-other-window 'right))
301 (shrink-window-horizontally arg)
302 (enlarge-window-horizontally arg)))
303
304 (defun hydra-move-splitter-right (arg)
305 "Move window splitter right."
306 (interactive "p")
307 (if (let ((windmove-wrap-around))
308 (windmove-find-other-window 'right))
309 (enlarge-window-horizontally arg)
310 (shrink-window-horizontally arg)))
311
312 (defun hydra-move-splitter-up (arg)
313 "Move window splitter up."
314 (interactive "p")
315 (if (let ((windmove-wrap-around))
316 (windmove-find-other-window 'up))
317 (enlarge-window arg)
318 (shrink-window arg)))
319
320 (defun hydra-move-splitter-down (arg)
321 "Move window splitter down."
322 (interactive "p")
323 (if (let ((windmove-wrap-around))
324 (windmove-find-other-window 'up))
325 (shrink-window arg)
326 (enlarge-window arg)))
327
328 (defvar rectangle-mark-mode)
329 (defun hydra-ex-point-mark ()
330 "Exchange point and mark."
331 (interactive)
332 (if rectangle-mark-mode
333 (rectangle-exchange-point-and-mark)
334 (let ((mk (mark)))
335 (rectangle-mark-mode 1)
336 (goto-char mk))))
337
338 (provide 'hydra-examples)
339 ;;; hydra-examples.el ends here