Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1547 lines
59 KiB

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