Skip to content

bbatsov/asciidoc-mode

Repository files navigation

asciidoc-mode

MELPA MELPA Stable CI License GPL 3

A tree-sitter-based major mode for editing AsciiDoc files in Emacs.

Features

  • 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-mode when grammars are unavailable

Rationale

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+

Requirements

  • 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)

Installation

Grammar Setup

After installing the package, run:

M-x asciidoc-install-grammars

This downloads and compiles both grammars automatically. You only need to do this once.

Package Installation

MELPA

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 RET

Or with use-package:

(use-package asciidoc-mode
  :ensure t)

use-package with vc

Alternatively, Emacs 30+ can install directly from VCS:

(use-package asciidoc-mode
  :vc (:url "https://github.com/bbatsov/asciidoc-mode" :rev :newest :branch "main"))

Manual

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

(add-to-list 'load-path "/path/to/asciidoc-mode")
(require 'asciidoc-mode)

Usage

Open any .adoc or .asciidoc file and asciidoc-mode activates automatically.

Design

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.

Development

The project uses Eldev for build tooling and Buttercup for testing.

# 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.

License

Licensed under the GNU General Public License v3.0 or later. See LICENSE for details.

About

A modern Emacs major mode for editing AsciiDoc files, powered by TreeSitter

Resources

License

Contributing

Stars

Watchers

Forks

Packages