Allow head-hint to be dynamic

Instead of only a string like before, the head-hint can be anything that
evaluates to a string.

Example:

(defhydra hydra-test (:columns 2)
  "Test"
  ("j" next-line (format-time-string "%H:%M:%S" (current-time)))
  ("k" previous-line (format-time-string "%H:%M:%S" (current-time)))
  ("h" backward-char (format-time-string "%H:%M:%S" (current-time)))
  ("l" forward-char (format-time-string "%H:%M:%S" (current-time))))

Pressing "hjkl" will refresh the hint, and thus update the current time.
Note that the hint needs to evaluate to a string at both compile-time
and run-time. The column formatting depends on the compile-time result.

Fixes #160
master
Oleh Krehel 11 years ago
parent 0712176e9b
commit 9f5f089af4
  1. 92
      hydra.el

@ -452,6 +452,11 @@ Return DEFAULT if PROP is not in H."
(format (format "%%%ds: %%%ds" key-width (- -1 doc-width))
key doc))
(defun hydra--to-string (x)
(if (stringp x)
x
(eval x)))
(defun hydra--hint (body heads)
"Generate a hint for the echo area.
BODY, and HEADS are parameters to `defhydra'."
@ -467,41 +472,48 @@ BODY, and HEADS are parameters to `defhydra'."
(cons (cadr h)
(cons pstr (cl-caddr h)))
alist)))))
(let ((keys (nreverse (mapcar #'cdr alist)))
(n-cols (plist-get (cddr body) :columns)))
(if n-cols
(let ((n-rows (1+ (/ (length keys) n-cols)))
(max-key-len (apply #'max (mapcar (lambda (x) (length (car x))) keys)))
(max-doc-len (apply #'max (mapcar (lambda (x) (length (cdr x))) keys))))
(concat
"\n"
(mapconcat #'identity
(mapcar
(lambda (x)
(mapconcat
(lambda (y)
(and y
(funcall hydra-key-doc-function
(car y)
max-key-len
(cdr y)
max-doc-len))) x ""))
(hydra--matrix keys n-cols n-rows))
"\n")))
(concat
(mapconcat
(lambda (x)
(format
(if (> (length (cdr x)) 0)
(concat hydra-head-format (cdr x))
"%s")
(car x)))
keys
", ")
(if keys "." ""))))))
(n-cols (plist-get (cddr body) :columns))
res)
(setq res
(if n-cols
(let ((n-rows (1+ (/ (length keys) n-cols)))
(max-key-len (apply #'max (mapcar (lambda (x) (length (car x))) keys)))
(max-doc-len (apply #'max (mapcar (lambda (x)
(length (hydra--to-string (cdr x)))) keys))))
`(concat
"\n"
(mapconcat #'identity
(mapcar
(lambda (x)
(mapconcat
(lambda (y)
(and y
(funcall hydra-key-doc-function
(car y)
,max-key-len
(hydra--to-string (cdr y))
,max-doc-len))) x ""))
',(hydra--matrix keys n-cols n-rows))
"\n")))
`(concat
(mapconcat
(lambda (x)
(let ((str (hydra--to-string (cdr x))))
(format
(if (> (length str) 0)
(concat hydra-head-format str)
"%s")
(car x))))
',keys
", ")
,(if keys "." ""))))
(if (cl-every #'stringp
(mapcar 'cddr alist))
(eval res)
res))))
(defvar hydra-fontify-head-function nil
"Possible replacement for `hydra-fontify-head-default'.")
@ -612,11 +624,14 @@ The expressions can be auto-expanded according to NAME."
(if (eq ?\n (aref docstring 0))
`(concat (format ,(substring docstring 1) ,@(nreverse varlist))
,rest)
`(format ,(replace-regexp-in-string
(let ((r `(replace-regexp-in-string
" +$" ""
(concat docstring ": "
(concat ,docstring ": "
(replace-regexp-in-string
"\\(%\\)" "\\1\\1" rest)))))))
"\\(%\\)" "\\1\\1" ,rest)))))
(if (stringp rest)
`(format ,(eval r))
`(format ,r))))))
(defun hydra--complain (format-string &rest args)
"Forward to (`message' FORMAT-STRING ARGS) unless `hydra-verbose' is nil."
@ -964,7 +979,8 @@ result of `defhydra'."
(t
(let ((hint (cl-caddr h)))
(unless (or (null hint)
(stringp hint))
(stringp hint)
(stringp (eval hint)))
(setcdr (cdr h) (cons
(hydra-plist-get-default body-plist :hint "")
(cddr h)))))

Loading…
Cancel
Save