]> code.delx.au - gnu-emacs-elpa/blob - packages/hydra/hydra.el
Merge commit 'e0454a100541ce3f1f732b97894a3441cef3316f' from hydra
[gnu-emacs-elpa] / packages / hydra / hydra.el
1 ;;; hydra.el --- Make bindings that stick around. -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2015 Free Software Foundation, Inc.
4
5 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
6 ;; Maintainer: Oleh Krehel <ohwoeowho@gmail.com>
7 ;; URL: https://github.com/abo-abo/hydra
8 ;; Version: 0.13.5
9 ;; Keywords: bindings
10 ;; Package-Requires: ((cl-lib "0.5"))
11
12 ;; This file is part of GNU Emacs.
13
14 ;; GNU Emacs is free software: you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation, either version 3 of the License, or
17 ;; (at your option) any later version.
18
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
23
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26
27 ;;; Commentary:
28 ;;
29 ;; This package can be used to tie related commands into a family of
30 ;; short bindings with a common prefix - a Hydra.
31 ;;
32 ;; Once you summon the Hydra (through the prefixed binding), all the
33 ;; heads can be called in succession with only a short extension.
34 ;; The Hydra is vanquished once Hercules, any binding that isn't the
35 ;; Hydra's head, arrives. Note that Hercules, besides vanquishing the
36 ;; Hydra, will still serve his orignal purpose, calling his proper
37 ;; command. This makes the Hydra very seamless, it's like a minor
38 ;; mode that disables itself automagically.
39 ;;
40 ;; Here's an example Hydra, bound in the global map (you can use any
41 ;; keymap in place of `global-map'):
42 ;;
43 ;; (defhydra hydra-zoom (global-map "<f2>")
44 ;; "zoom"
45 ;; ("g" text-scale-increase "in")
46 ;; ("l" text-scale-decrease "out"))
47 ;;
48 ;; It allows to start a command chain either like this:
49 ;; "<f2> gg4ll5g", or "<f2> lgllg".
50 ;;
51 ;; Here's another approach, when you just want a "callable keymap":
52 ;;
53 ;; (defhydra hydra-toggle (:color blue)
54 ;; "toggle"
55 ;; ("a" abbrev-mode "abbrev")
56 ;; ("d" toggle-debug-on-error "debug")
57 ;; ("f" auto-fill-mode "fill")
58 ;; ("t" toggle-truncate-lines "truncate")
59 ;; ("w" whitespace-mode "whitespace")
60 ;; ("q" nil "cancel"))
61 ;;
62 ;; This binds nothing so far, but if you follow up with:
63 ;;
64 ;; (global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
65 ;;
66 ;; you will have bound "C-c C-v a", "C-c C-v d" etc.
67 ;;
68 ;; Knowing that `defhydra' defines e.g. `hydra-toggle/body' command,
69 ;; you can nest Hydras if you wish, with `hydra-toggle/body' possibly
70 ;; becoming a blue head of another Hydra.
71 ;;
72 ;; Initially, Hydra shipped with a simplified `hydra-create' macro, to
73 ;; which you could hook up the examples from hydra-examples.el. It's
74 ;; better to take the examples simply as templates and use `defhydra'
75 ;; instead of `hydra-create', since it's more flexible.
76
77 ;;; Code:
78 ;;* Requires
79 (require 'cl-lib)
80 (require 'lv)
81
82 (defvar hydra-curr-map nil
83 "The keymap of the current Hydra called.")
84
85 (defvar hydra-curr-on-exit nil
86 "The on-exit predicate for the current Hydra.")
87
88 (defvar hydra-curr-foreign-keys nil
89 "The current :foreign-keys behavior.")
90
91 (defvar hydra-curr-body-fn nil
92 "The current hydra-.../body function.")
93
94 (defvar hydra-deactivate nil
95 "If a Hydra head sets this to t, exit the Hydra.
96 This will be done even if the head wasn't designated for exiting.")
97
98 (defun hydra-set-transient-map (keymap on-exit &optional foreign-keys)
99 "Set KEYMAP to the highest priority.
100
101 Call ON-EXIT when the KEYMAP is deactivated.
102
103 FOREIGN-KEYS determines the deactivation behavior, when a command
104 that isn't in KEYMAP is called:
105
106 nil: deactivate KEYMAP and run the command.
107 run: keep KEYMAP and run the command.
108 warn: keep KEYMAP and issue a warning instead of running the command."
109 (if hydra-deactivate
110 (hydra-keyboard-quit)
111 (setq hydra-curr-map keymap)
112 (setq hydra-curr-on-exit on-exit)
113 (setq hydra-curr-foreign-keys foreign-keys)
114 (add-hook 'pre-command-hook 'hydra--clearfun)
115 (internal-push-keymap keymap 'overriding-terminal-local-map)))
116
117 (defun hydra--clearfun ()
118 "Disable the current Hydra unless `this-command' is a head."
119 (unless (eq this-command 'hydra-pause-resume)
120 (when (or
121 (memq this-command '(handle-switch-frame
122 keyboard-quit))
123 (null overriding-terminal-local-map)
124 (not (or (eq this-command
125 (lookup-key hydra-curr-map (this-single-command-keys)))
126 (cl-case hydra-curr-foreign-keys
127 (warn
128 (setq this-command 'hydra-amaranth-warn))
129 (run
130 t)
131 (t nil)))))
132 (hydra-disable))))
133
134 (defvar hydra--ignore nil
135 "When non-nil, don't call `hydra-curr-on-exit'.")
136
137 (defvar hydra--input-method-function nil
138 "Store overridden `input-method-function' here.")
139
140 (defun hydra-disable ()
141 "Disable the current Hydra."
142 (setq hydra-deactivate nil)
143 (remove-hook 'pre-command-hook 'hydra--clearfun)
144 (unless hydra--ignore
145 (if (fboundp 'remove-function)
146 (remove-function input-method-function #'hydra--imf)
147 (when hydra--input-method-function
148 (setq input-method-function hydra--input-method-function)
149 (setq hydra--input-method-function nil))))
150 (dolist (frame (frame-list))
151 (with-selected-frame frame
152 (when overriding-terminal-local-map
153 (internal-pop-keymap hydra-curr-map 'overriding-terminal-local-map))))
154 (unless hydra--ignore
155 (when hydra-curr-on-exit
156 (let ((on-exit hydra-curr-on-exit))
157 (setq hydra-curr-on-exit nil)
158 (funcall on-exit)))))
159
160 (unless (fboundp 'internal-push-keymap)
161 (defun internal-push-keymap (keymap symbol)
162 (let ((map (symbol-value symbol)))
163 (unless (memq keymap map)
164 (unless (memq 'add-keymap-witness (symbol-value symbol))
165 (setq map (make-composed-keymap nil (symbol-value symbol)))
166 (push 'add-keymap-witness (cdr map))
167 (set symbol map))
168 (push keymap (cdr map))))))
169
170 (unless (fboundp 'internal-pop-keymap)
171 (defun internal-pop-keymap (keymap symbol)
172 (let ((map (symbol-value symbol)))
173 (when (memq keymap map)
174 (setf (cdr map) (delq keymap (cdr map))))
175 (let ((tail (cddr map)))
176 (and (or (null tail) (keymapp tail))
177 (eq 'add-keymap-witness (nth 1 map))
178 (set symbol tail))))))
179
180 (defun hydra-amaranth-warn ()
181 "Issue a warning that the current input was ignored."
182 (interactive)
183 (message "An amaranth Hydra can only exit through a blue head"))
184
185 ;;* Customize
186 (defgroup hydra nil
187 "Make bindings that stick around."
188 :group 'bindings
189 :prefix "hydra-")
190
191 (defcustom hydra-is-helpful t
192 "When t, display a hint with possible bindings in the echo area."
193 :type 'boolean
194 :group 'hydra)
195
196 (defcustom hydra-lv t
197 "When non-nil, `lv-message' (not `message') will be used to display hints."
198 :type 'boolean)
199
200 (defcustom hydra-verbose nil
201 "When non-nil, hydra will issue some non essential style warnings."
202 :type 'boolean)
203
204 (defcustom hydra-key-format-spec "%s"
205 "Default `format'-style specifier for _a_ syntax in docstrings.
206 When nil, you can specify your own at each location like this: _ 5a_.")
207
208 (make-obsolete-variable
209 'hydra-key-format-spec
210 "Since the docstrings are aligned by hand anyway, this isn't very useful."
211 "0.13.1")
212
213 (defface hydra-face-red
214 '((t (:foreground "#FF0000" :bold t)))
215 "Red Hydra heads don't exit the Hydra.
216 Every other command exits the Hydra."
217 :group 'hydra)
218
219 (defface hydra-face-blue
220 '((((class color) (background light))
221 :foreground "#0000FF" :bold t)
222 (((class color) (background dark))
223 :foreground "#8ac6f2" :bold t))
224 "Blue Hydra heads exit the Hydra.
225 Every other command exits as well.")
226
227 (defface hydra-face-amaranth
228 '((t (:foreground "#E52B50" :bold t)))
229 "Amaranth body has red heads and warns on intercepting non-heads.
230 Exitable only through a blue head.")
231
232 (defface hydra-face-pink
233 '((t (:foreground "#FF6EB4" :bold t)))
234 "Pink body has red heads and runs intercepted non-heads.
235 Exitable only through a blue head.")
236
237 (defface hydra-face-teal
238 '((t (:foreground "#367588" :bold t)))
239 "Teal body has blue heads and warns on intercepting non-heads.
240 Exitable only through a blue head.")
241
242 ;;* Fontification
243 (defun hydra-add-font-lock ()
244 "Fontify `defhydra' statements."
245 (font-lock-add-keywords
246 'emacs-lisp-mode
247 '(("(\\(defhydra\\)\\_> +\\(.*?\\)\\_>"
248 (1 font-lock-keyword-face)
249 (2 font-lock-type-face))
250 ("(\\(defhydradio\\)\\_> +\\(.*?\\)\\_>"
251 (1 font-lock-keyword-face)
252 (2 font-lock-type-face)))))
253
254 ;;* Find Function
255 (eval-after-load 'find-func
256 '(defadvice find-function-search-for-symbol
257 (around hydra-around-find-function-search-for-symbol-advice
258 (symbol type library) activate)
259 "Navigate to hydras with `find-function-search-for-symbol'."
260 ad-do-it
261 ;; The orignial function returns (cons (current-buffer) (point))
262 ;; if it found the point.
263 (unless (cdr ad-return-value)
264 (with-current-buffer (find-file-noselect library)
265 (let ((sn (symbol-name symbol)))
266 (when (and (null type)
267 (string-match "\\`\\(hydra-[a-z-A-Z0-9]+\\)/\\(.*\\)\\'" sn)
268 (re-search-forward (concat "(defhydra " (match-string 1 sn))
269 nil t))
270 (goto-char (match-beginning 0)))
271 (cons (current-buffer) (point)))))))
272
273 ;;* Universal Argument
274 (defvar hydra-base-map
275 (let ((map (make-sparse-keymap)))
276 (define-key map [?\C-u] 'hydra--universal-argument)
277 (define-key map [?-] 'hydra--negative-argument)
278 (define-key map [?0] 'hydra--digit-argument)
279 (define-key map [?1] 'hydra--digit-argument)
280 (define-key map [?2] 'hydra--digit-argument)
281 (define-key map [?3] 'hydra--digit-argument)
282 (define-key map [?4] 'hydra--digit-argument)
283 (define-key map [?5] 'hydra--digit-argument)
284 (define-key map [?6] 'hydra--digit-argument)
285 (define-key map [?7] 'hydra--digit-argument)
286 (define-key map [?8] 'hydra--digit-argument)
287 (define-key map [?9] 'hydra--digit-argument)
288 (define-key map [kp-0] 'hydra--digit-argument)
289 (define-key map [kp-1] 'hydra--digit-argument)
290 (define-key map [kp-2] 'hydra--digit-argument)
291 (define-key map [kp-3] 'hydra--digit-argument)
292 (define-key map [kp-4] 'hydra--digit-argument)
293 (define-key map [kp-5] 'hydra--digit-argument)
294 (define-key map [kp-6] 'hydra--digit-argument)
295 (define-key map [kp-7] 'hydra--digit-argument)
296 (define-key map [kp-8] 'hydra--digit-argument)
297 (define-key map [kp-9] 'hydra--digit-argument)
298 (define-key map [kp-subtract] 'hydra--negative-argument)
299 map)
300 "Keymap that all Hydras inherit. See `universal-argument-map'.")
301
302 (defun hydra--universal-argument (arg)
303 "Forward to (`universal-argument' ARG)."
304 (interactive "P")
305 (setq prefix-arg (if (consp arg)
306 (list (* 4 (car arg)))
307 (if (eq arg '-)
308 (list -4)
309 '(4)))))
310
311 (defun hydra--digit-argument (arg)
312 "Forward to (`digit-argument' ARG)."
313 (interactive "P")
314 (let* ((char (if (integerp last-command-event)
315 last-command-event
316 (get last-command-event 'ascii-character)))
317 (digit (- (logand char ?\177) ?0)))
318 (setq prefix-arg (cond ((integerp arg)
319 (+ (* arg 10)
320 (if (< arg 0)
321 (- digit)
322 digit)))
323 ((eq arg '-)
324 (if (zerop digit)
325 '-
326 (- digit)))
327 (t
328 digit)))))
329
330 (defun hydra--negative-argument (arg)
331 "Forward to (`negative-argument' ARG)."
332 (interactive "P")
333 (setq prefix-arg (cond ((integerp arg) (- arg))
334 ((eq arg '-) nil)
335 (t '-))))
336
337 ;;* Repeat
338 (defvar hydra-repeat--prefix-arg nil
339 "Prefix arg to use with `hydra-repeat'.")
340
341 (defvar hydra-repeat--command nil
342 "Command to use with `hydra-repeat'.")
343
344 (defun hydra-repeat (&optional arg)
345 "Repeat last command with last prefix arg.
346 When ARG is non-nil, use that instead."
347 (interactive "p")
348 (if (eq arg 1)
349 (unless (string-match "hydra-repeat$" (symbol-name last-command))
350 (setq hydra-repeat--command last-command)
351 (setq hydra-repeat--prefix-arg last-prefix-arg))
352 (setq hydra-repeat--prefix-arg arg))
353 (setq current-prefix-arg hydra-repeat--prefix-arg)
354 (funcall hydra-repeat--command))
355
356 ;;* Misc internals
357 (defun hydra--callablep (x)
358 "Test if X is callable."
359 (or (functionp x)
360 (and (consp x)
361 (memq (car x) '(function quote)))))
362
363 (defun hydra--make-callable (x)
364 "Generate a callable symbol from X.
365 If X is a function symbol or a lambda, return it. Otherwise, it
366 should be a single statement. Wrap it in an interactive lambda."
367 (cond ((or (symbolp x) (functionp x))
368 x)
369 ((and (consp x) (eq (car x) 'function))
370 (cadr x))
371 (t
372 `(lambda ()
373 (interactive)
374 ,x))))
375
376 (defun hydra-plist-get-default (plist prop default)
377 "Extract a value from a property list.
378 PLIST is a property list, which is a list of the form
379 \(PROP1 VALUE1 PROP2 VALUE2...).
380
381 Return the value corresponding to PROP, or DEFAULT if PROP is not
382 one of the properties on the list."
383 (if (memq prop plist)
384 (plist-get plist prop)
385 default))
386
387 (defun hydra--head-property (h prop &optional default)
388 "Return for Hydra head H the value of property PROP.
389 Return DEFAULT if PROP is not in H."
390 (hydra-plist-get-default (cl-cdddr h) prop default))
391
392 (defun hydra--body-foreign-keys (body)
393 "Return what BODY does with a non-head binding."
394 (or
395 (plist-get (cddr body) :foreign-keys)
396 (let ((color (plist-get (cddr body) :color)))
397 (cl-case color
398 ((amaranth teal) 'warn)
399 (pink 'run)))))
400
401 (defun hydra--body-exit (body)
402 "Return the exit behavior of BODY."
403 (or
404 (plist-get (cddr body) :exit)
405 (let ((color (plist-get (cddr body) :color)))
406 (cl-case color
407 ((blue teal) t)
408 (t nil)))))
409
410 (defalias 'hydra--imf #'list)
411
412 (defun hydra-default-pre ()
413 "Default setup that happens in each head before :pre."
414 (when (eq input-method-function 'key-chord-input-method)
415 (if (fboundp 'add-function)
416 (add-function :override input-method-function #'hydra--imf)
417 (unless hydra--input-method-function
418 (setq hydra--input-method-function input-method-function)
419 (setq input-method-function nil)))))
420
421 (defvar hydra-timeout-timer (timer-create)
422 "Timer for `hydra-timeout'.")
423
424 (defvar hydra-message-timer (timer-create)
425 "Timer for the hint.")
426
427 (defvar hydra--work-around-dedicated t
428 "When non-nil, assume there's no bug in `pop-to-buffer'.
429 `pop-to-buffer' should not select a dedicated window.")
430
431 (defun hydra-keyboard-quit ()
432 "Quitting function similar to `keyboard-quit'."
433 (interactive)
434 (hydra-disable)
435 (cancel-timer hydra-timeout-timer)
436 (cancel-timer hydra-message-timer)
437 (setq hydra-curr-map nil)
438 (unless (and hydra--ignore
439 (null hydra--work-around-dedicated))
440 (if hydra-lv
441 (lv-delete-window)
442 (message "")))
443 nil)
444
445 (defvar hydra-head-format "[%s]: "
446 "The formatter for each head of a plain docstring.")
447
448 (defvar hydra-key-doc-function 'hydra-key-doc-function-default
449 "The function for formatting key-doc pairs.")
450
451 (defun hydra-key-doc-function-default (key key-width doc doc-width)
452 "Doc"
453 (format (format "%%%ds: %%%ds" key-width (- -1 doc-width))
454 key doc))
455
456 (defun hydra--to-string (x)
457 (if (stringp x)
458 x
459 (eval x)))
460
461 (defun hydra--hint (body heads)
462 "Generate a hint for the echo area.
463 BODY, and HEADS are parameters to `defhydra'."
464 (let (alist)
465 (dolist (h heads)
466 (let ((val (assoc (cadr h) alist))
467 (pstr (hydra-fontify-head h body)))
468 (unless (null (cl-caddr h))
469 (if val
470 (setf (cadr val)
471 (concat (cadr val) " " pstr))
472 (push
473 (cons (cadr h)
474 (cons pstr (cl-caddr h)))
475 alist)))))
476 (let ((keys (nreverse (mapcar #'cdr alist)))
477 (n-cols (plist-get (cddr body) :columns))
478 res)
479 (setq res
480 (if n-cols
481 (let ((n-rows (1+ (/ (length keys) n-cols)))
482 (max-key-len (apply #'max (mapcar (lambda (x) (length (car x))) keys)))
483 (max-doc-len (apply #'max (mapcar (lambda (x)
484 (length (hydra--to-string (cdr x)))) keys))))
485 `(concat
486 "\n"
487 (mapconcat #'identity
488 (mapcar
489 (lambda (x)
490 (mapconcat
491 (lambda (y)
492 (and y
493 (funcall hydra-key-doc-function
494 (car y)
495 ,max-key-len
496 (hydra--to-string (cdr y))
497 ,max-doc-len))) x ""))
498 ',(hydra--matrix keys n-cols n-rows))
499 "\n")))
500
501
502 `(concat
503 (mapconcat
504 (lambda (x)
505 (let ((str (hydra--to-string (cdr x))))
506 (format
507 (if (> (length str) 0)
508 (concat hydra-head-format str)
509 "%s")
510 (car x))))
511 ',keys
512 ", ")
513 ,(if keys "." ""))))
514 (if (cl-every #'stringp
515 (mapcar 'cddr alist))
516 (eval res)
517 res))))
518
519 (defvar hydra-fontify-head-function nil
520 "Possible replacement for `hydra-fontify-head-default'.")
521
522 (defun hydra-fontify-head-default (head body)
523 "Produce a pretty string from HEAD and BODY.
524 HEAD's binding is returned as a string with a colored face."
525 (let* ((foreign-keys (hydra--body-foreign-keys body))
526 (head-exit (hydra--head-property head :exit))
527 (head-color
528 (if head-exit
529 (if (eq foreign-keys 'warn)
530 'teal
531 'blue)
532 (cl-case foreign-keys
533 (warn 'amaranth)
534 (run 'pink)
535 (t 'red)))))
536 (when (and (null (cadr head))
537 (not head-exit))
538 (hydra--complain "nil cmd can only be blue"))
539 (propertize (if (string= (car head) "%")
540 "%%"
541 (car head))
542 'face
543 (or (hydra--head-property head :face)
544 (cl-case head-color
545 (blue 'hydra-face-blue)
546 (red 'hydra-face-red)
547 (amaranth 'hydra-face-amaranth)
548 (pink 'hydra-face-pink)
549 (teal 'hydra-face-teal)
550 (t (error "Unknown color for %S" head)))))))
551
552 (defun hydra-fontify-head-greyscale (head _body)
553 "Produce a pretty string from HEAD and BODY.
554 HEAD's binding is returned as a string wrapped with [] or {}."
555 (format
556 (if (hydra--head-property head :exit)
557 "[%s]"
558 "{%s}") (car head)))
559
560 (defun hydra-fontify-head (head body)
561 "Produce a pretty string from HEAD and BODY."
562 (funcall (or hydra-fontify-head-function 'hydra-fontify-head-default)
563 head body))
564
565 (defun hydra--strip-align-markers (str)
566 "Remove ^ from STR, unless they're escaped: \\^."
567 (let ((start 0))
568 (while (setq start (string-match "\\\\?\\^" str start))
569 (if (eq (- (match-end 0) (match-beginning 0)) 2)
570 (progn
571 (setq str (replace-match "^" nil nil str))
572 (cl-incf start))
573 (setq str (replace-match "" nil nil str))))
574 str))
575
576 (defun hydra--format (_name body docstring heads)
577 "Generate a `format' statement from STR.
578 \"%`...\" expressions are extracted into \"%S\".
579 _NAME, BODY, DOCSTRING and HEADS are parameters of `defhydra'.
580 The expressions can be auto-expanded according to NAME."
581 (setq docstring (hydra--strip-align-markers docstring))
582 (setq docstring (replace-regexp-in-string "___" "_β_" docstring))
583 (let ((rest (hydra--hint body heads))
584 (start 0)
585 varlist
586 offset)
587 (while (setq start
588 (string-match
589 "\\(?:%\\( ?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_\\( ?-?[0-9]*?\\)\\(\\[\\|]\\|[-[:alnum:] ~.,;:/|?<>={}*+#%@!&^]+?\\)_\\)"
590 docstring start))
591 (cond ((eq ?_ (aref (match-string 0 docstring) 0))
592 (let* ((key (match-string 4 docstring))
593 (key (if (equal key "β") "_" key))
594 (head (assoc key heads)))
595 (if head
596 (progn
597 (push (hydra-fontify-head head body) varlist)
598 (setq docstring
599 (replace-match
600 (or
601 hydra-key-format-spec
602 (concat "%" (match-string 3 docstring) "s"))
603 t nil docstring)))
604 (warn "Unrecognized key: _%s_" key))))
605
606 (t
607 (let* ((varp (if (eq ?` (aref (match-string 2 docstring) 0)) 1 0))
608 (spec (match-string 1 docstring))
609 (lspec (length spec)))
610 (setq offset
611 (with-temp-buffer
612 (insert (substring docstring (+ 1 start varp
613 (length spec))))
614 (goto-char (point-min))
615 (push (read (current-buffer)) varlist)
616 (- (point) (point-min))))
617 (when (or (zerop lspec)
618 (/= (aref spec (1- (length spec))) ?s))
619 (setq spec (concat spec "S")))
620 (setq docstring
621 (concat
622 (substring docstring 0 start)
623 "%" spec
624 (substring docstring (+ start offset 1 lspec varp))))))))
625 (if (eq ?\n (aref docstring 0))
626 `(concat (format ,(substring docstring 1) ,@(nreverse varlist))
627 ,rest)
628 (let ((r `(replace-regexp-in-string
629 " +$" ""
630 (concat ,docstring ": "
631 (replace-regexp-in-string
632 "\\(%\\)" "\\1\\1" ,rest)))))
633 (if (stringp rest)
634 `(format ,(eval r))
635 `(format ,r))))))
636
637 (defun hydra--complain (format-string &rest args)
638 "Forward to (`message' FORMAT-STRING ARGS) unless `hydra-verbose' is nil."
639 (if hydra-verbose
640 (apply #'error format-string args)
641 (apply #'message format-string args)))
642
643 (defun hydra--doc (body-key body-name heads)
644 "Generate a part of Hydra docstring.
645 BODY-KEY is the body key binding.
646 BODY-NAME is the symbol that identifies the Hydra.
647 HEADS is a list of heads."
648 (format
649 "Create a hydra with %s body and the heads:\n\n%s\n\n%s"
650 (if body-key
651 (format "a \"%s\"" body-key)
652 "no")
653 (mapconcat
654 (lambda (x)
655 (format "\"%s\": `%S'" (car x) (cadr x)))
656 heads ",\n")
657 (format "The body can be accessed via `%S'." body-name)))
658
659 (defun hydra--call-interactively (cmd name)
660 "Generate a `call-interactively' statement for CMD.
661 Set `this-command' to NAME."
662 (if (and (symbolp name)
663 (not (memq name '(nil body))))
664 `(progn
665 (setq this-command ',name)
666 (call-interactively #',cmd))
667 `(call-interactively #',cmd)))
668
669 (defun hydra--make-defun (name body doc head
670 keymap body-pre body-before-exit
671 &optional body-after-exit)
672 "Make a defun wrapper, using NAME, BODY, DOC, HEAD, and KEYMAP.
673 NAME and BODY are the arguments to `defhydra'.
674 DOC was generated with `hydra--doc'.
675 HEAD is one of the HEADS passed to `defhydra'.
676 BODY-PRE is added to the start of the wrapper.
677 BODY-BEFORE-EXIT will be called before the hydra quits.
678 BODY-AFTER-EXIT is added to the end of the wrapper."
679 (let ((cmd-name (hydra--head-name head name))
680 (cmd (when (car head)
681 (hydra--make-callable
682 (cadr head))))
683 (doc (if (car head)
684 (format "%s\n\nCall the head: `%S'." doc (cadr head))
685 doc))
686 (hint (intern (format "%S/hint" name)))
687 (body-foreign-keys (hydra--body-foreign-keys body))
688 (body-timeout (plist-get body :timeout))
689 (body-idle (plist-get body :idle)))
690 `(defun ,cmd-name ()
691 ,doc
692 (interactive)
693 (hydra-default-pre)
694 ,@(when body-pre (list body-pre))
695 ,@(if (hydra--head-property head :exit)
696 `((hydra-keyboard-quit)
697 (setq hydra-curr-body-fn ',(intern (format "%S/body" name)))
698 ,@(if body-after-exit
699 `((unwind-protect
700 ,(when cmd
701 (hydra--call-interactively cmd (cadr head)))
702 ,body-after-exit))
703 (when cmd
704 `(,(hydra--call-interactively cmd (cadr head))))))
705 (delq
706 nil
707 `((let ((hydra--ignore ,(not (eq (cadr head) 'body))))
708 (hydra-keyboard-quit)
709 (setq hydra-curr-body-fn ',(intern (format "%S/body" name))))
710 ,(when cmd
711 `(condition-case err
712 ,(hydra--call-interactively cmd (cadr head))
713 ((quit error)
714 (message "%S" err)
715 (unless hydra-lv
716 (sit-for 0.8)))))
717 ,(if (and body-idle (eq (cadr head) 'body))
718 `(hydra-idle-message ,body-idle ,hint)
719 `(when hydra-is-helpful
720 (if hydra-lv
721 (lv-message (eval ,hint))
722 (message (eval ,hint)))))
723 (hydra-set-transient-map
724 ,keymap
725 (lambda () (hydra-keyboard-quit) ,body-before-exit)
726 ,(when body-foreign-keys
727 (list 'quote body-foreign-keys)))
728 ,body-after-exit
729 ,(when body-timeout
730 `(hydra-timeout ,body-timeout))))))))
731
732 (defmacro hydra--make-funcall (sym)
733 "Transform SYM into a `funcall' to call it."
734 `(when (and ,sym (symbolp ,sym))
735 (setq ,sym `(funcall #',,sym))))
736
737 (defun hydra--head-name (h name)
738 "Return the symbol for head H of hydra with NAME."
739 (let ((str (format "%S/%s" name
740 (cond ((symbolp (cadr h))
741 (cadr h))
742 ((and (consp (cadr h))
743 (eq (cl-caadr h) 'function))
744 (cadr (cadr h)))
745 (t
746 (concat "lambda-" (car h)))))))
747 (when (and (hydra--head-property h :exit)
748 (not (memq (cadr h) '(body nil))))
749 (setq str (concat str "-and-exit")))
750 (intern str)))
751
752 (defun hydra--delete-duplicates (heads)
753 "Return HEADS without entries that have the same CMD part.
754 In duplicate HEADS, :cmd-name is modified to whatever they duplicate."
755 (let ((ali '(((hydra-repeat . nil) . hydra-repeat)))
756 res entry)
757 (dolist (h heads)
758 (if (setq entry (assoc (cons (cadr h)
759 (hydra--head-property h :exit))
760 ali))
761 (setf (cl-cdddr h) (plist-put (cl-cdddr h) :cmd-name (cdr entry)))
762 (push (cons (cons (cadr h)
763 (hydra--head-property h :exit))
764 (plist-get (cl-cdddr h) :cmd-name))
765 ali)
766 (push h res)))
767 (nreverse res)))
768
769 (defun hydra--pad (lst n)
770 "Pad LST with nil until length N."
771 (let ((len (length lst)))
772 (if (= len n)
773 lst
774 (append lst (make-list (- n len) nil)))))
775
776 (defmacro hydra-multipop (lst n)
777 "Return LST's first N elements while removing them."
778 `(if (<= (length ,lst) ,n)
779 (prog1 ,lst
780 (setq ,lst nil))
781 (prog1 ,lst
782 (setcdr
783 (nthcdr (1- ,n) (prog1 ,lst (setq ,lst (nthcdr ,n ,lst))))
784 nil))))
785
786 (defun hydra--matrix (lst rows cols)
787 "Create a matrix from elements of LST.
788 The matrix size is ROWS times COLS."
789 (let ((ls (copy-sequence lst))
790 res)
791 (dotimes (_c cols)
792 (push (hydra--pad (hydra-multipop ls rows) rows) res))
793 (nreverse res)))
794
795 (defun hydra--cell (fstr names)
796 "Format a rectangular cell based on FSTR and NAMES.
797 FSTR is a format-style string with two string inputs: one for the
798 doc and one for the symbol name.
799 NAMES is a list of variables."
800 (let ((len (cl-reduce
801 (lambda (acc it) (max (length (symbol-name it)) acc))
802 names
803 :initial-value 0)))
804 (mapconcat
805 (lambda (sym)
806 (if sym
807 (format fstr
808 (documentation-property sym 'variable-documentation)
809 (let ((name (symbol-name sym)))
810 (concat name (make-string (- len (length name)) ?^)))
811 sym)
812 ""))
813 names
814 "\n")))
815
816 (defun hydra--vconcat (strs &optional joiner)
817 "Glue STRS vertically. They must be the same height.
818 JOINER is a function similar to `concat'."
819 (setq joiner (or joiner #'concat))
820 (mapconcat
821 (lambda (s)
822 (if (string-match " +$" s)
823 (replace-match "" nil nil s)
824 s))
825 (apply #'cl-mapcar joiner
826 (mapcar
827 (lambda (s) (split-string s "\n"))
828 strs))
829 "\n"))
830
831 (defvar hydra-cell-format "% -20s %% -8`%s"
832 "The default format for docstring cells.")
833
834 (defun hydra--table (names rows cols &optional cell-formats)
835 "Format a `format'-style table from variables in NAMES.
836 The size of the table is ROWS times COLS.
837 CELL-FORMATS are `format' strings for each column.
838 If CELL-FORMATS is a string, it's used for all columns.
839 If CELL-FORMATS is nil, `hydra-cell-format' is used for all columns."
840 (setq cell-formats
841 (cond ((null cell-formats)
842 (make-list cols hydra-cell-format))
843 ((stringp cell-formats)
844 (make-list cols cell-formats))
845 (t
846 cell-formats)))
847 (hydra--vconcat
848 (cl-mapcar
849 #'hydra--cell
850 cell-formats
851 (hydra--matrix names rows cols))
852 (lambda (&rest x)
853 (mapconcat #'identity x " "))))
854
855 (defun hydra-reset-radios (names)
856 "Set varibles NAMES to their defaults.
857 NAMES should be defined by `defhydradio' or similar."
858 (dolist (n names)
859 (set n (aref (get n 'range) 0))))
860
861 (defun hydra-idle-message (secs hint)
862 "In SECS seconds display HINT."
863 (cancel-timer hydra-message-timer)
864 (setq hydra-message-timer (timer-create))
865 (timer-set-time hydra-message-timer
866 (timer-relative-time (current-time) secs))
867 (timer-set-function
868 hydra-message-timer
869 (lambda ()
870 (when hydra-is-helpful
871 (if hydra-lv
872 (lv-message (eval hint))
873 (message (eval hint))))
874 (cancel-timer hydra-message-timer)))
875 (timer-activate hydra-message-timer))
876
877 (defun hydra-timeout (secs &optional function)
878 "In SECS seconds call FUNCTION, then function `hydra-keyboard-quit'.
879 Cancel the previous `hydra-timeout'."
880 (cancel-timer hydra-timeout-timer)
881 (setq hydra-timeout-timer (timer-create))
882 (timer-set-time hydra-timeout-timer
883 (timer-relative-time (current-time) secs))
884 (timer-set-function
885 hydra-timeout-timer
886 `(lambda ()
887 ,(when function
888 `(funcall ,function))
889 (hydra-keyboard-quit)))
890 (timer-activate hydra-timeout-timer))
891
892 ;;* Macros
893 ;;;###autoload
894 (defmacro defhydra (name body &optional docstring &rest heads)
895 "Create a Hydra - a family of functions with prefix NAME.
896
897 NAME should be a symbol, it will be the prefix of all functions
898 defined here.
899
900 BODY has the format:
901
902 (BODY-MAP BODY-KEY &rest BODY-PLIST)
903
904 DOCSTRING will be displayed in the echo area to identify the
905 Hydra. When DOCSTRING starts with a newline, special Ruby-style
906 substitution will be performed by `hydra--format'.
907
908 Functions are created on basis of HEADS, each of which has the
909 format:
910
911 (KEY CMD &optional HINT &rest PLIST)
912
913 BODY-MAP is a keymap; `global-map' is used quite often. Each
914 function generated from HEADS will be bound in BODY-MAP to
915 BODY-KEY + KEY (both are strings passed to `kbd'), and will set
916 the transient map so that all following heads can be called
917 though KEY only. BODY-KEY can be an empty string.
918
919 CMD is a callable expression: either an interactive function
920 name, or an interactive lambda, or a single sexp (it will be
921 wrapped in an interactive lambda).
922
923 HINT is a short string that identifies its head. It will be
924 printed beside KEY in the echo erea if `hydra-is-helpful' is not
925 nil. If you don't even want the KEY to be printed, set HINT
926 explicitly to nil.
927
928 The heads inherit their PLIST from BODY-PLIST and are allowed to
929 override some keys. The keys recognized are :exit and :bind.
930 :exit can be:
931
932 - nil (default): this head will continue the Hydra state.
933 - t: this head will stop the Hydra state.
934
935 :bind can be:
936 - nil: this head will not be bound in BODY-MAP.
937 - a lambda taking KEY and CMD used to bind a head.
938
939 It is possible to omit both BODY-MAP and BODY-KEY if you don't
940 want to bind anything. In that case, typically you will bind the
941 generated NAME/body command. This command is also the return
942 result of `defhydra'."
943 (declare (indent defun))
944 (cond ((stringp docstring))
945 ((and (consp docstring)
946 (memq (car docstring) '(hydra--table concat format)))
947 (setq docstring (concat "\n" (eval docstring))))
948 (t
949 (setq heads (cons docstring heads))
950 (setq docstring "hydra")))
951 (when (keywordp (car body))
952 (setq body (cons nil (cons nil body))))
953 (condition-case-unless-debug err
954 (let* ((keymap (copy-keymap hydra-base-map))
955 (keymap-name (intern (format "%S/keymap" name)))
956 (body-name (intern (format "%S/body" name)))
957 (body-key (cadr body))
958 (body-plist (cddr body))
959 (body-map (or (car body)
960 (plist-get body-plist :bind)))
961 (body-pre (plist-get body-plist :pre))
962 (body-body-pre (plist-get body-plist :body-pre))
963 (body-before-exit (or (plist-get body-plist :post)
964 (plist-get body-plist :before-exit)))
965 (body-after-exit (plist-get body-plist :after-exit))
966 (body-inherit (plist-get body-plist :inherit))
967 (body-foreign-keys (hydra--body-foreign-keys body))
968 (body-exit (hydra--body-exit body)))
969 (dolist (base body-inherit)
970 (setq heads (append heads (copy-sequence (eval base)))))
971 (dolist (h heads)
972 (let ((len (length h)))
973 (cond ((< len 2)
974 (error "Each head should have at least two items: %S" h))
975 ((= len 2)
976 (setcdr (cdr h)
977 (list
978 (hydra-plist-get-default body-plist :hint "")))
979 (setcdr (nthcdr 2 h) (list :exit body-exit)))
980 (t
981 (let ((hint (cl-caddr h)))
982 (unless (or (null hint)
983 (stringp hint)
984 (stringp (eval hint)))
985 (setcdr (cdr h) (cons
986 (hydra-plist-get-default body-plist :hint "")
987 (cddr h)))))
988 (let ((hint-and-plist (cddr h)))
989 (if (null (cdr hint-and-plist))
990 (setcdr hint-and-plist (list :exit body-exit))
991 (let* ((plist (cl-cdddr h))
992 (h-color (plist-get plist :color)))
993 (if h-color
994 (progn
995 (plist-put plist :exit
996 (cl-case h-color
997 ((blue teal) t)
998 (t nil)))
999 (cl-remf (cl-cdddr h) :color))
1000 (let ((h-exit (hydra-plist-get-default plist :exit 'default)))
1001 (plist-put plist :exit
1002 (if (eq h-exit 'default)
1003 body-exit
1004 h-exit))))))))))
1005 (plist-put (cl-cdddr h) :cmd-name (hydra--head-name h name))
1006 (when (null (cadr h)) (plist-put (cl-cdddr h) :exit t)))
1007 (let ((doc (hydra--doc body-key body-name heads))
1008 (heads-nodup (hydra--delete-duplicates heads)))
1009 (mapc
1010 (lambda (x)
1011 (define-key keymap (kbd (car x))
1012 (plist-get (cl-cdddr x) :cmd-name)))
1013 heads)
1014 (hydra--make-funcall body-pre)
1015 (hydra--make-funcall body-body-pre)
1016 (hydra--make-funcall body-before-exit)
1017 (hydra--make-funcall body-after-exit)
1018 (when (memq body-foreign-keys '(run warn))
1019 (unless (cl-some
1020 (lambda (h)
1021 (hydra--head-property h :exit))
1022 heads)
1023 (error
1024 "An %S Hydra must have at least one blue head in order to exit"
1025 body-foreign-keys)))
1026 `(progn
1027 ;; create keymap
1028 (set (defvar ,keymap-name
1029 nil
1030 ,(format "Keymap for %S." name))
1031 ',keymap)
1032 ;; declare heads
1033 (set (defvar ,(intern (format "%S/heads" name))
1034 nil
1035 ,(format "Heads for %S." name))
1036 ',(mapcar (lambda (h)
1037 (let ((j (copy-sequence h)))
1038 (cl-remf (cl-cdddr j) :cmd-name)
1039 j))
1040 heads))
1041 (set
1042 (defvar ,(intern (format "%S/hint" name)) nil
1043 ,(format "Dynamic hint for %S." name))
1044 ',(hydra--format name body docstring heads))
1045 ;; create defuns
1046 ,@(mapcar
1047 (lambda (head)
1048 (hydra--make-defun name body doc head keymap-name
1049 body-pre
1050 body-before-exit
1051 body-after-exit))
1052 heads-nodup)
1053 ;; free up keymap prefix
1054 ,@(unless (or (null body-key)
1055 (null body-map)
1056 (hydra--callablep body-map))
1057 `((unless (keymapp (lookup-key ,body-map (kbd ,body-key)))
1058 (define-key ,body-map (kbd ,body-key) nil))))
1059 ;; bind keys
1060 ,@(delq nil
1061 (mapcar
1062 (lambda (head)
1063 (let ((name (hydra--head-property head :cmd-name)))
1064 (when (and (cadr head)
1065 (or body-key body-map))
1066 (let ((bind (hydra--head-property head :bind body-map))
1067 (final-key
1068 (if body-key
1069 (vconcat (kbd body-key) (kbd (car head)))
1070 (kbd (car head)))))
1071 (cond ((null bind) nil)
1072 ((hydra--callablep bind)
1073 `(funcall ,bind ,final-key (function ,name)))
1074 ((and (symbolp bind)
1075 (if (boundp bind)
1076 (keymapp (symbol-value bind))
1077 t))
1078 `(define-key ,bind ,final-key (quote ,name)))
1079 (t
1080 (error "Invalid :bind property `%S' for head %S" bind head)))))))
1081 heads))
1082 ,(hydra--make-defun
1083 name body doc '(nil body)
1084 keymap-name
1085 (or body-body-pre body-pre) body-before-exit
1086 '(setq prefix-arg current-prefix-arg)))))
1087 (error
1088 (hydra--complain "Error in defhydra %S: %s" name (cdr err))
1089 nil)))
1090
1091 (defmacro defhydradio (name _body &rest heads)
1092 "Create radios with prefix NAME.
1093 _BODY specifies the options; there are none currently.
1094 HEADS have the format:
1095
1096 (TOGGLE-NAME &optional VALUE DOC)
1097
1098 TOGGLE-NAME will be used along with NAME to generate a variable
1099 name and a function that cycles it with the same name. VALUE
1100 should be an array. The first element of VALUE will be used to
1101 inialize the variable.
1102 VALUE defaults to [nil t].
1103 DOC defaults to TOGGLE-NAME split and capitalized."
1104 (declare (indent defun))
1105 `(progn
1106 ,@(apply #'append
1107 (mapcar (lambda (h)
1108 (hydra--radio name h))
1109 heads))
1110 (defvar ,(intern (format "%S/names" name))
1111 ',(mapcar (lambda (h) (intern (format "%S/%S" name (car h))))
1112 heads))))
1113
1114 (defun hydra--radio (parent head)
1115 "Generate a hydradio with PARENT from HEAD."
1116 (let* ((name (car head))
1117 (full-name (intern (format "%S/%S" parent name)))
1118 (doc (cadr head))
1119 (val (or (cl-caddr head) [nil t])))
1120 `((defvar ,full-name ,(hydra--quote-maybe (aref val 0)) ,doc)
1121 (put ',full-name 'range ,val)
1122 (defun ,full-name ()
1123 (hydra--cycle-radio ',full-name)))))
1124
1125 (defun hydra--quote-maybe (x)
1126 "Quote X if it's a symbol."
1127 (cond ((null x)
1128 nil)
1129 ((symbolp x)
1130 (list 'quote x))
1131 (t
1132 x)))
1133
1134 (defun hydra--cycle-radio (sym)
1135 "Set SYM to the next value in its range."
1136 (let* ((val (symbol-value sym))
1137 (range (get sym 'range))
1138 (i 0)
1139 (l (length range)))
1140 (setq i (catch 'done
1141 (while (< i l)
1142 (if (equal (aref range i) val)
1143 (throw 'done (1+ i))
1144 (cl-incf i)))
1145 (error "Val not in range for %S" sym)))
1146 (set sym
1147 (aref range
1148 (if (>= i l)
1149 0
1150 i)))))
1151
1152 (require 'ring)
1153
1154 (defvar hydra-pause-ring (make-ring 10)
1155 "Ring for paused hydras.")
1156
1157 (defun hydra-pause-resume ()
1158 "Quit the current hydra and save it to the stack.
1159 If there's no active hydra, pop one from the stack and call its body.
1160 If the stack is empty, call the last hydra's body."
1161 (interactive)
1162 (cond (hydra-curr-map
1163 (ring-insert hydra-pause-ring hydra-curr-body-fn)
1164 (hydra-keyboard-quit))
1165 ((zerop (ring-length hydra-pause-ring))
1166 (funcall hydra-curr-body-fn))
1167 (t
1168 (funcall (ring-remove hydra-pause-ring 0)))))
1169
1170 ;; Local Variables:
1171 ;; outline-regexp: ";;\\([;*]+ [^\s\t\n]\\|###autoload\\)\\|("
1172 ;; indent-tabs-mode: nil
1173 ;; End:
1174
1175 (provide 'hydra)
1176
1177 ;;; hydra.el ends here