Sabaki 注释中的 Markdown 详解:支持的语法、自动链接机制与底层实现

发布时间:2026/10/14 17:32:37
Sabaki 注释中的 Markdown 详解:支持的语法、自动链接机制与底层实现 桌面应用【免费下载链接】SabakiAn elegant Go board and SGF editor for a more civilized age.项目地址https://gitcode.com/gh_mirrors/sa/Sabaki点击查看免费下载SabakiAn elegant Go board and SGF editor for a more civilized age在棋谱注释Comment中支持 Markdown 的一个实用子集并在此基础上扩展了 URL/邮箱自动链接、棋盘坐标识别、变招悬停预览和按手数跳转等围棋场景专属能力。本文以官方指南docs/guides/markdown.md为主体结合src/components/MarkdownContentDisplay.js、src/components/ContentDisplay.js等源码完整讲清 Sabaki 注释 Markdown 支持哪些语法、哪些写法被刻意禁用以及自动链接功能在渲染管线中的实现原理。Markdown 的应用位置注释框Sabaki 中所有对局节点SGF 树的每个 vertex都可以附带一段标题Title和一段注释文本Comment后者即以 Markdown 形式渲染。在源码中这条链路非常清晰注释输入与展示位于侧边栏的注释框组件 CommentBox编辑区是一个textarea渲染区通过h(MarkdownContentDisplay, {source: comment})将原始 Markdown 文本交给 MarkdownContentDisplay 处理MarkdownContentDisplay基于react-markdown当前仓库 package.json 中声明为^10.1.0渲染并挂上remark-breaks插件^4.0.0渲染出的每个文本节点再被包装进 ContentDisplay由它负责自动链接转换与交互事件绑定。因此Markdown 在 Sabaki 中的作用域就是对局注释标题栏Title不走 Markdown 解析只做排版符号替换。与标准 Markdown 的差异ChangesSabaki 支持的是 Markdown 的一个子集而非完整语法。如果你不熟悉 Markdown 基础语法可先阅读 John Gruber 的原始语法文档docs/guides/markdown.md中给出的建议。以下四点是与标准 Markdown 的关键差异换行不再需要行尾两个空格在标准 Markdown 中一个段落内的软换行要在行尾补两个空格才能变成br。Sabaki 通过挂载remark-breaks插件取消了这一要求// src/components/MarkdownContentDisplay.js remarkPlugins: [breaks],也就是说在注释里直接按 Enter 换行渲染结果就会真正换行这对在移动端或快速记谱场景下写注释非常友好。代码块不可用注释中书写代码块 围栏不会被渲染成代码样式。从源码结构看MarkdownContentDisplay的自定义组件映射中code被显式指向了Paragraph// src/components/MarkdownContentDisplay.js components: { // ... code: Paragraph, // ... }即代码标记退化为普通段落文本输出保留原始文字而不带code语义样式。这是面向围棋注释场景的取舍——注释中几乎不会出现代码。图片会被转换成链接MarkdownContentDisplay中定义了Image组件function Image({src, alt}) { return h(Link, {href: src}, typographer(alt)) }alt最终渲染为可点击的外部链接链接文本是 alt 部分而不会内嵌图片。这与HTML 输入不被允许的取向一致注释是纯文本增强不承担富媒体展示职责。不允许 HTML 输入注释中的 HTML 片段不会被执行或渲染为标签。实现分两层文本层ContentDisplay.render在把字符串注入 DOM 前先做转义——// src/components/ContentDisplay.js dangerouslySetInnerHTML: { __html: htmlify( content .replace(//g, amp;) .replace(//g, lt;) .replace(//g, gt;), ), },结构层react-markdown的html节点由自定义Html组件接住按纯文本输出为段落或行内 spanfunction Html({isBlock, value}) { return h(isBlock ? Paragraph : span, {}, value) }两层配合保证了注释内容无法注入可执行 HTML。自动链接Auto linking官方文档中Auto linking一节描述的三类自动链接能力全部实现在ContentDisplay顶部的htmlify函数里。该函数用一组正则把纯文本中出现的模式替换为带特定 class 的 HTML 片段// src/components/ContentDisplay.js let urlRegex /\b(ht|f)tps?:\/\/[^\s][^.,:;\)\]\s](\/\B|\b)/i let emailRegex /\b[^\s][^\s]\b/i let variationRegex /\b(black\s?|white\s?|[bw]\s*)(([a-hj-z]\d{1,2}[ ])[a-hj-z]\d{1,2})\b/i let coordRegex /\b[a-hj-z]\d{1,2}\b/i let movenumberRegex /(\B#|\bmove[ ])(\d)\b/iURL 与邮箱任意http://、https://、ftp://、ftps://开头的 URL 自动变成a classcomment-external点击时通过shell.openExternal在系统浏览器中打开不占用 Electron 主窗口形如namedomain的邮箱地址自动变成mailto:链接。棋盘坐标coordRegex匹配a1–z99中除掉 i 列后的坐标写法[a-hj-z]\d{1,2}符合 SGF 无 i 列的坐标习惯生成span classcomment-coord。鼠标悬停时触发this.handleCoordMouseEnter (evt) { let {board} sabaki.inferredState let vertex board.parseVertex(evt.currentTarget.innerText) sabaki.setState({highlightVertices: [vertex]}) }即在棋盘上高亮该点——这正是文档中Hovering over them will show the position on the board的实现。悬停样式黑底、高亮变蓝定义在 style/index.css 的.comment-coord:hover规则中。变招序列VariationvariationRegex额外识别坐标串可选带black/white/b/w前缀指定行棋方例如b qk rl、white fc gd。匹配结果生成span classcomment-variation>a href# classcomment-movenumber titleJump to Move Number >} else if (linkElement.classList.contains(comment-movenumber)) { evt.preventDefault() let moveNumber linkElement.dataset.movenumber sabaki.goToMainVariation() sabaki.goToMoveNumber(moveNumber) }两条跳转函数均在 src/modules/sabaki.js 中goToMainVariation()约 L1752若当前位置不在主变上则沿parentId向上回溯到主变节点并定位保证跳到第 N 手始终落在主变线上goToMoveNumber(number)约 L1604对非法值NaN直接返回负数按 0 处理然后从树根出发调用tree.navigate(root, Math.round(number))定位第 N 手若手数超出主变长度返回null则回退为goToEnd()跳至末尾。所以#127的完整语义是先回到主变再前进到第 127 手若不存在则停在主变终点。排版细节typographer 智能引号Sabaki 渲染管线中还有一个容易被忽略的细节MarkdownContentDisplay在把字符串交给ContentDisplay之前会先经过typographer函数处理。该函数定义在 src/modules/utils.js由 src/modules/helper.js 再导出export function typographer(input) { return input .replace(/\.{3}/g, \u2026) // ... → … .replace(/(\S)/g, $1\u2019) // 右单引号 .replace(/(\S)/g, $1\u201d) // 右双引号 .replace(/(\S)/g, \u2018$1) // 左单引号 .replace(/(\S)/g, \u201c$1) // 左双引号 .replace(/(\s)-(\s)/g, $1\u2013$2) // 词间 - → – }注释与标题中书写的直引号、三连点省略号、词间连字符会被统一替换为排版符号、、、、…、–让注释文本更接近出版级排版。注意这是无方向的启发式替换依据引号前后的非空白字符判断左右并不区分语言。注释的编辑与提交时机了解 Markdown 渲染的同时也需要了解注释文本何时被写回对局树CommentBox对输入做防抖每次input事件后等待comments.commit_delay毫秒默认 500见 src/setting.js 的comments.commit_delay: 500才调用onCommentInput把{title, comment}提交给对局树失焦blur则立即提交。因此注释的 Markdown 渲染在编辑过程中是编辑区实时文本 展示区防抖刷新的双轨状态偏好项comments.show_move_interpretation默认true控制节点没有自定义 Title 时是否自动显示由sabaki/boardmatcher计算出的手名如角部定式名称、N 点等该提示文本出现在注释框标题位置一个实用技巧在编辑模式下 Ctrl点击棋盘某点会把该点坐标自动追加进当前节点的注释——这样得到的坐标文本随后就会命中上文所述的coordRegex自动高亮逻辑。端到端测试 e2e/comment-coordinate.spec.js对应 issue #844专门验证了追加坐标后注释文本框能正确刷新并随节点提交是回归验证这条工作流的关键用例。小结Sabaki 注释 Markdown 的设计可以概括为三句话支持子集段落、强调、删除线、表格、列表、标题等常规语法可用且换行免双空格代码块退化为纯文本图片转为链接HTML 一律按文本转义围棋特化坐标、变招序列、手数#N/move N三类模式由htmlify的正则识别为可交互元素分别映射到棋盘高亮、变招回放和主变跳转可追溯从CommentBox→MarkdownContentDisplayreact-markdown remark-breaks 自定义组件→ContentDisplay正则链接化 事件委托→sabaki.goToMoveNumber/goToMainVariation的调用链完整落在仓库源码中读者可以按上文列出的文件路径逐层对照。赞分享桌面应用【免费下载链接】SabakiAn elegant Go board and SGF editor for a more civilized age.项目地址https://gitcode.com/gh_mirrors/sa/Sabaki点击查看免费下载相关推荐绳网社区功能扩展指南如何轻松添加新的游戏讨论板块 绳网社区功能扩展指南如何轻松添加新的游戏讨论板块 绳网是一个专注于游戏和技术交流的开源社区平台为玩家提供了畅所欲言的交流空间。在这篇 绳网社区功能扩展StarRocks DATE 函数详解语法、用法与底层实现StarRocks DATE 函数详解语法、用法与底层实现 本文深入解析 StarRocks 中的 DATE 函数如何从 DATETIME 或 DATE 表数据库OLAP数据仓库大数据湖仓一体数据分析Puppeteer asyncDisposeSymbolTypeScript await using 自动释放资源的底层机制解析Puppeteer asyncDisposeSymbolTypeScript await using 自动释放资源的底层机制解析 asyncDisposeSy浏览器控制测试网页爬虫开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询