Personal emacs config
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.

1536 lines
58 KiB

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