Skip to content

Prgebish/evil-tex-ts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

evil-tex-ts

evil-tex-ts is a modern, tree-sitter based toolkit for LaTeX editing in Evil mode. It is a re-imagining of the classic evil-tex package, utilizing Emacs 29+ built-in tree-sitter capabilities for superior performance and accuracy.

Why a new package? The original `evil-tex` has not seen updates in years and relies on regular expressions for text object detection. This approach can be brittle, inaccurate in complex cases, and inefficient on large files. evil-tex-ts leverages the structural understanding of the `tree-sitter-latex` parser to provide precise text objects, efficient toggles, and robust surround integration.

This is the first release of the package. While functional, it may contain bugs or rough edges. If you encounter any issues, please report them on GitHub.

If you find evil-tex-ts useful, please consider giving it a star on GitHub — it helps others discover the project!

Table of Contents

Showcase

| marks point.

Visual reference

   \foobar{barbaz}     \foobar{barbaz}    \foobar     \foobar    \foobar{}     \foobar{}
   └─────────────┘             └────┘     └─────┘            ┆   └───────┘             ┆
          ac                     ic         ac      ic (empty)      ac            ic (empty)

  ┌\begin{foobar}     \begin{foobar}
  │                  ┌
ae│ baz            ie│ baz
  │                  └
  └\end{foobar}       \end{foobar}

  \(foobar\)    \(foobar\)    \[foobar\]    \[foobar\]
  └────────┘      └────┘      └────────┘      └────┘
      am            im            am            im

  (foobar)    (foobar)    \left(foobar\right)    \left(foobar\right)  \Bigl(foobar\Bigr)    \Bigl(foobar\Bigr)
  └──────┘     └────┘     └─────────────────┘          └────┘         └────────────────┘          └────┘
     ad          id               ad                     id                   ad                    id

   ┌\section{foo}          \section{foo}
   │                      ┌
 aS│ baz                iS│ baz
   │\subsection*{}        │\subsection*{}
   └ qux                  └ qux
    \chapter*{bar}         \chapter*{bar}

   a^{foo}    a^{foo}    a^b    a^b    a^\bar    a^\bar
    └────┘       └─┘      └╵      ╵     └───┘      └──┘
      a^          i^      a^     i^      a^         i^

   a_{foo}    a_{foo}    a_b    a_b    a_\bar    a_\bar
    └────┘       └─┘      └╵      ╵     └───┘      └──┘
      a_          i_      a_     i_      a_         i_

   & foobar &    & foobar &    & foobar \\    & foobar \\
   └───────┘      └──────┘     └───────┘       └──────┘
       aT            iT            aT             iT

    `foobar'      `foobar'     ``foobar''     ``foobar''
    └──────┘       └────┘      └────────┘       └────┘
       aq            iq            aQ             iQ

