Skip to content

Commit 86dcfa9

Browse files
committed
Tag shell/REPL blocks at build time via asciidoctor extension
Add asciidoctor-extensions/terminal-role.js, an Asciidoctor tree-processor that walks listing and literal blocks and calls `block.addRole('terminal')` when the source starts with a known prompt (iex>, iex(n)>, irb>, irb(...)>, >>, $, user@host:). The role becomes `class="listingblock terminal"` in the rendered HTML, which the shared UI bundle styles as a macOS-style terminal window. Registered via the asciidoc. extensions entry in antora-playbook.yml and the local development playbook. Replaces the previous runtime terminal-detect.js that ran in the browser after DOM load; now the class is baked into the static HTML at build time.
1 parent c239ed6 commit 86dcfa9

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

antora-local-playbook.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ ui:
1818
output_dir: antora-assets
1919
runtime:
2020
fetch: true
21+
22+
asciidoc:
23+
extensions:
24+
- ./asciidoctor-extensions/terminal-role.js

antora-playbook.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ ui:
1717
output_dir: antora-assets
1818
runtime:
1919
fetch: true
20+
21+
asciidoc:
22+
extensions:
23+
- ./asciidoctor-extensions/terminal-role.js
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Detect shell / REPL transcripts in source and literal blocks
2+
// at build time and add the `terminal` role to them. The UI
3+
// bundle's CSS targets `.doc .listingblock.terminal` to render
4+
// those blocks with macOS-style terminal chrome (three
5+
// traffic-light dots, subtle depth). Doing this at build time
6+
// means the class lands in the static HTML — no runtime JS
7+
// needed in the browser.
8+
//
9+
// We match the first non-whitespace line of the block against
10+
// common prompts:
11+
// iex> — Elixir IEx
12+
// iex(n)> — IEx with numbered prompt
13+
// irb> — Ruby irb (simple form)
14+
// irb(main):001:0> — Ruby irb (default form)
15+
// >> — minimalist prompt used in the Ruby /
16+
// Rails books for irb transcripts
17+
// $ — POSIX shell prompt
18+
// user@host: — shell prompt with hostname prefix
19+
//
20+
// The extension is a tree processor: it walks every listing
21+
// (source) block and every literal block, checks the raw
22+
// source, and calls `addRole('terminal')` when the prefix
23+
// matches. Roles on blocks are emitted by Asciidoctor as CSS
24+
// classes on the wrapping <div>.
25+
26+
'use strict'
27+
28+
const TERMINAL_PREFIX = /^\s*(iex(\([^)]*\))?>|irb(\([^)]*\))?>|>>|\$\s|[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+[:#$]\s)/
29+
30+
module.exports.register = function register (registry) {
31+
registry.treeProcessor(function () {
32+
const self = this
33+
self.process(function (doc) {
34+
;['listing', 'literal'].forEach(function (context) {
35+
doc.findBy({ context: context }).forEach(function (block) {
36+
const lines = block.getLines ? block.getLines() : (block.lines || [])
37+
const source = Array.isArray(lines) ? lines.join('\n') : String(lines || '')
38+
if (source && TERMINAL_PREFIX.test(source)) {
39+
block.addRole('terminal')
40+
}
41+
})
42+
})
43+
})
44+
})
45+
}

0 commit comments

Comments
 (0)