功能全览:自动格式化的魔法
学完你能做什么
- 了解插件的 8 大核心功能
- 知道哪些场景适合用这个插件
- 明白插件的边界在哪里(不能做什么)
你现在的困境
插件信息
本插件全名为 @franlol/opencode-md-table-formatter,以下简称"表格格式化插件"。
AI 生成的 Markdown 表格经常是这样的:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |列宽参差不齐,看着难受。手动调整?每次 AI 生成新表格都要调一遍,太累了。
什么时候用这一招
- AI 生成了 Markdown 表格,你想让它更整齐
- 你开启了 OpenCode 的隐藏模式(Concealment Mode),表格对齐总是出问题
- 你懒得手动调整表格列宽
核心思路
这个插件的工作原理很简单:
AI 生成文本 → 插件检测表格 → 验证结构 → 格式化 → 返回美化后的文本它挂载在 OpenCode 的 experimental.text.complete 钩子上,AI 每次生成完文本,插件就自动处理。你不需要手动触发,全程无感。
8 大核心功能
1. 自动表格格式化
插件会自动检测 AI 生成文本中的 Markdown 表格,统一列宽,让表格整齐美观。
格式化前:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |格式化后:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |触发条件
插件挂载在 experimental.text.complete 钩子上,AI 生成文本完成后自动触发,无需手动操作。
2. 隐藏模式兼容
OpenCode 默认开启隐藏模式(Concealment Mode),会隐藏 Markdown 符号(如 **、*、~~)。
普通的表格格式化工具不考虑这一点,计算宽度时会把 ** 也算进去,导致对齐错位。
这个插件专门为隐藏模式优化:
- 计算宽度时,剥离
**粗体**、*斜体*、~~删除线~~等符号 - 输出时保留原始 Markdown 语法
- 最终效果:隐藏模式下表格完美对齐
技术细节:宽度计算逻辑
// 剥离 Markdown 符号(用于宽度计算)
visualText = visualText
.replace(/\*\*\*(.+?)\*\*\*/g, "$1") // ***粗斜体*** → 文本
.replace(/\*\*(.+?)\*\*/g, "$1") // **粗体** → 粗体
.replace(/\*(.+?)\*/g, "$1") // *斜体* → 斜体
.replace(/~~(.+?)~~/g, "$1") // ~~删除线~~ → 删除线源码位置:index.ts:181-185
3. 对齐支持
支持 Markdown 表格的三种对齐方式:
| 语法 | 对齐方式 | 效果 |
|---|---|---|
--- 或 :--- | 左对齐 | 文本靠左(两种语法效果相同) |
:---: | 居中 | 文本居中 |
---: | 右对齐 | 文本靠右 |
示例:
| 左对齐 | 居中 | 右对齐 |
|--- | --- | ---|
| 文本 | 文本 | 文本 |格式化后,每列会按指定方式对齐,分隔行会根据对齐方式重新生成。
4. 嵌套 Markdown 处理
表格单元格里可能有嵌套的 Markdown 语法,比如 ***粗斜体***。
插件使用多轮正则算法,从外到内逐层剥离:
***粗斜体*** → **粗斜体** → *粗斜体* → 粗斜体这样即使嵌套多层,宽度计算也是准确的。
5. 代码块保护
行内代码(用反引号包裹)里的 Markdown 符号应该保持原样,不被剥离。
比如 `**bold**`,用户看到的就是 **bold** 这 8 个字符,而不是 bold 这 4 个字符。
插件会先提取代码块内容,剥离其他部分的 Markdown 符号后,再把代码块内容放回去。
技术细节:代码块保护逻辑
// 第 1 步:提取并保护行内代码
const codeBlocks: string[] = []
let textWithPlaceholders = text.replace(/`(.+?)`/g, (match, content) => {
codeBlocks.push(content)
return `\x00CODE${codeBlocks.length - 1}\x00`
})
// 第 2 步:剥离非代码部分的 Markdown 符号
// ...
// 第 3 步:恢复行内代码内容
visualText = visualText.replace(/\x00CODE(\d+)\x00/g, (match, index) => {
return codeBlocks[parseInt(index)]
})源码位置:index.ts:168-193
6. 边界情况处理
插件能正确处理各种边界情况:
| 场景 | 处理方式 |
|---|---|
| Emoji 表情 | 使用 Bun.stringWidth 正确计算显示宽度 |
| Unicode 字符 | 中文、日文等宽字符正确对齐 |
| 空单元格 | 填充空格到最小宽度(3 字符) |
| 超长内容 | 正常处理,不截断 |
7. 静默操作
插件在后台静默运行:
- 无日志输出:不会在控制台打印任何信息
- 错误不中断:即使格式化失败,也不会影响 AI 的正常输出
如果格式化过程中出错,插件会保留原文,并在末尾添加一条 HTML 注释:
<!-- table formatting failed: [错误信息] -->8. 验证反馈
插件会验证表格结构是否有效。无效的表格不会被格式化,而是保留原样,并添加提示:
<!-- table not formatted: invalid structure -->有效表格的要求:
- 至少 2 行(含分隔行)
- 所有行的列数一致
- 必须有分隔行(格式:
|---|---|)
插件的边界
不支持的场景
- HTML 表格:只处理 Markdown 管道表格(
| ... |) - 多行单元格:含
<br>标签的单元格不支持 - 无分隔行表格:必须有
|---|---|分隔行 - 无表头表格:必须有表头行
检查点
完成本课后,你应该能回答:
- [ ] 插件是如何自动触发的?(答:
experimental.text.complete钩子) - [ ] 为什么需要"隐藏模式兼容"?(答:隐藏模式会隐藏 Markdown 符号,影响宽度计算)
- [ ] 行内代码里的 Markdown 符号会被剥离吗?(答:不会,代码内的 Markdown 符号会被完整保留)
- [ ] 无效表格会怎么处理?(答:保留原样,添加错误注释)
本课小结
| 功能 | 说明 |
|---|---|
| 自动格式化 | AI 生成完文本自动触发,无需手动操作 |
| 隐藏模式兼容 | 正确计算 Markdown 符号隐藏后的显示宽度 |
| 对齐支持 | 左对齐、居中、右对齐 |
| 嵌套 Markdown | 多轮正则剥离,支持嵌套语法 |
| 代码块保护 | 行内代码中的符号保持原样 |
| 边界情况 | Emoji、Unicode、空单元格、超长内容 |
| 静默操作 | 无日志,错误不中断 |
| 验证反馈 | 无效表格添加错误注释 |
下一课预告
下一课我们深入 隐藏模式原理。
你会学到:
- OpenCode 隐藏模式的工作原理
- 插件如何正确计算显示宽度
Bun.stringWidth的作用
附录:源码参考
点击展开查看源码位置
更新时间:2026-01-26
| 功能 | 文件路径 | 行号 |
|---|---|---|
| 插件入口 | index.ts | 9-23 |
| 表格检测 | index.ts | 58-61 |
| 表格验证 | index.ts | 70-88 |
| 宽度计算(隐藏模式) | index.ts | 161-196 |
| 对齐方式解析 | index.ts | 141-149 |
| 代码块保护 | index.ts | 168-173 |
关键常量:
colWidths[col] = 3:列最小宽度为 3 字符(index.ts:115)
关键函数:
formatMarkdownTables():主处理函数,格式化文本中的所有表格getStringWidth():计算字符串显示宽度,剥离 Markdown 符号isValidTable():验证表格结构是否有效