Antora resource IDs like 2.0@cli:install:page$linux.adoc#prerequisites carry a lot of meaning, but to most editors they're plain text. A typo in an xref: surfaces as a broken link at build time, and renaming a page means searching the repository by hand. The AsciiDoc plugin for IntelliJ solved this years ago, but only inside IntelliJ. antora-ls brings that understanding to any editor that speaks the Language Server Protocol.
Day one: a port
The first commit was a port of the IntelliJ plugin's Antora resolution logic to Rust, built on tower-lsp: a catalog of every component, version, module and resource family in the workspace, a scanner for references in AsciiDoc, and tests for both. It offered completion, go to definition, hover and broken-reference diagnostics. A release workflow building binaries for macOS, Linux and Windows was there from the start, because the Zed extension downloads them. The README ended with an honest list of what hadn't been ported yet.
Day two: refactoring and a preview
Most of that list was gone the next evening. The new references module finds every reference to a resource and plans the edits for a rename. Two design decisions kept renames safe:
- Moves stay within the resource's family directory, so only a reference's relative path ever has to change, never its module or component.
- Each reference keeps its style. A
./relative xref stays relative, a plain include path stays plain, and a page reference without.adocstays without it.
The same commit taught the server about page-aliases, local content sources in playbooks, and nav-file checks.
An hour later came the live site preview. Rather than reimplementing Antora, a small JavaScript server runs the project's own Antora and registers itself as an Antora extension. It captures the content catalog, enables source maps, tags every block with its source line, and stops Antora right before it would write the site to disk. Everything is served from memory, and unsaved edits re-render only the page that changed. The script is embedded in the Rust binary, which batches keystrokes into 40 ms updates. A Markdown converter for an in-editor approximation came in the same commit.
The same night: making it fast
The first preview converted the whole site up front: about 80 seconds for an 11,000-page site. Two hours later, version 0.2.0 rendered pages on first request instead, while still reading every page header so xref text and navigation stayed complete. That brought the start down to about 3 seconds. The server now starts listening before the build, so the browser shows progress immediately. It runs builds one at a time while serving the old site, re-applies edits made during a build, and no longer crashes on assets that Antora keeps as streams.
Fixes from the following weeks
- Safari (0.2.1): Safari drops a page's event stream when it keeps the page in its back/forward cache, and the preview took that for a stopped server. It now asks the server before saying so.
- Double-click to source: added alongside the IntelliJ plugin. The browser can't hold the session token, so the endpoint only accepts requests from the preview's own origin.
- Release builds (0.2.2): GitHub retired its Intel macOS runners, and the job waited a day before being cancelled, leaving 0.2.1 without an Intel binary. Apple Silicon runners now cross-compile it.
- Windows (0.2.3): the runtime lookup searched for
bunandnode, but Windows names thembun.exeandnode.exeand usually setsUSERPROFILEinstead ofHOME.
antora-ls went public on 10 October under the Apache-2.0 license.