这个页面专门检验 Org 语义能否走完整条发布管线。它尽可能多地使用 strict renderer 已经支持的 Org 结构,既是展示,也是留在真实内容里的回归测试。以后哪次修改让这里坏掉,内容管线也就退化了。
下面的结构都来自 Org AST,并经过 ox-edn 和 Loam 的正常路径;页面没有直接插入任意 HTML。
行内语义
Org 会为行内标记保留各自的节点。比如:粗体、斜体、下划线、删除线、code 与 verbatim 在 AST 中都有不同的类型。
上下标也保留结构:水可以写成 H2O,平方可以写成 x2。Org entity 也能进入 AST,例如 α、β 和 →;这一行的末尾还故意放一个显式换行,
这句话因此从新的一行开始,换行来自 Org 节点。
键盘操作可以用专门的宏表示,例如 C-c C-c、M-x 和 RET。现在 Loam 只允许直接渲染 kbd;未知 macro 会产生 deferred diagnostic。
时间戳也是语义节点:active timestamp 是 ,inactive timestamp 是 。
链接、锚点和跨页关系
普通外链可以直接写成 Org Mode。站内关系则来自 Org ID:这条 Majutsu 链接会让 Loam 生成 outgoing link、backlink 和 graph edge。
跨文章也不需要退回手写 URL。这里先用 建站文章 指向另一篇 Org 页面本身;再用 跨文章 fuzzy link 直接指向那篇文章里的具体 headline。两条链接指向同一页面,但属于两个独立的 backlink occurrence。
同一页也可以链接到稳定的 CUSTOM_ID,例如直接跳到 下面的表格示例。
Org 还有显式 target。这里放一个不可见但可寻址的 target,然后这条 fuzzy link 再跳回来。下面这个 radio target 属于另一种 Org 原生锚点类型,有自己的解析规则。
列表的多种结构
无序列表可以嵌套:
内容层
Org source
ox-edn Envelope
编译层
Loam index
link resolution
表现层
SvelteKit
static HTML
有序列表也保留顺序:
parse Org;
validate semantics;
resolve the corpus;
render artifacts。
Checkbox 状态保存在 item 节点上:
Org 仍然是 source of truth
语法覆盖仍在继续扩展
citation 和部分更少用的 Org 节点还没有进入 release-grade renderer
description list 则适合写术语:
ID全局稳定 UUID,用于
id:link。CUSTOM_ID人类可读的局部 anchor。
EXPORT_FILE_NAME发布路径,不承担内容身份。
Quote、verse、fixed-width 和 center
内容管线应该保留作者写下的结构,不满足于一段「看起来差不多」的文字。
Verse block 会保留人为控制的换行:
Org 是源, AST 是边界, 链接在 corpus 中重新相遇, 最后才轮到浏览器。
Fixed-width 很适合不需要 syntax highlighting、但又必须保留空白的文本:
Org
-> ox-edn
-> Loam
-> SvelteKit这一句来自 Org 的 center block,源码里没有手写 <div style="text-align:center">。
Callout / special block
Loam 通过 allowlist 约束 special block,当前允许 note、tip、warning、danger、experimental 和 compatibility。扩展语法因此有了明确边界。
LaTeX:让 Emacs 先把公式变成 SVG
LaTeX 在构建阶段完成排版。比如行内公式 会先交给 Org 的 LaTeX preview 系统,网页直接拿到 SVG,无需等待 MathJax 或 KaTeX。
Display math 也走同一条路径:
完整的 LaTeX environment 同样可以成为 Org AST 节点:
这里直接复用 Org 10 的 org-latex-preview-cache-images。它会根据 preamble、公式内容、转换器、背景和 equation number 等信息计算 preview key,然后查询 org-persist;只有 cache miss 才启动 LaTeX 和 dvisvgm。dvisvgm 生成的 SVG 又会把公式前景变成 currentColor,所以 Loam 可以严格清洗 SVG,再把它 inline 到正文中并继承网站的明暗主题。
缓存留在 Emacs/Org 的编译环境,SVG 进入最终内容产物。Envelope 里不会出现 ~/.config/emacs/.local/cache/org/persist/... 这样的本机路径。
Source block、example 和不同语言
Source block 会保留语言、font-lock face 和字符区间。构建时,Emacs 根据 org-src-get-lang-mode 选择 major mode,ox-edn 再把结果写进 Envelope;Loam 把这些区间安全地变成 span,网站主题决定颜色。下面的 Svelte 由我配置里的 svelte-ts-mode 处理:
(defun publish-current-org-file ()
"The real pipeline is deliberately less magical than this demo."
(interactive)
(message "Org -> ox-edn -> Loam -> SvelteKit"))
(-> documents
validate
partition-pages
build-index
resolve-links
render-page-fragments)
{#each page.backlinks as backlink}
<a href={backlink.route}>{backlink.title}</a>
{/each}
Example block 用于原样示例文本,其中的内容不需要语言高亮:
manifest.json search-index.json graph.json pages/*.html source/**/*.org
表格
Org table 会生成带有行列结构的 HTML table:
| 层 | 输入 | 输出 | 是否理解全站关系 |
|---|---|---|---|
| ox-edn | 单份 Org | Envelope v1 | 否 |
| Loam | 全部 Envelope | Manifest / Graph / HTML | 是 |
| SvelteKit | 编译产物 | Static site | 不重新解释 |
脚注
脚注也有自己的 AST 节点。比如这句话后面有一个具名脚注semantic-source,渲染器会根据节点生成脚注标记。
Horizontal rule,以及「隐藏也是语义」
上面这个 heading 的 source 里故意带了一个 drawer。Loam 知道它存在,但不会把内部 metadata 渲染进公开正文。它仍然保留在公开的 Org source 中。下面还有 Org comment 和 comment block,它们同样不会进入正文。
这条横线来自 Org horizontal rule 节点。