Configuring meow for Friendly LaTeX Editing
TL;DR: We implement some configuration to recover functionality possible in evil-tex in the meow modal editing scheme.
Having ditched evil-collection
to get familiar with the default emacs keybindings, I found myself satsisfied with many of the facilities emacs provides out-of-the-box for editing text.
Alas, I feel modal editing is something I prefer, so I switched to meow
.
I chose meow for a few reasons:
- Trivial to extend and hack on
- The “selection-first” ethos is intriguing
- No dependencies
- Prefers built-in methods for various tasks
- Keypad mode offers a great, lighter weight alternative to the
SPC
DOOM leader with evil mode
So far, it’s been an enjoyable experience, but one evil-mode package–evil-tex
–gave me pause.
evil-tex
evil-tex is an extension to evil that adds support for “vimmable” text objects in LaTeX syntax.
As an example, let |
denote the location of the point when using evil mode.
Suppose we’re given the situation:
The qu|ick brown fox jumps over the lazy dog.
In evil-normal-mode
you can type the keys ciw
to “Change Inner Word”, deleting the work quick
and placing you in evil-insert-mode
.
If w
denotes the “word” evil object, evil-tex offers the math-mode text object, allowing this same loop to be performed but inside LaTeX syntax.
Consider the following inline math expression with point |
:
\( X\cong | Y \)
With evil-tex-mode
enabled, and inside evil-normal-mode
, we can press cim
to “Change Inner Math”, deleting all the text within the \( \)
delimiters and placing us in insert mode.
This is just one example of what evil-tex offers; a more comprehensive picture is in the documentation.
Doing Our Own Thing
Meow uses things
(lit.) to demarcate sections of text that you can navigate around and select.
For example, some things that come preloaded with meow are sentences, defuns, paragraphs, buffers, windows, and lines.
When a thing is defined, you can press , <THING_KEY>
to select the inner part of the thing, where <THING_KEY>
is the key associated with that thing (e.g. l
for line, d
for defun).
Similarly, you can press . <THING_KEY>
to select to the bounds of the thing.
Here’s a demo on how that works with the symbol
thing, mapped to e
:
There’s a parallel between this behavior and the “inner <object>” and “all <object>” behavior in evil.
For example, suppose we have a text object in evil that picks out the line the point is on, mapped to l
.
Then the key sequence c i l
in evil mode (to “Change Inner Line”) could be replicated in meow with , l c
.
In meow, it’s easy to define a thing
with the function (meow-thing-register)
.
Let’s register a thing
that picks out the LaTeX inline math environment \( \)
.
The simplest way to do this is using the pair matching:
(meow-thing-register 'inline-math
'(pair ("\\(") ("\\)"))
'(pair ("\\(") ("\\)") ) )
Now we can map this thing to a key:
(add-to-list 'meow-char-thing-table '(?m . inline-math))
Now, when we’re inside an inline math environment, we can press , m
to select all the text within the math environment, and . m
to select all of the math environment.
The bindings , m
and . m
replicate the evil-tex object identification i m
and a m
, respectively.
We can also use this same concept to extend functionality to full-scale LaTeX environments. That configuration is
(meow-thing-register 'latex-env
'(regexp "\\\\begin{.*?}\n\\(?:\\\\label{.*?}\n\\)?" "\n\\\\end{.*?}" )
'(regexp "\\\\begin{.*?}" "\\\\end{.*?}" ) )
(add-to-list 'meow-char-thing-table '(?E . latex-env))
This adds the same support for latex environments that look this like:
\begin{ENV}
...
\end{ENV}
The \label{...}
directive sometimes appears in these environments, so the regex used to match these things are included as optional match groups.
In fact, in my own configuration, I’ve combined the latex-math
and latex-env
things into one thing, so I use just the key m
to pick out either inline math environments or \begin{...} \end{...}
environments.
These are all well and good, but one of my favorite evil-tex objects were the LaTeX delimiters: including \left( \right)
and friends.
Let’s do those too.
(setq latex-left-delim (rx "\\left"
(or "\\langle"
"("
"\["
"\\{"
"\\lbrace")))
(setq latex-right-delim (rx "\\right"
(or "\\rangle"
")"
"\]"
"\\}"
"\\rbrace")))
(meow-thing-register 'latex-delim
`(regexp ,latex-left-delim ,latex-right-delim)
`(regexp ,latex-left-delim ,latex-right-delim))
(add-to-list 'meow-char-thing-table '(?j . latex-delim))
Here’s what that looks like:
Note that the way we have defined the delimiters makes it trivial to add/subtract delimiters from the list of things we want to match.
Edge Cases
Because of the way meow searches for the beginnings and ends of things, this implementation has obvious edge cases which I think are acceptable compromises.
Notably, meow searches behind and in front of the point for the inner/outer/bounds of the thing.
This implies that–for example–if the point was on a line containing \label{...}
and you press , E
in normal mode, it would select the line containing the label directive as well as the content before the \end{..}
:
I strongly suspect (nay, I know) that more clever implementations are possible using emacs lisp.
Closing Thoughts
What I’ve shown here is a very small, quickly-put-together look at the hackability of meow. The documentation