首页
/ bat 的 Markdown 高亮回归测试体系:从 example.md 源码样本到 ANSI 快照对比

bat 的 Markdown 高亮回归测试体系:从 example.md 源码样本到 ANSI 快照对比

2026-09-05 11:27:28作者:范垣楠Rhoda

bat 仓库为每种受支持的语法都维护了一对“源码样本 + 高亮快照”测试文件,tests/syntax-tests/ 下的 Markdown 目录是其中最具代表性的一个:它以一份覆盖 Markdown 全部常见语法要素的 example.md 为样本,验证 bat 基于 syntect 语法定义对 Markdown 的解析、作用域映射与 24 位色 ANSI 输出是否稳定。读完本文,你将理解 bat 如何用“快照比对”方式守护语法高亮的正确性,并能复现整套 Markdown 高亮测试流程。

测试样本的组织方式:source 与 highlighted 成对出现

Markdown 相关测试文件位于两处目录,一一对应:

每个样本按“语言目录/文件名”组织,这一约定由对比脚本固化下来:compare_highlighted_versions.py 中的 strip_root 函数只取 dirname/filename 两级路径作为比较键(见 tests/syntax-tests/compare_highlighted_versions.py 中的 strip_root 定义),也就是说 Markdown 的快照必须存放在以语言名命名的目录中才能被正确发现。

example.md 样本:一份覆盖 Markdown 语法全集的“考题”

example.md 全文仅 39 行,但每一行都在考核 Markdown 语法定义文件中的一类规则:

行号 样本内容 考核的语法要素
1–6 # H1###### H6 ATX 六级标题
8–9 **bold** *italic* ~~strike~~ ~~***link***~~__bold__ _italic_ 粗体、斜体、删除线、链接,含星号/下划线两种写法与嵌套强调
11–17 * Unordered 缩进列表、1. Ordered 有序列表 无序/有序列表及缩进层级
19 Markdown Logo 图片语法
21–22 > quotes 多行引用 块引用
24 `fn inline_code() ...` 行内代码
26–30 ```rust 围栏代码块(内含 Rust 函数) 围栏代码块的语言名识别与内嵌 Rust 高亮
32–34 - [x] Task GFM 任务列表
36–39 两列表格 GFM 表格

值得注意的两个细节:

  1. 第 26 行的围栏语言写的是 rust。bat 的 Markdown 补丁(后文详述)已把匹配规则放宽为 rust|rs,但样本仍用最常用的 rust 写法,保证快照反映主流用法;
  2. 代码块内容是合法的 Rust 代码 fn syntax_highlighted<T: AsRef<&str>>(thing: T)。Markdown 语法文件通过 embed 机制把代码围栏内部交给 Rust 语法处理,因此这段内容的高亮快照同时考验了“Markdown → 内嵌 Rust”的双层语法协作,是快照里彩色 token 最密集的区域。

高亮快照是怎么生成的:固定的 bat 选项与环境隔离

生成脚本 tests/syntax-tests/create_highlighted_versions.py 定义了所有语言(包括 Markdown)统一的高亮基准:

# Avoid 'default' theme because it can choose a different theme based on
# the appearance settings on macOS.
BAT_OPTIONS = [
    "--no-config",        # 忽略用户 bat 配置
    "--style=plain",       # 只输出纯内容,不带行号/文件头
    "--color=always",      # 强制输出 ANSI 色码
    "--theme=Monokai Extended",  # 固定主题,保证色彩可复现
    "--italic-text=always", # 固定斜体行为
]

每个选项都有明确目的:--no-config 排除个人配置干扰;固定 Monokai Extended 主题(主题文件位于 assets/themes/sublime-monokai-extended/)避免“default”主题随 macOS 明暗外观切换导致快照漂移;--style=plain 让快照只包含内容本身的着色,不含行号等 UI 装饰。

脚本还会主动清除一批环境变量:BAT_CACHE_PATHBAT_CONFIG_PATHBAT_OPTSBAT_THEMENO_COLORPAGER 等,并显式设置 COLORTERM=truecolor。这一步解释了快照文件的“长相”——highlighted/Markdown/example.md 中充满了 ESC[38;2;R;G;Bm 形式的 24 位真彩色码,例如标题行:

ESC[38;2;253;151;31m# ESC[0m...   ← H1 的 "H1" 用 RGB(253,151,31) 高亮

逐段观察该快照,可以读出 syntect 作用域到主题的映射结果:

  • ESC[38;2;253;151;31m(橙红):markup.heading 标题文本,出现 7 次,对应 H1–H6 共六行及标题样式;
  • ESC[1;38;2;249;38;114m(粗体红):markup.bold 粗体文本,如 bold 与嵌套强调中的粗体部分;
  • ESC[3;38;2;228;46;112m(斜体蓝绿):markup.italic,对应 italic、链接文本中的斜体段;
  • ESC[3;38;2;102;217;239m(斜体天蓝):块引用的 > quotes
  • ESC[38;2;236;53;51m(品红):行内代码 `fn inline_code()...`
  • ESC[38;2;190;132;255m(紫色关键字)与 ESC[38;2;230;219;116m(黄色字符串):rust 围栏内的 Rust 关键字与字符串字面量,证明内嵌语法确实生效;
  • ESC[4;38;2;166;226;46m(下划线绿色):链接/图片 URL。

这些色码不是手写的,而是“Markdown 语法定义 → 作用域 → 主题”链条的产物,因此快照漂移即意味着某个环节发生了变化。

Markdown 语法定义上的两个补丁:任务列表之外还藏了什么

bat 不直接使用上游 Sublime 的 Markdown 语法文件,而是通过补丁注入。assets/patches/Markdown.sublime-syntax.patch 在构建资源时由 assets/create.sh 应用(脚本遍历 patches/*.patch 执行 patch --strip=0),其中与测试直接相关的改动有两处:

  1. 围栏语言别名放宽rust 的匹配从 ((?i:rust)) 改为 ((?i:rust|rs)),即 ```rs 围栏同样触发 Rust 内嵌高亮;
  2. 新增 TypeScript 嵌入:补丁为 typescript|ts 增加了 embed: scope:source.ts 的围栏规则,这正是 source/Markdown/typescript.md 样本存在的原因——它验证 Markdown 内嵌 TypeScript 代码块能正确高亮。

