clojure-ts-mode
is an Emacs major mode that provides font-lock (syntax
highlighting), indentation, and navigation support for the
Clojure(Script) programming language, powered by the
tree-sitter-clojure
tree-sitter grammar.
clojure-mode has served us well
for a very long time, but it suffers from a few long-standing
problems, related to
Emacs limitations baked into its design. The introduction of built-in support
for Tree-sitter in Emacs 29 presents a natural opportunity to address many of
them. Enter clojure-ts-mode
, which makes use of TreeSitter to provide:
- fast, accurate and more granular font-locking
- fast indentation
- common Emacs functionality like structured navigation,
imenu
(an outline of a source buffer), current form inference (used internally by various Emacs modes and utilities), etc
Working with TreeSitter is significantly easier than the legacy Emacs APIs for font-locking and
indentation, which makes it easier to contribute to clojure-ts-mode
, and to improve it in general.
Keep in mind that the transition to clojure-ts-mode
won't happen overnight for several reasons:
- getting to feature parity with
clojure-mode
will take some time - tools that depend on
clojure-mode
will need to be updated to work withclojure-ts-mode
- we still need to support users of older Emacs versions that don't support Tree-sitter
That's why clojure-ts-mode
is being developed independently of clojure-mode
and will one day replace it when the time is right. (e.g. 3 major Emacs version
down the road, so circa Emacs 32)
You can read more about the vision for clojure-ts-mode
here.
Warning
This library is still under active development. Breaking changes should be expected.
The currently provided functionality should cover the needs of most Clojure programmers, but you can expect to encounter some bugs and missing functionality here and there.
Those will be addressed over the time, as more and more people use clojure-ts-mode
.
For clojure-ts-mode
to work, you need Emacs 29+ built with TreeSitter support.
To check if your Emacs supports tree sitter run the following (e.g. by using M-:
):
(treesit-available-p)
Additionally, you'll need to have Git and some C compiler (cc
) installed and available
in your $PATH
(or Emacs's exec-path
), for clojure-ts-mode
to be able to install the required
TreeSitter grammars automatically.
Tip
As the TreeSitter support in Emacs is still fairly new and under active development itself, for optimal results you should use the latest stable Emacs release or even the development version of Emacs. See the "Caveats" section for more on the subject.
Note
That's the recommended way to install clojure-ts-mode
.
If you have git
and a C compiler (cc
) available on your system's PATH
,
clojure-ts-mode
will install the
grammars
clojure-ts-mode is available on MElPA and NonGNU ELPA. It can be installed with
(package-install 'clojure-ts-mode)
Emacs 29 also includes package-vc-install
, so you can run
(package-vc-install "https://github.com/clojure-emacs/clojure-ts-mode")
to install this package from source.
You can install it by cloning the repository and adding it to your load path.
git clone https://github.com/clojure-emacs/clojure-ts-mode.git
(add-to-list 'load-path "~/path/to/clojure-ts-mode/")
Once installed, evaluate clojure-ts-mode.el and you should be ready to go.
Note
clojure-ts-mode
install the required grammars automatically, so for most
people no manual actions will be required.
clojure-ts-mode
makes use of two TreeSitter grammars to work properly:
- The Clojure grammar, mentioned earlier
- markdown_inline, which
will be used for docstrings if available and if
clojure-ts-use-markdown-inline
is enabled.
If you have git
and a C compiler (cc
) available on your system's PATH
,
clojure-ts-mode
will install the
grammars when you first open a Clojure file and clojure-ts-ensure-grammars
is
set to t
(the default).
If clojure-ts-mode
fails to automatically install the grammar, you have the
option to install it manually, Please, refer to the installation instructions of
each required grammar and make sure you're install the versions expected. (see
clojure-ts-grammar-recipes
for details)
To see a list of available configuration options do M-x customize-group <RET> clojure-ts
.
Most configuration changes will require reverting any active clojure-ts-mode
buffers.
By default, clojure-ts-mode
assumes command over all buffers and file extensions previously associated with clojure-mode
(and derived major modes like clojurescript-mode
). To disable this remapping, set
(setopt clojure-ts-auto-remap nil)
You can also use the commands clojure-ts-activate
/ clojure-ts-deactivate
to interactively change this behavior.
clojure-ts-mode
currently supports 2 different indentation strategies:
semantic
, the default, which tries to match the indentation ofclojure-mode
andcljfmt
fixed
, a simple indentation strategy outlined by Tonsky in a blog post
Set the var clojure-ts-indent-style
to change it.
(setq clojure-ts-indent-style 'fixed)
Tip
You can find this article comparing semantic and fixed indentation useful.
To highlight entire rich comment
expression with the comment font face, set
(setq clojure-ts-comment-macro-font-lock-body t)
By default this is nil
, so that anything within a comment
expression is
highlighted like regular clojure code.
Tip
You can customize the exact level of font-locking via the variables
treesit-font-lock-level
(the default value is 3) and
treesit-font-lock-features-list
. Check this
section
of the Emacs manual for more details.
By default markdown syntax is highlighted in the docstrings using
markdown_inline
grammar. To disable this feature set
(setopt clojure-ts-use-markdown-inline nil)
To make forms inside of (comment ...)
forms appear as top-level forms for evaluation and navigation, set
(setq clojure-ts-toplevel-inside-comment-form t)
To change the maximal line length used by M-x prog-fill-reindent-defun
(also
bound to M-q
by default) to reformat docstrings and comments it's possible to
customize clojure-ts-fill-paragraph
variable (by default set to the value of
Emacs' fill-paragraph
value).
Every new line in the docstrings is indented by
clojure-ts-docstring-fill-prefix-width
number of spaces (set to 2 by default
which matches the clojure-mode
settings).
If you are migrating to clojure-ts-mode
note that clojure-mode
is still required for cider and clj-refactor packages to work properly.
After installing the package do the following.
- Check the value of
clojure-mode-hook
and copy all relevant hooks toclojure-ts-mode-hook
.
(add-hook 'clojure-ts-mode-hook #'cider-mode)
(add-hook 'clojure-ts-mode-hook #'enable-paredit-mode)
(add-hook 'clojure-ts-mode-hook #'rainbow-delimiters-mode)
(add-hook 'clojure-ts-mode-hook #'clj-refactor-mode)
- Update
.dir-locals.el
in all of your Clojure projects to activate directory local variables inclojure-ts-mode
.
((clojure-mode
(cider-clojure-cli-aliases . ":test:repl"))
(clojure-ts-mode
(cider-clojure-cli-aliases . ":test:repl")))
As the TreeSitter Emacs APIs are new and keep evolving there are some
differences in the behavior of clojure-ts-mode
on different Emacs versions.
Here are some notable examples:
- On Emacs 29 the parent mode is
prog-mode
, but on Emacs 30+ it's bothprog-mode
andclojure-mode
(this is very helpful when dealing withderived-mode-p
checks) - Navigation by sexp/lists might work differently on Emacs versions lower than 31. Starting with version 31, Emacs uses TreeSitter 'things' settings, if available, to rebind some commands.
As of version 0.2.x, the most obvious missing feature are the various
refactoring commands in clojure-mode
.
Yes! Preliminary support for clojure-ts-mode
was released in CIDER
1.14. Make sure to
grab the latest CIDER from MELPA/GitHub. Note that clojure-mode
is still
needed for some APIs that haven't yet been ported to clojure-ts-mode
.
For now, when you take care of the keybindings for the CIDER commands you use
and ensure cider-mode
is enabled for clojure-ts-mode
buffers in your config,
most functionality should already work:
(add-hook 'clojure-ts-mode-hook #'cider-mode)
Check out this article for more details.
Currently, there is an open PR adding support for inf-clojure.
Copyright © 2022-2025 Danny Freeman and contributors.
Distributed under the GNU General Public License; type C-h C-c to view it.