A tree-sitter-based major mode for editing AsciiDoc files in Emacs.
-
Syntax highlighting via tree-sitter (headings, inline markup, blocks, lists, admonitions, macros, attributes)
-
Section navigation (
C-M-a/C-M-e) and sentence-level movement (M-a/M-e) across paragraphs and blocks -
Imenu support for section navigation
-
Outline minor mode enabled by default — heading navigation (
C-c C-n/p/f/b/u) and folding -
Comment support (
//line comments) -
Graceful degradation — works as basic
text-modewhen grammars are unavailable
I’ve been maintaining adoc-mode since 2022, but over time I realized I rarely used many of its advanced features (e.g. inline image preview, interactive markup commands, tempo templates, native code block highlighting). I wanted something simpler.
asciidoc-mode is my attempt to build a leaner alternative to adoc-mode, not a replacement for it. The key differences:
-
Tree-sitter for robust, accurate font-locking and optimal performance in large documents
-
Simple by design — focuses on the essentials (highlighting, navigation, folding) without the bells and whistles
-
Single-file implementation with minimal complexity
I named it asciidoc-mode instead of adoc-ts-mode because it shares nothing with adoc-mode and I wanted to emphasize that. There has never been an asciidoc-mode before, so asciidoc-ts-mode felt too verbose for no good reason.
adoc-mode will continue to be maintained and evolved separately. Pick whichever suits your workflow.
| Feature | asciidoc-mode | adoc-mode |
|---|---|---|
Syntax highlighting |
Tree-sitter |
Regex |
Imenu |
Yes |
Yes |
Outline / folding |
Yes |
Yes |
Section navigation |
Yes |
No |
Sentence navigation |
Yes |
No |
Markup insertion commands |
No |
Yes |
Tempo templates |
No |
Yes |
Inline image preview |
No |
Yes |
Title promotion / demotion |
No |
Yes |
Native code block highlighting |
No |
Yes |
Flyspell integration |
No |
Yes |
Compilation error support |
No |
Yes |
Emacs requirement |
30.1+ |
26.1+ |
-
Emacs 30.1 or later (built with tree-sitter support)
-
Two tree-sitter grammars from cathaysia/tree-sitter-asciidoc:
-
asciidoc(block-level structure) -
asciidoc_inline(inline formatting)
-
After installing the package, run:
M-x asciidoc-install-grammarsThis downloads and compiles both grammars automatically. You only need to do this once.
The package is available on MELPA and MELPA Stable. If you’ve configured MELPA as a package source:
M-x package-install RET asciidoc-mode RETOr with use-package:
(use-package asciidoc-mode
:ensure t)Alternatively, Emacs 30+ can install directly from VCS:
(use-package asciidoc-mode
:vc (:url "https://github.com/bbatsov/asciidoc-mode" :rev :newest :branch "main"))asciidoc-mode uses two tree-sitter parsers from cathaysia/tree-sitter-asciidoc, each covering the full buffer independently:
-
asciidoc— block-level structure (headings, paragraphs, lists, code blocks, admonitions, attributes, comments, etc.) -
asciidoc-inline— inline formatting (bold, italic, monospace, links, cross-references, footnotes, macros, replacements, etc.)
The grammar author split them because block-level and inline-level parsing have fundamentally different rules in AsciiDoc, and separating them keeps each grammar simpler. Both parsers operate on the entire buffer without range restrictions — this is the same dual-parser pattern used by Emacs’s built-in markdown-ts-mode.
Because both parsers run independently on the same text, they can disagree. In particular, the inline parser misinterprets and * list markers as emphasis delimiters, creating spurious emphasis spans that can swallow subsequent inline content (e.g. autolinks). To mitigate this, all block-level font-lock rules use :override t so that block-level faces (list markers, headings, code blocks, etc.) always win over incorrect inline faces. This doesn’t fix inline elements consumed by the spurious emphasis nodes — that requires an upstream grammar fix (see #2).
A related subtlety: treesit’s default font-lock behavior (:override nil) skips an entire captured range if any position within it already has a face. This means font-lock rules that capture a broad parent node will silently fail when a child node was already fontified by an earlier rule. To avoid this, inline macro rules capture specific child nodes (macro_name, target) rather than the whole inline_macro node — the same pattern used for block macros.
When grammars are unavailable, the mode falls back to plain text-mode with comment support only. No tree-sitter features are activated in this case.
# Install Eldev (if not already installed)
curl -fsSL https://raw.github.com/emacs-eldev/eldev/master/webinstall/eldev | sh
# Run everything
make all
# Individual targets
make compile # Byte-compile with warnings-as-errors
make lint # Run elisp-lint
make test # Run buttercup tests
make clean # Remove build artifacts|
Note
|
Font-lock tests require the tree-sitter grammars to be installed. Tests that need grammars will be skipped (not failed) if they are unavailable. |
Licensed under the GNU General Public License v3.0 or later. See LICENSE for details.