Automatically pick between TreeSitter and default major modes in Emacs 29+.
The recommended installation method is through MELPA. After following their
setup, you can install through your preferred package manager. If that’s the
default package.el
, simply M-x package-refresh-contents
and then
M-x package-install RET treesit-auto
If you want a local clone of the repository, rather than just a copy of the
source, you might instead use package-vc-install
M-x package-vc-install RET https://github.com/renzmann/treesit-auto.git
Then, in your Emacs configuration file (~/.emacs.d/init.el
),
(use-package treesit-auto
:config
(treesit-auto-apply-remap))
Emacs 29, while featuring treesit.el
and a convenient
treesit-install-language-grammar
, will not feature an intelligent way to choose
between a default mode, such as python-mode
, and it’s tree-sitter enhanced
version, python-ts-mode
, automatically. This package attempts to remedy that
by applying these rules:
1. If the grammar is installed, then switch to the appropriate tree-sitter mode:
In this case, assuming we open a Python buffer, and the Python tree-sitter
grammar is installed, then Emacs will use python-ts-mode
instead of
python-mode
.
2. If the grammar is NOT installed, and the user has specified a fallback:
This package exposes a customizable variable treesit-auto-fallback-alist
that
lets you pick the fallback modes by name. For instance, if we apply this:
(add-to-list 'treesit-auto-fallback-alist '(toml-ts-mode . conf-toml-mode))
Then, when the TOML grammar is missing, Emacs will use conf-toml-mode
, instead
of trying to fall back to toml-mode
.
**3. If the grammar is NOT installed and the user has NOT specified a fallback mode AND an appropriately named base mode exists, switch to it**
This is the most general case. If, for example, the Go tree-sitter grammar is
not installed, but we have installed go-mode, then Emacs will use that instead
of go-ts-mode
, since they share the same go-
prefix.
If you have modified treesit-language-source-alist
through setq
, then it is
recommended to put any configuration of this package AFTER that setq
.
Not all default major modes make sense to bump up to a similar tree-sitter mode.
For example, when I open a .sh
file, my intent is nearly always to be using it
with Bash. This is not the case for everyone, though, so by default this
package will not replace sh-mode
with bash-ts-mode
. If you do want such a
remap, simply include a line like this before calling treesit-auto-apply-remap
:
(add-to-list 'treesit-auto-fallback-alist '(bash-ts-mode . sh-mode))
If you want treesit-auto-apply-remap
to re-run after installing a grammar with
treesit-install-language-grammar
, try advising the function with something like
this:
(advice-add 'treesit-install-language-grammar
:after (lambda (&rest _r) (treesit-auto-apply-remap)))
This package does not modify any of your major mode hooks. That is, if you have
functions in python-mode-hook
, but not in python-ts-mode-hook
, then your hook
from python-mode
will not be applied, assuming python-ts-mode
is what gets
loaded. For major modes in which this is a concern, the current recommendation
is to address this as part of your configuration.
(setq python-ts-mode-hook python-mode-hook)
This is how I configure treesit-auto
for my own personal use.
(use-package treesit-auto
:demand t
:config
(add-to-list 'treesit-auto-fallback-alist '(bash-ts-mode . sh-mode))
(treesit-auto-apply-remap)
(advice-add 'treesit-install-language-grammar
:after (lambda (&rest _r) (treesit-auto-apply-remap))))