In contrast, hatty always renders a small symbol over one of the characters in each word. This makes it possible to refer to the word immediately, without the intermediate step of bringing up an interface.
This library was designed while attempting to make voice control of Emacs more fluent, where the two-step system of avy made it impossible to string together a sequence of actions in a single utterance. This method of indexing positions was inspired by the cursorless project, whose hat designs this project reuses.
This package is available on MELPA ashatty
.
Clone this repo and add the following to your configuration:
(add-to-list 'load-path "path/to/hatty/directory")
- Hat: The small symbol rendered above a glyph by hatty.
- Token: The region of the buffer indicated by the hat. In general, this corresponds to a word or a special character such as punctuation.
- Style: The appearance of a hat is decided by its color and shape. The combination of a color and shape is called a style.
(require 'hatty)
(global-hatty-mode 1)
This starts rendering hats in visited buffers. To get the token of a
hat, use hatty-locate-token
. For example,
(hatty-locate-token ?n 'yellow 'bolt)
will return the token that has a yellow bolt over the character “n”. The bounds or markers, ensuring stability of the positions across editing operations. See the Emacs lisp manual for more information on markers.
The available colors and shapes are specified by the variables
hatty-colors
and hatty-shapes
. The keys in these alists are the
symbols used to invoke hatty-locate
. The special identifier
default
denotes the color or shape to use whenever the argument is
nil or absent.
If you want to disable special shapes while getting used to hatty, see Disabling specific colors and shapes.
The following snippet will define three keyboard commands for jumping, copying, and inserting a token as indexed by the hat. After enteringC-c j
, C-c c
or C-c b
, Emacs will wait for a key sequence
referring to a hat. The sequence is terminated by SPC
.
If the hat does not have color and is oval, you will not need to
specify the color or shape. In this case, if the word you want to
jump to has a hat over its “w”, enter C-c j w SPC
.
If the hat is red, enter the corresponding character from
my/color-lookup
before “w”: C-c j r w SPC
. Similarly, if it has
the bolt shape (but no color), enter C-c j z w SPC
. If you specify
both color and shape, you do not need to terminate with SPC
. In
this case, if the hat is a red bolt, you can jump to it with
C-c j r z w
.
(defvar my/color-lookup
'((?y . yellow)
(?r . red)
(?b . blue)
(?p . pink)
(?g . green)))
(defvar my/shape-lookup
'((?z . bolt)
(?c . curve)
(?v . fox)
(?f . frame)
(?> . play)
(?a . wing)
(?o . hole)
(?x . ex)
(?t . cross)
(?i . eye)))
(defun my/apply-hat-action (f)
"Apply F to token of hat read from input."
(let ((input '()))
(while (and (< (length input) 3) (not (eq (car input) ?\ )))
(push (read-char) input))
(when (eq (car input) ?\ )
(setq input (cdr input)))
(setq input (reverse input))
(let ((color nil)
(shape nil)
(character nil))
(while (> (length input) 1)
(when (alist-get (car input) my/color-lookup)
(setq color (alist-get (car input) my/color-lookup)))
(when (alist-get (car input) my/shape-lookup)
(setq shape (alist-get (car input) my/shape-lookup)))
(pop input))
(setq character (car input))
(funcall f (hatty-locate-token character color shape)))))
(defun my/hat-jump ()
(interactive)
(my/apply-hat-action (lambda (region)
(goto-char (car region)))))
(defun my/hat-copy ()
(interactive)
(my/apply-hat-action (lambda (region)
(copy-region-as-kill (car region) (cdr region)))))
(defun my/hat-bring ()
(interactive)
(my/apply-hat-action (lambda (region)
(insert
(buffer-substring-no-properties (car region) (cdr region))))))
(global-set-key (kbd "C-c j") #'my/hat-jump)
(global-set-key (kbd "C-c c") #'my/hat-copy)
(global-set-key (kbd "C-c b") #'my/hat-bring)
To see how hatty can be used to build a more complex interface, see cursorfree.el.
Hatty variables may be customized via thehatty
customization group.
After doing M-x customize RET
, click Convenience
and then Hatty
.
As usual, customization can also be done in your configuration file.
If you want a prioritize certain colours or shapes, change the alists
hatty-color-penalties
and hatty-shape-penalties
. The penalty for
a style is the sum of the color and shape penalty. Styles with lower
penalties will be placed closer to the cursor.
The default settings are optimized for voice control, with penalties corresponding to the amount of utterances needed to refer to the style.
When loading hatty, it will attempt to set the color themes for the hats appropriately. To change the colors to better fit your theme, customizehatty-colors
.
hatty-colors
should be an association list mapping an identifier
symbol to a color. A color can be a hex code like "#aa7023"
or a
named color like "magenta"
(M-x list-colors-display RET
to see
available color names). hatty-colors
may contain or exclude
arbitrary identifiers and colors, allowing you to remove, add or
change them to your liking.
hatty-colors
or
hatty-shapes
.
For example, to disable all special shapes, remove all shapes except for the default shape. In Elisp:
(setq hatty-shapes (list (assq 'default hatty-shapes)))
emacs -Q -l hatty.el -l test.el --eval '(ert t)'
It is not possible to run the ERT tests in batch mode, as the tests require a graphical display to measure the size of rendered text.