Text object examples

  • die (delete inner environment)

    Before:

    \begin{equation}
      x^2 + y^2 = z^2|
    \end{equation}
        

    Press die

    After:

    \begin{equation}
    \end{equation}
        
  • cic (change inner command)

    Point can be anywhere inside the command:

    Before: \textbf{hel|lo}

    Press cic

    After: \textbf{|}

    Before: \tex|tbf{hello}

    Press cic

    After: \textbf{|}

    If point is outside a command, seeks the nearest command to the right on the same line:

    Before: s|ome text \textbf{hello}

    Press cic

    After: some text \textbf{|}

  • dam (delete around math)

    Before: \(x + y| = z\)

    Press dam

    After: (empty)

    If point is outside math, seeks the nearest math to the right on the same line:

    Before: some te|xt \(x + y\)

    Press dam

    After: some text|

  • viS (select inner section)

    Select the content of a section until the next section (excluding the \section{...} header).

    Before:

    \section{Introduction}
    This is the intro.|
    More text here.
    
    \section{Methods}
        

    Press viS

    After (selected region marked with ##):

    \section{Introduction}
    ##This is the intro.
    ##More text here.
    ##
    \section{Methods}
        

    The empty line before \section{Methods} is included. Use vaS to also include the \section{...} header.

Toggle examples

All toggle commands use the mt prefix by default (mnemonic: “magnificent toggle”).

Note: The mt prefix overrides the m (set-marker) command for the t character. You have 25 other marks available. To change this behavior, see User Options.

  • mte (toggle environment *)

    Toggle the asterisk on environments. Useful for switching between numbered and unnumbered equations.

    \begin{equation}|  →  \begin{equation*}
        

    Works with any environment:

    \begin{align}    ↔  \begin{align*}
    \begin{figure}   ↔  \begin{figure*}
    \begin{table}    ↔  \begin{table*}
        
  • mtm (toggle math mode)

    Toggle between inline and display math modes.

    \(x + y|\)  →  \[x + y\]  →  \(x + y\)
    $x + y|$    →  \[x + y\]  →  $x + y$
        

    The inline math format is controlled by evil-tex-ts-preferred-inline-math: dollar ($...$, default) or paren (\(...\)).

  • mtM (toggle math align)

    Toggle between display math and align* environment.

    Before:

    \[
      x + y|
    \]
        

    Press mtM

    After:

    \begin{align*}
      x + y
    \end{align*}
        

    Press mtM again

    \[
      x + y
    \]
        

    Also works starting from inline math (one-way to align*):

    Before: $x + |y$

    Press mtM

    After:

    \begin{align*}
      x + y
    \end{align*}
        

    Then toggles between align* and \[...\].

  • mtd (toggle delimiter sizing)

    Toggle automatic delimiter sizing with \left=/\right=.

    (x + y|)      ↔  \left(x + y\right)
    [a, b|]       ↔  \left[a, b\right]
    \{1, 2|\}     ↔  \left\{1, 2\right\}
        

    Also removes \bigl=/\bigr= and similar sizing commands (one-way):

    \bigl(x + y\bigr)   →  (x + y)
    \Bigl[a, b\Bigr]    →  [a, b]
        
  • mtc (toggle command *)

    Toggle the asterisk on commands. Useful for switching between numbered and unnumbered sections.

    \section{Title|}  →  \section*{Title}
        

    Works with various sectioning commands:

    \chapter{Title}      ↔  \chapter*{Title}
    \subsection{Title}   ↔  \subsection*{Title}
    \paragraph{Title}    ↔  \paragraph*{Title}
        
  • mtS (change section type)

    Change the type of the current section. A prompt appears with available section types.

    Before:

    \section{My Title|}
    Some content here.
        

    Press mtS, select subsection from prompt

    After:

    \subsection{My Title}
    Some content here.
        

    Available types: part, chapter, section, subsection, subsubsection, paragraph, subparagraph

Surround examples

Surround commands follow the evil-surround patterns:

  • ys<text-object><surround-type> — add surround (e.g., ysiwe wraps inner word with environment)
  • cs<old><new> — change surround (e.g., csee changes environment to environment)
  • ds<type> — delete surround (e.g., dsd deletes delimiter)

When <new> or <type> opens a keymap (like e for environment or d for delimiter), press the corresponding key to select (see Keymaps).

  • ysiwe (surround word with environment)

    Before: |word

    Press ysiwe, then type equation

    After:

    \begin{equation}
      word
    \end{equation}
        
  • Se (visual surround with environment)

    Before: |1 + 2

    Select the expression with v$ (or any visual selection), press S, then e for environment, then a for align (see Environment Keymap)

    After:

    \begin{align}
      1 + 2
    \end{align}
        

    Content is automatically indented inside the environment.

  • VjSeA (linewise surround multiple lines with environment)

    Before:

    |1 + 2
    3 + 4
        

    Vj selects both lines, S starts surround, e for environment, A for align*

    After:

    \begin{align*}
      1 + 2
      3 + 4
    \end{align*}
        
  • cseea (change environment to align)

    Before:

    \begin{equation}
      x^2 + y^2| = z^2
    \end{equation}
        

    Press cs (change surround), e (old: environment), e (new: environment keymap), a (align)

    After:

    \begin{align}
      x^2 + y^2 = z^2
    \end{align}
        
  • dsd (delete surrounding delimiter)

    Before: \left(x + y|\right)

    Press dsd

    After: |x + y

    Also works with simple delimiters:

    Before: (a + b|)

    Press dsd

    After: |a + b

Installation

Requirements

  • Emacs 29.1 or later (with tree-sitter support enabled)
  • evil
  • evil-surround (optional, but highly recommended)
  • A generic `tree-sitter-latex` grammar (usually installed via `M-x treesit-install-language-grammar`)

Setup

From MELPA

(use-package evil-tex-ts
  :ensure t
  :after (evil)
  :hook ((LaTeX-mode . evil-tex-ts-mode)
         (latex-mode . evil-tex-ts-mode))
  :init
  ;; Register tree-sitter grammar source
  (add-to-list 'treesit-language-source-alist
               '(latex "https://github.com/latex-lsp/tree-sitter-latex"))
  :config
  ;; Auto-install grammar if not available
  (unless (treesit-language-available-p 'latex)
    (treesit-install-language-grammar 'latex))

  ;; IMPORTANT: Set preferred inline math format
  ;; 'dollar for $...$ (default), 'paren for \(...\)
  (setq evil-tex-ts-preferred-inline-math 'dollar))

Or install manually with M-x package-install RET evil-tex-ts RET.

Manual installation

Clone the repository and add it to your load-path:

(add-to-list 'load-path "/path/to/evil-tex-ts")
(require 'evil-tex-ts)

;; Hook into LaTeX modes
(add-hook 'latex-ts-mode-hook #'evil-tex-ts-mode)
(add-hook 'LaTeX-mode-hook #'evil-tex-ts-mode) ;; If using AUCTeX

Important: The variable evil-tex-ts-preferred-inline-math controls which format is used when toggling math modes (mtm) and surrounding with inline math (m). Default value is 'dollar ($...$). Set to 'paren for \(...\).

Overview

Text Objects

This package defines precise text objects based on the AST:

KeyText Object TargetNotes
cLaTeX commands: \foo{...}Handles optional args [...] and nested braces
eEnvironments: \begin{...} ... \end{...}Selects proper range including newlines
mMath: \(...\), \[...\], $...$, environmentsDetects inline vs display math automatically
dDelimiters: (), [], \{\}, \left(\right)Handles balanced pairs
SSections: \section{...} to end of sectionHierarchical selection
^Superscripts: x^2, x^{...}
_Subscripts: x_i, x_{...}

Toggles

Default prefix is mt (“magnificent toggle”).

KeyBehaviourExample
mteToggle environment asterisk\begin{eq}\begin{eq*}
mtcToggle command asterisk\section\section*
mtmToggle math mode (inline ↔ display)\(...\)\[...\]
mtMToggle math align (display ↔ align*)\[...\]\begin{align*}...
mtdToggle delimiter sizing(x)\left(x\right)

Surround

If `evil-surround` is installed, `evil-tex-ts` adds specific surround pairs.

KeySurrounds withExample InputResult
cCommand (prompts)text\cmd{text}
eEnvironment (keymap)text\begin{env} text \end{env}
mInline mathtext\(text\) or $text$
MDisplay mathtext\[text\]
dDelimiter (keymap)text\left(text\right)
^Superscriptx^{x}
_Subscriptx_{x}
;CDLaTeX accents (keymap)x\bar{x}

See Keymaps for full keymaps.

Navigation

KeyCommandDescription
]]evil-tex-ts-go-forward-sectionJump to next section heading
[[evil-tex-ts-go-back-sectionJump to previous section heading

Works in both normal and visual modes. Recognizes chapter, section, subsection, etc.

Configuration

User Options

Customize these variables via M-x customize-group RET evil-tex-ts.

  • evil-tex-ts-select-newlines-with-envs (default: t)
    Include newlines when selecting/deleting environments. Makes dae remove the whole block cleanly.
  • evil-tex-ts-toggle-override-m (default: t)
    Bind toggles to mt. Set to nil to preserve the m marker key.
  • evil-tex-ts-toggle-override-t (default: nil)
    Bind toggles to ts (vimtex style). Can be used alongside or instead of mt.
  • evil-tex-ts-preferred-inline-math (default: 'dollar)
    Preferred format for inline math toggles: dollar ($...$) or paren (\(...\)).

Custom Surround Insertions

Add your own environments, accents, and delimiters using these functions:

;; Add "quote" environment on "q"
(evil-tex-ts-bind-to-env-map '(("q" . "quote")))

;; Add figure with default [!ht] position
(evil-tex-ts-bind-to-env-map '(("F" "\\begin{figure}[!ht]" . "\\end{figure}")))

;; Add custom accent
(evil-tex-ts-bind-to-cdlatex-accents-map '(("B" . "fbox")))

;; Add custom delimiter
(evil-tex-ts-bind-to-delim-map '(("h" "\\huge(" . "\\huge)")))

See docstrings of evil-tex-ts-bind-to-env-map for the complete format.

Custom Toggles

Bind your function to evil-tex-ts-toggle-map, it’s a normal keymap:

(define-key evil-tex-ts-toggle-map "x" #'my-custom-toggle-function)

Differences from evil-tex

Featureevil-tex (Original)evil-tex-ts (This package)
ParsingRegular ExpressionsTree-sitter (AST)
PerformanceSlower on large filesFast & Incremental
AccuracyCan be tricked by commentsRobust structural parsing
DependenciesEmacs 25+, AUCTeXEmacs 29+, tree-sitter grammar
MaintainabilityHarder (complex regex)Easier (standard grammar)

Acknowledgements

Appendix

Keymaps

Environment Keymap (e)

KeyEnvKeyEnv
xpromptmmultline
eequationMmultline*
Eequation*ccases
aalignztikzpicture
Aalign*ffigure
nalignatiitemize
Nalignat*Ienumerate
ggatherbframe
Ggather*yarray
lflalignreqnarray
Lflalign*

Theorem prefix (t)

Press t then the second key to select theorem-like environment.

Example: ysiwetd wraps word in \begin{definition}...\end{definition}

KeyEnvKeyEnv
taaxiomtllemma
tccorollarytpproof
tCclaimtqquestion
tddefinitiontrremark
teexamplestttheorem
tsexercise

Delimiter Keymap (d)

Uppercase = simple, lowercase = sized (\left~/\right~).

KeySimpleKeySized
P()p\left(\right)
S[]s\left[\right]
C\{\}c\left\{\right\}
R\langle\rangler\left\langle\right\rangle
V\lvert\rvertv\left\lvert\right\rvert
N\lVert\rVertn\left\lVert\right\rVert

CDLaTeX Accent Keymap (;)

Context sensitive: uses \mathbf in math, \textbf in text.

Math accents

KeyAccentKeyAccent
.dot:ddot
^hatHwidehat
~~~~tildeNwidetilde
-barToverline
vcheckubreve
>vec/grave
"acute_underline
{overbrace}underbrace
qsqrt

Text styles

KeyStyleKeyStyle
bbold (bf)rroman (rm)
iitalic (it)eemph
ytypewriter (tt)fsans-serif (sf)
lslanted (textsl)ccalligraphic
mmbox

Math size styles

Useful for controlling formula size, e.g. in fractions.

Example: ysiw;1 wraps word in {\displaystyle ...}

KeyStyle
0{\textstyle }
1{\displaystyle }
2{\scriptstyle }
3{\scriptscriptstyle }

About

Tree-sitter based LaTeX text objects for Evil mode

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •