antora-ls started as a port of the Antora support in the AsciiDoc plugin for IntelliJ. IntelliJ already had completion, navigation and validation for Antora references. What it lacked was the live preview of the real site that antora-ls had grown along the way. antora-intellij adds just that, and it went from its first commit to its first release in one day.
Reuse the server, not the language server
The plugin doesn't run antora-ls. It bundles only the preview server, antora-preview.js, taken from a specific antora-ls release; version 0.1.0 of the plugin ships the script from antora-ls 0.2.2. The first commit, about 1,500 lines of Kotlin, splits the work into small pieces:
- a process wrapper that starts the script under Bun or Node and reads its handshake, status and reveal lines from stdout
- a client that posts unsaved text and caret positions to the server in 40 ms batches
- an editor sync that listens for document, caret and save events
- a tool window that shows the site in an embedded JCEF browser, next to a log of the server's and Antora's output
Everything Antora-specific stays in the shared script. The plugin knows nothing about Antora's content model, so a fix to the preview server reaches both Zed and IntelliJ.
Double-click to source
Unlike Zed, IntelliJ can show the preview right next to the editor, which made one feature obvious: double-click a block in the preview and jump to its source line. The browser side went into the shared preview server in antora-ls, a minute after the plugin's first commit. The server reports the block's file and line on stdout, and the plugin opens the file there.
Finding Node
A surprising share of the plugin finds the JavaScript runtime. It looks on the PATH and in the places that Volta, nvm, fnm, asdf, mise and Homebrew install Node, plus nvm-windows, Scoop and Program Files\nodejs on Windows. When a version manager has several versions installed, it picks the newest by version number, so v20.10.0 wins over v20.9.1. If Antora isn't installed in the project, the plugin offers to install it with the project's own package manager.
The same afternoon
The rest of the day turned the plugin into something releasable:
- Memory: a setting lets the tool window dispose of its embedded browser while no preview runs.
- Idle page: the page shown after stopping a preview was loaded from an internal
file://URL, which the plugin's link filter handed to the system browser as a "not found" page. It's now adata:URL. - Releases: a workflow runs the tests and attaches the plugin zip to a GitHub release, using the preview script from the pinned antora-ls release. The plugin is Apache-2.0 licensed, with a notice crediting the bundled script.
- CI: the first release build failed because a test for the nvm lookup found the runner's own Node in
/usr/local/binfirst. The system folders are now a constructor parameter that the test leaves empty.