补丁中还有一组较大的结构性调整:移除了原语法中 heading1/heading2 的 Setext 分支点(heading2-branchsetext_escape 变量等),把 Setext 标题识别简化为段落上下文中直接匹配 ===+ / ---+ 的写法,并顺带清理了粗斜体上下文里的 setext_escape 逃逸。这类改动的效果会在 example.md 快照中体现为标题/段落着色边界的变化,因此补丁更新后必须重新生成快照。

测试闭环:update.sh 与 regression_test.sh

整个 Markdown(以及其他语言)高亮测试由两个脚本驱动:

  • tests/syntax-tests/update.sh:调用 create_highlighted_versions.py -O highlighted 重新生成 highlighted/ 目录下全部快照。在语法文件、补丁或主题变更后用此脚本刷新基线;
  • tests/syntax-tests/regression_test.sh:回归验证入口。它先 mktemp -d 建临时目录,用当前 bat 重新高亮全部 source/ 样本,再调用 compare_highlighted_versions.py 与仓库中存储的 highlighted/ 快照做逐文件 unified diff:
output_directory=$(mktemp -d)
"$script_directory"/create_highlighted_versions.py --output="$output_directory"
"$script_directory"/compare_highlighted_versions.py \
    "$script_directory/highlighted" \
    "$output_directory"

比对脚本对每个文件输出 diff;只要任一对“旧快照 vs 新输出”存在差异,或新出现了没有快照的语言目录(输出 “No fixture for this language, run update.sh”),脚本即以退出码 1 失败。对 Markdown 而言,这意味着 highlighted/Markdown/example.md 中任何一个 ANSI 色码的变动都会使 CI 变红——这正是把“高亮效果”当作可回归资产的核心思想。

语法映射:.md 与 .mkd 如何被识别为 Markdown

样本文件名为 example.md,bat 对扩展名 .md 的识别来自随语法定义内置的扩展名列表;仓库另在 src/syntax_mapping/builtins/common/50-markdown.toml 中补充了一条常见别名映射:

[mappings]
"Markdown" = ["*.mkd"]

.mkd 扩展名同样映射到 Markdown 语法。这类 NN-name.toml 映射文件位于 src/syntax_mapping/builtins/common/ 等目录,bat 在运行时按文件名/扩展名将输入路由到对应的 syntect 语法,测试样本正是通过这条路由链才走到 Markdown 语法定义的。

小结

  • Markdown 在 bat 测试体系中的代表是 source/Markdown/example.md,它以 39 行覆盖标题、强调、链接、列表、引用、代码块、任务列表与表格;
  • 快照文件 highlighted/Markdown/example.md 是固定选项(--theme=Monokai Extended--style=plain--color=alwaysCOLORTERM=truecolor)下 bat 的 24 位色 ANSI 输出,逐色码即可审计“语法作用域 → 主题”的映射结果;
  • 语法行为由 assets/patches/Markdown.sublime-syntax.patch 定制(rust|rs 别名、TypeScript 嵌入、Setext 简化),由 assets/create.sh 在构建时应用;
  • 变更闭环为:改语法/补丁/主题 → update.sh 刷新快照 → regression_test.sh 保证后续每次构建的高亮输出与快照逐字节一致。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384