代码高亮自研替换:20套配色(10浅+10深)、语言标签、复制不带行号、评论可贴代码 #11

Closed
opened 2026-10-26 00:22:31 +00:00 by laoyang · 4 comments
Owner

背景

站内代码高亮目前依赖别人写的插件(Enlighter / wp-editormd 残留 + 主题里一段 Prism 兜底),
存在三个问题:深色配色印在浅色底上导致大量 token 看不见、复制会带行号、评论里根本贴不了代码。
本次自研替换:用 highlight.js 自托管,主题侧统一接管,并打通评论区的代码输入与展示。

需求拆解

1. 配色 20 套 = 浅色 10 + 深色 10

深色组必须存在,理由:技术文章里把代码块做成深色能压住浅色正文,突出代码;
同一篇文章同时给 Python 和 Java 两种实现时也靠配色区分阅读节奏。

若 10+10 不好取舍,可退为 14 浅 + 6 深;但优先 10+10。

2. 行号

  • 默认关闭。
  • 行号由纯 CSS 计数器绘制,因此天然不会进入复制内容 —— 这是本次"复制不带行号"的实现方式,
    不需要额外开关,也不需要任何后处理。
  • 逐行对比由用户用自己习惯的工具完成,产品侧不做行号对齐/差异高亮。

3. 复制按钮

  • 默认开启(可关)。
  • 复制内容 = 纯代码:无 HTML 标签、无行号、缩进与换行原样。
  • navigator.clipboard 只在安全上下文可用,HTTP 下必须退回 execCommand。

4. 自动识别语言

  • 必须做成用户可选开关,默认开启。
  • 做成选项的理由(本人确认):历史文章里存在没写语言标记的代码块,自动识别能兜住大部分;
    但识别本身会出错,所以必须让用户能关掉、回退成纯文本。
  • 识别结果与作者手标的语言必须在视觉上可区分(虚线边框 + 斜体),
    不能把猜测伪装成事实。
  • 有标记的代码块永远按标记走,自动识别只对无标记块生效。

5. 代码语言标签(新增)

代码块左上角直接显示语言名(Java / Python / YAML…)。

场景:同一篇文章同时给出多语言实现,读者容易复制错;标签在复制按钮旁边,
一眼能确认"我复制的是哪一种"。

6. 评论也要能贴代码(新增)

  • 评论工具条现有 加粗 / 斜体 / 颜色 / 表情,在其后增加一个代码按钮。
  • 点代码按钮 → 选语言 → 插入代码块;评论区正常渲染高亮。
  • 需要同时改三处:kses 白名单放行 pre 与 code[class]、
    序列化器保留代码块结构、评论样式表补代码块外观。

验收标准

  1. 20 套配色两两可区分,深色组代码块自带深色底(不出现浅底浅字)。
  2. 复制结果与页面代码逐字一致(换行归一化后),不含行号、不含标签。
  3. 行号开关、复制按钮开关、自动识别开关三者各自生效,互不干扰;反复拨动不累积、不错乱。
  4. 有语言标记的块标签为实线边框;自动识别得到的标签为虚线边框 + 斜体。
  5. 作者未标语言的代码块在自动识别开启时被上色,关闭时回退纯文本且标签隐藏。
  6. 评论提交含代码块时:pre 不被剥掉、class="language-xxx" 不被剥掉、
    不被 wpautop 套 <p> 折叠缩进、引号不变弯、URL 不变链接。
  7. 触屏设备(hover: none)下复制按钮常驻可见。
  8. 窄屏(390px)无横向溢出,长代码行横向滚动而非任意字符断行。

实现范围

主题侧:

  • 新增 inc/theme-highlight.php:语言注册、别名映射(text → plaintext 为必需,
    站内 47 个代码块用 text)、渲染包装(语言标签 + 复制按钮 + 作用域类)。
  • footer.php 移除现有 Prism 兜底段。
  • inc/theme-options.php 增加三个选项。
  • 代码块样式重写:现有 word-break: break-all 必须改掉(会在任意字符断行,代码像乱码)。

评论侧:

  • comments.php 工具条加代码按钮 + 语言选择面板。
  • assets/js/comments.js 扩展 serializeEditor() 保留代码块。
  • inc/theme-comments.php 扩展 kses 白名单。

发布方式

只走 /theme-update/ 更新通道(zip + readme + update.json),不覆盖服务器主题目录。

## 背景 站内代码高亮目前依赖别人写的插件(Enlighter / wp-editormd 残留 + 主题里一段 Prism 兜底), 存在三个问题:深色配色印在浅色底上导致大量 token 看不见、复制会带行号、评论里根本贴不了代码。 本次自研替换:用 highlight.js 自托管,主题侧统一接管,并打通评论区的代码输入与展示。 ## 需求拆解 ### 1. 配色 20 套 = 浅色 10 + 深色 10 深色组必须存在,理由:技术文章里把代码块做成深色能压住浅色正文,突出代码; 同一篇文章同时给 Python 和 Java 两种实现时也靠配色区分阅读节奏。 若 10+10 不好取舍,可退为 14 浅 + 6 深;但优先 10+10。 ### 2. 行号 - **默认关闭**。 - 行号由纯 CSS 计数器绘制,因此**天然不会进入复制内容** —— 这是本次"复制不带行号"的实现方式, 不需要额外开关,也不需要任何后处理。 - 逐行对比由用户用自己习惯的工具完成,产品侧不做行号对齐/差异高亮。 ### 3. 复制按钮 - **默认开启**(可关)。 - 复制内容 = 纯代码:无 HTML 标签、无行号、缩进与换行原样。 - `navigator.clipboard` 只在安全上下文可用,HTTP 下必须退回 `execCommand`。 ### 4. 自动识别语言 - **必须做成用户可选开关**,默认开启。 - 做成选项的理由(本人确认):历史文章里存在没写语言标记的代码块,自动识别能兜住大部分; 但识别本身会出错,所以必须让用户能关掉、回退成纯文本。 - 识别结果与作者手标的语言必须在视觉上可区分(虚线边框 + 斜体), 不能把猜测伪装成事实。 - 有标记的代码块永远按标记走,自动识别只对无标记块生效。 ### 5. 代码语言标签(新增) 代码块左上角直接显示语言名(`Java` / `Python` / `YAML`…)。 场景:同一篇文章同时给出多语言实现,读者容易复制错;标签在复制按钮旁边, 一眼能确认"我复制的是哪一种"。 ### 6. 评论也要能贴代码(新增) - 评论工具条现有 加粗 / 斜体 / 颜色 / 表情,在其后增加一个**代码按钮**。 - 点代码按钮 → 选语言 → 插入代码块;评论区正常渲染高亮。 - 需要同时改三处:kses 白名单放行 `pre` 与 `code[class]`、 序列化器保留代码块结构、评论样式表补代码块外观。 ## 验收标准 1. 20 套配色两两可区分,深色组代码块自带深色底(不出现浅底浅字)。 2. 复制结果与页面代码逐字一致(换行归一化后),不含行号、不含标签。 3. 行号开关、复制按钮开关、自动识别开关三者各自生效,互不干扰;反复拨动不累积、不错乱。 4. 有语言标记的块标签为实线边框;自动识别得到的标签为虚线边框 + 斜体。 5. 作者未标语言的代码块在自动识别开启时被上色,关闭时回退纯文本且标签隐藏。 6. 评论提交含代码块时:`pre` 不被剥掉、`class="language-xxx"` 不被剥掉、 不被 `wpautop` 套 `<p>` 折叠缩进、引号不变弯、URL 不变链接。 7. 触屏设备(`hover: none`)下复制按钮常驻可见。 8. 窄屏(390px)无横向溢出,长代码行横向滚动而非任意字符断行。 ## 实现范围 主题侧: - 新增 `inc/theme-highlight.php`:语言注册、别名映射(`text` → `plaintext` 为必需, 站内 47 个代码块用 `text`)、渲染包装(语言标签 + 复制按钮 + 作用域类)。 - `footer.php` 移除现有 Prism 兜底段。 - `inc/theme-options.php` 增加三个选项。 - 代码块样式重写:现有 `word-break: break-all` 必须改掉(会在任意字符断行,代码像乱码)。 评论侧: - `comments.php` 工具条加代码按钮 + 语言选择面板。 - `assets/js/comments.js` 扩展 `serializeEditor()` 保留代码块。 - `inc/theme-comments.php` 扩展 kses 白名单。 ## 发布方式 只走 `/theme-update/` 更新通道(zip + readme + update.json),**不覆盖服务器主题目录**。
Author
Owner

补充 1:开工前的全站实测结论

按要求,开工前把站内全部文章、页面、评论遍历了一遍。以下都是实测数字,不是估算。

站点规模

项 数量
文章 967
页面 11
评论 8585
含代码块的文章 71
代码块总数 284

代码块的 HTML 形态(最关键的一组数据)

形态 数量 占比
<pre><code class="language-xxx"> 标准形态 204 71.8%
裸 <pre>(没有 <code> 子元素) 80 28.2%

裸 pre 这 80 个是实现硬要求:只处理 pre code 会整块漏掉近三成。
用户已关闭 Enlighter(实测已不在 active_plugins 里),现在只剩 wp-editormd 启用中,
它产出的历史内容正是这种裸 pre 形态。

现有语言标记分布

bash 131、text 47、yaml 11、python 8、json 4、javascript 1、shell 1、sql 1。

⚠️ text 这 47 个必须做别名映射到 plaintext。hljs 没有 text 这个语言名,
不映射的话这 47 块会全部落到"未知语言"分支、静默不上色,而且不报错。

覆盖率

可处理 267 / 284 = 94.0%。剩下 17 个(6.0%)逐个查明:

  • 8 个是空代码块(0 行内容)
  • 9 个是一行短命令(gitlab-ctl reconfigure、su -、dpkg-reconfigure locales 等)

没有一个是"应该高亮却被漏掉的真实代码"。

行数分布

1 行 186(65.5%)、2–3 行 33、4–10 行 39、11–30 行 14、31–100 行 3、100 行以上 1。

六成半的代码块是一行命令 —— 这类块开不开自动识别差别很小,所以自动识别默认开启的代价很低。

自动识别的真实准确率(这是要不要做成选项的关键依据)

取 18 个 ≥4 行、且作者没标语言的代码块,用真 hljs 跑 highlightAuto():

实际内容 识别成 置信度
LaTeX 140 行 ruby 127
Java Servlet 61 行 java 82 ✓
LaTeX 32 行 shell 2
JavaScript 22 行 javascript 18 ✓
命令行输出 18 行 swift 27
apt 错误 14 行 swift 18
GitLab Ruby 13 行 go 25
debian sources 12 行 ruby 21
Java 片段 12 行 kotlin 11
JavaScript 10 行 javascript 10 ✓
Java 片段 9 行 kotlin 10
deb … 8 行 cpp 13
JavaScript 7 行 csharp 7
Java Servlet 6 行 csharp 6
augury 输出 5 行 bash 1
locales 配置 4 行 无 0
git 报错 4 行 sql 3
PHP 报错 4 行 php 13 ✓

18 个只对 4 个(22%)。

另有两条实测结论值得记录:

  1. 置信度(relevance)不能当阈值用。LaTeX 140 行置信 127 是错的,PHP 报错置信 13 是对的。
    所以不能"低于某个置信度就不上色"。
  2. 这正好印证了把自动识别做成用户可关选项的必要性 —— 如果默认强制开且无法关闭,
    等于给这批老文章贴上 78% 的错误标签。

语言标签的实证价值

  • 19 篇文章含 ≥2 种语言
  • 相邻两个代码块语言不同 38 处(如 bash→python、python→json)

这直接支撑了"代码块左上角显示语言标签"这个需求:确实存在读者会复制错的实际场景。

补充 2:评论区的现状(已用真实 WP 7.1.3 验证)

当前访客在评论里贴不了代码,三层都会坏:

环节 现状
kses 白名单 pre 不在白名单(整条被剥掉);code 在,但任何属性都会被剥,包括 class
wpautop 没有 pre 兜着时会套 <p>,而 <p> 的 white-space: normal 会把连续空格折叠成一个,缩进全丢
wptexturize 把 ' 变成 &#8217;、-- 变成 &#8212;、" 变成弯引号 —— 代码直接跑不了
make_clickable 把代码里的 URL 包成 <a href rel="nofollow">,复制出来全是 HTML

后两条是最容易忽略的:wptexturize 和 make_clickable 只在没有 pre 包裹时才破坏内容,
一旦 pre 进了白名单,二者都会被 pre 挡住。已用真实 WP 核心跑通完整链路(11 条判据全通过):
pre 保住、class 保住、无 <p>、无 <br>、缩进保留、引号不变弯、无 <a>、-- 不变 en dash。

补充 3:实现时必须改掉的两处现有样式

assets/css/kratos.css 986–1035 行:

.k-main .details .article .content pre {
  background-color: #f8f8f8;   /* 浅灰底 —— 深色配色印在上面,11 类 token 看不见 */
  font-size: 11px;             /* 偏小 */
  word-break: break-all;       /* ★ 在任意字符处断行,代码看起来像乱码 */
}

word-break: break-all 必须改成 white-space: pre + overflow-x: auto,
长行横向滚动而不是折断。

补充 4:原型已可交互验证

原型页已做出来并跑通验收(含反向验证),覆盖:

  • 20 套配色可切换,深色组代码块自带深色底
  • 语言标签在左上角;自动识别得到的标签用虚线边框 + 斜体,与作者手标的实线区分
  • 复制按钮:真点、真读剪贴板,内容与页面逐字一致、无标签、无行号
  • 行号开关打开后复制,结果与关闭时完全一致(结构保证:行号在 <pre> 之外)
  • 触屏 hover: none 下复制按钮常驻
  • 390px 窄屏无横向溢出

验收过程中发现并修掉两个真实缺陷(都不是判据问题,是实现真的坏了):

  1. 行号一行都没画出来 —— 原方案用 span.line::before 计数器,
    但 hljs 输出的是 token span,没有行结构,span.line 根本不存在。
    而当时的判据只查"CSS 里有 counter-increment 规则"和"body 有 opt-ln 类"两件书面证据,
    双双通过、画面空白。已改成 <pre> 之外的独立行号槽。
  2. 触屏兜底是空操作 —— 原来写 @media (hover: none) { opacity: 1 },
    但桌面端从未设过 opacity: 0,1 就是默认值,这条规则删掉也不会有任何变化。
    已改为默认隐藏、hover 显示、触屏覆盖回可见。

另外量出一起几何错位:hljs 每套官方主题都自带 pre code.hljs{padding:1em},
把代码整体压低 15.5px,行号槽没跟着压,屏幕上第一行代码旁边写着 2。
已归零该 padding,现在逐行坐标偏差 0.00px。

## 补充 1:开工前的全站实测结论 按要求,开工前把站内全部文章、页面、评论遍历了一遍。以下都是实测数字,不是估算。 ### 站点规模 | 项 | 数量 | |---|---| | 文章 | 967 | | 页面 | 11 | | 评论 | 8585 | | 含代码块的文章 | 71 | | 代码块总数 | 284 | ### 代码块的 HTML 形态(最关键的一组数据) | 形态 | 数量 | 占比 | |---|---|---| | `<pre><code class="language-xxx">` 标准形态 | 204 | 71.8% | | **裸 `<pre>`(没有 `<code>` 子元素)** | **80** | **28.2%** | 裸 `pre` 这 80 个是**实现硬要求**:只处理 `pre code` 会整块漏掉近三成。 用户已关闭 Enlighter(实测已不在 active_plugins 里),现在只剩 wp-editormd 启用中, 它产出的历史内容正是这种裸 `pre` 形态。 ### 现有语言标记分布 `bash` 131、**`text` 47**、`yaml` 11、`python` 8、`json` 4、`javascript` 1、`shell` 1、`sql` 1。 ⚠️ `text` 这 47 个必须做别名映射到 `plaintext`。hljs 没有 `text` 这个语言名, 不映射的话这 47 块会全部落到"未知语言"分支、静默不上色,而且不报错。 ### 覆盖率 可处理 267 / 284 = **94.0%**。剩下 17 个(6.0%)逐个查明: - 8 个是空代码块(0 行内容) - 9 个是一行短命令(`gitlab-ctl reconfigure`、`su -`、`dpkg-reconfigure locales` 等) **没有一个是"应该高亮却被漏掉的真实代码"。** ### 行数分布 1 行 186(65.5%)、2–3 行 33、4–10 行 39、11–30 行 14、31–100 行 3、100 行以上 1。 六成半的代码块是一行命令 —— 这类块开不开自动识别差别很小,所以自动识别默认开启的代价很低。 ### 自动识别的真实准确率(这是要不要做成选项的关键依据) 取 18 个 ≥4 行、且作者没标语言的代码块,用真 hljs 跑 `highlightAuto()`: | 实际内容 | 识别成 | 置信度 | |---|---|---| | LaTeX 140 行 | ruby | 127 | | Java Servlet 61 行 | java | 82 ✓ | | LaTeX 32 行 | shell | 2 | | JavaScript 22 行 | javascript | 18 ✓ | | 命令行输出 18 行 | swift | 27 | | apt 错误 14 行 | swift | 18 | | GitLab Ruby 13 行 | go | 25 | | debian sources 12 行 | ruby | 21 | | Java 片段 12 行 | kotlin | 11 | | JavaScript 10 行 | javascript | 10 ✓ | | Java 片段 9 行 | kotlin | 10 | | `deb …` 8 行 | cpp | 13 | | JavaScript 7 行 | csharp | 7 | | Java Servlet 6 行 | csharp | 6 | | augury 输出 5 行 | bash | 1 | | locales 配置 4 行 | 无 | 0 | | git 报错 4 行 | sql | 3 | | PHP 报错 4 行 | php | 13 ✓ | **18 个只对 4 个(22%)**。 另有两条实测结论值得记录: 1. **置信度(relevance)不能当阈值用**。LaTeX 140 行置信 127 是错的,PHP 报错置信 13 是对的。 所以不能"低于某个置信度就不上色"。 2. 这正好印证了把自动识别做成用户可关选项的必要性 —— 如果默认强制开且无法关闭, 等于给这批老文章贴上 78% 的错误标签。 ### 语言标签的实证价值 - 19 篇文章含 ≥2 种语言 - **相邻两个代码块语言不同 38 处**(如 `bash→python`、`python→json`) 这直接支撑了"代码块左上角显示语言标签"这个需求:确实存在读者会复制错的实际场景。 ## 补充 2:评论区的现状(已用真实 WP 7.1.3 验证) 当前访客在评论里**贴不了代码**,三层都会坏: | 环节 | 现状 | |---|---| | kses 白名单 | `pre` **不在**白名单(整条被剥掉);`code` 在,但**任何属性都会被剥**,包括 `class` | | `wpautop` | 没有 `pre` 兜着时会套 `<p>`,而 `<p>` 的 `white-space: normal` 会把连续空格折叠成一个,缩进全丢 | | `wptexturize` | 把 `'` 变成 `&#8217;`、`--` 变成 `&#8212;`、`"` 变成弯引号 —— **代码直接跑不了** | | `make_clickable` | 把代码里的 URL 包成 `<a href rel="nofollow">`,复制出来全是 HTML | 后两条是最容易忽略的:`wptexturize` 和 `make_clickable` **只在没有 `pre` 包裹时**才破坏内容, 一旦 `pre` 进了白名单,二者都会被 `pre` 挡住。已用真实 WP 核心跑通完整链路(11 条判据全通过): `pre` 保住、`class` 保住、无 `<p>`、无 `<br>`、缩进保留、引号不变弯、无 `<a>`、`--` 不变 en dash。 ## 补充 3:实现时必须改掉的两处现有样式 `assets/css/kratos.css` 986–1035 行: ```css .k-main .details .article .content pre { background-color: #f8f8f8; /* 浅灰底 —— 深色配色印在上面,11 类 token 看不见 */ font-size: 11px; /* 偏小 */ word-break: break-all; /* ★ 在任意字符处断行,代码看起来像乱码 */ } ``` `word-break: break-all` 必须改成 `white-space: pre` + `overflow-x: auto`, 长行横向滚动而不是折断。 ## 补充 4:原型已可交互验证 原型页已做出来并跑通验收(含反向验证),覆盖: - 20 套配色可切换,深色组代码块自带深色底 - 语言标签在左上角;**自动识别得到的标签用虚线边框 + 斜体**,与作者手标的实线区分 - 复制按钮:真点、真读剪贴板,内容与页面逐字一致、无标签、无行号 - 行号开关打开后复制,结果与关闭时完全一致(结构保证:行号在 `<pre>` 之外) - 触屏 `hover: none` 下复制按钮常驻 - 390px 窄屏无横向溢出 验收过程中发现并修掉两个真实缺陷(都不是判据问题,是实现真的坏了): 1. **行号一行都没画出来** —— 原方案用 `span.line::before` 计数器, 但 hljs 输出的是 token span,**没有行结构**,`span.line` 根本不存在。 而当时的判据只查"CSS 里有 counter-increment 规则"和"body 有 opt-ln 类"两件书面证据, 双双通过、画面空白。已改成 `<pre>` 之外的独立行号槽。 2. **触屏兜底是空操作** —— 原来写 `@media (hover: none) { opacity: 1 }`, 但桌面端从未设过 `opacity: 0`,`1` 就是默认值,这条规则删掉也不会有任何变化。 已改为默认隐藏、hover 显示、触屏覆盖回可见。 另外量出一起**几何错位**:hljs 每套官方主题都自带 `pre code.hljs{padding:1em}`, 把代码整体压低 15.5px,行号槽没跟着压,屏幕上第一行代码旁边写着 2。 已归零该 padding,现在逐行坐标偏差 0.00px。
Author
Owner

实现完成 + 验收结果

一、按需求逐项对照

1. 20 套主题 = 浅色 10 + 深色 10

按用户原话"10 套浅色、10 套深色是比较好的配置"直接做成 10+10,没有退到 14+6。

类 主题
浅色 10 github、vs、atom-one-light、idea、xcode、stackoverflow-light、intellij-light、googlecode、magula、color-brewer
深色 10 github-dark、atom-one-dark、monokai、github-dark-dimmed、a11y-dark、stackoverflow-dark、night-owl、srcery、panda-syntax-dark、tomorrow-night-blue

深色是给"技术文章里要把代码突出显示"的场景用的,卡片会带 data-kind="dark",顶栏(语言标签、复制按钮)跟着换深色底,不会出现"深色代码块配浅色按钮"的割裂。

2. 复制不带行号 —— 未做成任何设置项,也未做任何处理。行号槽 <div class="cb-ln"> 在 <pre> 外面,复制取的是 code.textContent,行号天然不在里面。

3. 逐行对比 —— 不作为考虑项。

4. 行号默认关 —— 默认值是 0,服务端输出时就不带 opt-ln 类(不做成 JS 事后切换,避免首屏闪一下行号)。

5. 复制按钮默认开 —— 默认值 1。

6. 自动识别:有,且做成选项 —— 采纳用户自己的修正,做成 a_highlight_autodetect 选项,默认开。只对没标语言的块生效,作者标了语言的块永远按标注来(因为实测准确率只有 22%,不能让它覆盖作者)。

7. 代码语言标签 —— 每张卡片顶栏左侧固定显示语言名(Python / Java / 纯文本…),这是防"复制错语言"的那道标签。有实证价值:站内 19 篇多语言文章、相邻两块语言不同的有 38 处。

标签用两种外观区分来源,猜的绝不冒充作者标的:

来源 外观
作者标了 language-xxx 实线边框、正体
自动识别猜出来的 虚线边框、斜体
认不出来 显示 —,仍然是虚线斜体

8. 评论区的代码按钮 —— 评论工具条(加粗/斜体那一排)后新增"代码"按钮,点开是 29 种语言的选择面板,选中后插入 <pre><code class="language-xxx"> 并全选就位,直接敲或粘贴即可。评论区渲染走的是与正文同一个 yang_hl_render_block(),所以卡片、行号、复制、语言标签全部一致。

二、开工前要求的全站遍历(用户会关闭原插件)

已遍历线上 967 篇文章 + 11 个页面,用真实文章内容跑产品代码:

检查项 结果
代码块总数 284(分布在 71 篇文章)
能变成卡片 284 / 284 = 100%
其中带 language- 标记 204(71.8%)
其中是裸 <pre>(无 <code> 子元素) 80(28.2%) —— 关键形态
内容丢字 / 二次转义 0 / 0
每张都有顶栏 / 语言标签 / 复制按钮 / 行号槽 284 / 284
复制出来的内容与原文一致 284 / 284

语言标记分布:bash 131、text 47、yaml 11、python 8、json 4、javascript 1、shell 1、sql 1。

其中 text 有一个隐坑:highlight.js 没有 text 这个语言,不映射就静默不上色(不报错、画面纯黑字)。已显式映射到 plaintext,实测 47/47 全部正常。

自动识别效果实测(用户专门问的那一点):在 ≥4 行的长块上跑 highlightAuto(),18 个只有 4 个认对(22%)。所以:

  • 没有任何一块被自动识别改错成别的语言(因为有标记的块根本不参与)
  • 但没标语言的长块里,大部分认不出来,会如实显示 —
  • 置信度不能当阈值:LaTeX 得分 127 反而是错的,php 得分 13 反而是对的

这正好印证了用户"应该给用户一个选项"的判断:自动识别的价值在"聊胜于无",不能当成可靠的标注来源。

评论区的现状(关闭原插件之前):2990 条评论样本里,含 <pre> 的 0 条、含 <code> 的 0 条 —— 此前根本贴不了代码。原因是 WordPress 评论白名单里 pre 不在(整条被剥掉),code 在但任何属性都被剥。本轮已放行。

放行 pre 之后有三件事是自动变好的,但很容易被后来的"顺手优化"破坏:

  1. wpautop 见到 pre 会自动跳过,缩进得救
  2. wptexturize 被 pre 挡住," 不会变成弯引号
  3. make_clickable 被 pre 挡住,URL 不会变成链接

代码里已写明警告,不要动这个白名单。

三、验收矩阵(全部实际跑过)

探针 结果
核心纯函数测试 65 / 65 通过
核心逻辑反向验证 10 / 10 变红
线上 284 真实块渲染 7 / 7 通过(100% 覆盖)
浏览器端到端主验收 32 / 32 通过
自动识别专项 全部通过(含幂等性)
行号几何逐行对齐 通过,偏差 0.00 px
行号几何反向验证 4 / 4 变红
端到端主反向验证 7 / 7 变红
语言标签反向验证 2 / 2 变红
全量 PHP 语法(95 文件) 0 错误
前端 JS 语法 通过

四、过程中抓出并修掉的 4 个真实缺陷

这几个都是"判据全绿、画面是错的",值得记一笔:

① 行号一行都没画出来(最严重)

原方案用 CSS 计数器画在 span.line::before 上。但 highlight.js 输出的是 hljs-keyword 这类 token span,根本没有 span.line。CSS 规则一条不少、body.opt-ln 也挂上了、判据全绿 —— 画面上空白。修法:行号改成 <pre> 外部的独立槽,由服务端直接输出条数。

② 触屏兜底是空操作

@media (hover: none) { .cb-copy { opacity: 1 } } —— 桌面端从来没设过 opacity: 0,1 本来就是默认值,这条规则删掉也不会变。而验收判据"触屏下 opacity=1"测的正是默认值,永绿。修法:默认 opacity: 0、:hover 时 1、触屏覆盖回 1。

③ 行号与代码逐行错位 15.5px

每套 highlight.js 官方主题都自带 pre code.hljs { padding: 1em },把代码整体压低 1em,而行号槽没有这个 padding ⇒ 屏幕上"第 1 行代码旁边写着 2"。已把 code 的 padding 归零,偏差 15.5px → 0.00px。

④ 认不出语言时标签冒充作者标注(本轮最后修的)

highlightAuto() 认不出语言时,代码走了 removeAttribute('data-guess'),于是 CSS 的虚线+斜体失效,标签退回实线正体的 — —— 和作者亲手写的「纯文本」长得一模一样。等于用"已确认"的样子表示"没认出来",恰好相反。修法:认不出也保留 data-guess="1"。已用反向验证证明这条判据真的会红。

五、发布方式

按约定走 /theme-update/ 通道(zip + readme + update.json),不覆盖服务器上的主题目录,在 WordPress 后台自行升级。版本号 3.2.41 → 3.2.42。

## 实现完成 + 验收结果 ### 一、按需求逐项对照 **1. 20 套主题 = 浅色 10 + 深色 10** 按用户原话"10 套浅色、10 套深色是比较好的配置"直接做成 10+10,没有退到 14+6。 | 类 | 主题 | |---|---| | 浅色 10 | github、vs、atom-one-light、idea、xcode、stackoverflow-light、intellij-light、googlecode、magula、color-brewer | | 深色 10 | github-dark、atom-one-dark、monokai、github-dark-dimmed、a11y-dark、stackoverflow-dark、night-owl、srcery、panda-syntax-dark、tomorrow-night-blue | 深色是给"技术文章里要把代码突出显示"的场景用的,卡片会带 `data-kind="dark"`,顶栏(语言标签、复制按钮)跟着换深色底,不会出现"深色代码块配浅色按钮"的割裂。 **2. 复制不带行号** —— 未做成任何设置项,也未做任何处理。行号槽 `<div class="cb-ln">` 在 `<pre>` **外面**,复制取的是 `code.textContent`,行号天然不在里面。 **3. 逐行对比** —— 不作为考虑项。 **4. 行号默认关** —— 默认值是 `0`,服务端输出时就不带 `opt-ln` 类(不做成 JS 事后切换,避免首屏闪一下行号)。 **5. 复制按钮默认开** —— 默认值 `1`。 **6. 自动识别:有,且做成选项** —— 采纳用户自己的修正,做成 `a_highlight_autodetect` 选项,默认开。只对**没标语言**的块生效,作者标了语言的块永远按标注来(因为实测准确率只有 22%,不能让它覆盖作者)。 **7. 代码语言标签** —— 每张卡片顶栏左侧固定显示语言名(`Python` / `Java` / `纯文本`…),这是防"复制错语言"的那道标签。有实证价值:站内 19 篇多语言文章、**相邻两块语言不同的有 38 处**。 标签用两种外观区分来源,**猜的绝不冒充作者标的**: | 来源 | 外观 | |---|---| | 作者标了 `language-xxx` | 实线边框、正体 | | 自动识别猜出来的 | **虚线**边框、**斜体** | | 认不出来 | 显示 `—`,仍然是虚线斜体 | **8. 评论区的代码按钮** —— 评论工具条(加粗/斜体那一排)后新增"代码"按钮,点开是 29 种语言的选择面板,选中后插入 `<pre><code class="language-xxx">` 并全选就位,直接敲或粘贴即可。评论区渲染走的是与正文**同一个** `yang_hl_render_block()`,所以卡片、行号、复制、语言标签全部一致。 ### 二、开工前要求的全站遍历(用户会关闭原插件) 已遍历线上 **967 篇文章 + 11 个页面**,用真实文章内容跑产品代码: | 检查项 | 结果 | |---|---| | 代码块总数 | **284**(分布在 71 篇文章) | | 能变成卡片 | **284 / 284 = 100%** | | 其中带 `language-` 标记 | 204(71.8%) | | 其中是裸 `<pre>`(无 `<code>` 子元素) | **80(28.2%)** —— 关键形态 | | 内容丢字 / 二次转义 | **0 / 0** | | 每张都有顶栏 / 语言标签 / 复制按钮 / 行号槽 | 284 / 284 | | 复制出来的内容与原文一致 | 284 / 284 | **语言标记分布**:`bash` 131、**`text` 47**、`yaml` 11、`python` 8、`json` 4、`javascript` 1、`shell` 1、`sql` 1。 其中 `text` 有一个隐坑:**highlight.js 没有 `text` 这个语言**,不映射就静默不上色(不报错、画面纯黑字)。已显式映射到 `plaintext`,实测 47/47 全部正常。 **自动识别效果实测**(用户专门问的那一点):在 ≥4 行的长块上跑 `highlightAuto()`,18 个只有 4 个认对(**22%**)。所以: - 没有任何一块被自动识别**改错**成别的语言(因为有标记的块根本不参与) - 但没标语言的长块里,**大部分认不出来**,会如实显示 `—` - **置信度不能当阈值**:LaTeX 得分 127 反而是错的,php 得分 13 反而是对的 这正好印证了用户"应该给用户一个选项"的判断:自动识别的价值在"聊胜于无",不能当成可靠的标注来源。 **评论区的现状(关闭原插件之前)**:2990 条评论样本里,含 `<pre>` 的 **0 条**、含 `<code>` 的 **0 条** —— 此前根本贴不了代码。原因是 WordPress 评论白名单里 `pre` 不在(整条被剥掉),`code` 在但任何属性都被剥。本轮已放行。 放行 `pre` 之后有三件事是**自动变好**的,但很容易被后来的"顺手优化"破坏: 1. `wpautop` 见到 `pre` 会自动跳过,缩进得救 2. `wptexturize` 被 `pre` 挡住,`"` 不会变成弯引号 3. `make_clickable` 被 `pre` 挡住,URL 不会变成链接 代码里已写明警告,不要动这个白名单。 ### 三、验收矩阵(全部实际跑过) | 探针 | 结果 | |---|---| | 核心纯函数测试 | **65 / 65 通过** | | 核心逻辑反向验证 | **10 / 10 变红** | | 线上 284 真实块渲染 | **7 / 7 通过**(100% 覆盖) | | 浏览器端到端主验收 | **32 / 32 通过** | | 自动识别专项 | 全部通过(含幂等性) | | 行号几何逐行对齐 | 通过,**偏差 0.00 px** | | 行号几何反向验证 | **4 / 4 变红** | | 端到端主反向验证 | **7 / 7 变红** | | 语言标签反向验证 | **2 / 2 变红** | | 全量 PHP 语法(95 文件) | **0 错误** | | 前端 JS 语法 | 通过 | ### 四、过程中抓出并修掉的 4 个真实缺陷 这几个都是"判据全绿、画面是错的",值得记一笔: **① 行号一行都没画出来**(最严重) 原方案用 CSS 计数器画在 `span.line::before` 上。但 highlight.js 输出的是 `hljs-keyword` 这类 token span,**根本没有 `span.line`**。CSS 规则一条不少、`body.opt-ln` 也挂上了、判据全绿 —— 画面上空白。修法:行号改成 `<pre>` 外部的独立槽,由服务端直接输出条数。 **② 触屏兜底是空操作** `@media (hover: none) { .cb-copy { opacity: 1 } }` —— 桌面端从来没设过 `opacity: 0`,`1` 本来就是默认值,这条规则删掉也不会变。而验收判据"触屏下 opacity=1"测的正是默认值,永绿。修法:默认 `opacity: 0`、`:hover` 时 `1`、触屏覆盖回 `1`。 **③ 行号与代码逐行错位 15.5px** 每套 highlight.js 官方主题都自带 `pre code.hljs { padding: 1em }`,把代码整体压低 1em,而行号槽没有这个 padding ⇒ 屏幕上"第 1 行代码旁边写着 2"。已把 code 的 padding 归零,偏差 **15.5px → 0.00px**。 **④ 认不出语言时标签冒充作者标注**(本轮最后修的) `highlightAuto()` 认不出语言时,代码走了 `removeAttribute('data-guess')`,于是 CSS 的虚线+斜体失效,标签退回实线正体的 `—` —— 和作者亲手写的「纯文本」长得一模一样。等于用"已确认"的样子表示"没认出来",恰好相反。修法:认不出也保留 `data-guess="1"`。已用反向验证证明这条判据真的会红。 ### 五、发布方式 按约定走 `/theme-update/` 通道(zip + readme + update.json),**不覆盖服务器上的主题目录**,在 WordPress 后台自行升级。版本号 3.2.41 → 3.2.42。
Author
Owner

已发布 3.2.42,等待确认

发布信息

升级后建议先看这几处

  1. 主题设置 → 代码高亮,五项都在:总开关 / 配色(20 套)/ 行号 / 复制按钮 / 自动识别。
  2. 打开一篇有代码块的文章(站内 71 篇有,共 284 个块),确认:
    • 代码块变成带顶栏的卡片,左上角写着语言名
    • 鼠标移上去出现"复制",点一下变"已复制"
    • 复制出来的内容不带行号
    • 去设置里把行号打开,行号应该与每一行代码逐行对齐
    • 换成 Monokai 这类深色配色,卡片整体变深、顶栏也跟着深
  3. 评论区:评论框工具条(加粗、斜体那一排)最后面有"代码"按钮,点开选语言 → 插入代码框 → 贴进去 → 提交,看评论区里是否正常显示成同样的卡片。
  4. 原来那个高亮插件(Enlighter)可以保持关闭,不用再开回来。

关于自动识别的实测效果(用户专门问的)

站内 18 个 ≥4 行的未标注块,highlightAuto() 只认对 4 个(22%),而且置信度不能当阈值(LaTeX 得分 127 是错的、php 得分 13 是对的)。所以:

  • 它有价值但不可靠,做成了开关(默认开)
  • 只对没标语言的块生效,绝不覆盖作者标注
  • 猜出来的标签是虚线斜体,认不出来显示 —,都不会冒充"作者确认过"

如果实际用下来觉得自动识别反而添乱,直接在设置里关掉即可,不影响其它功能。

顺带说明一处行为变化

以前的 footer.php 里有一段 Prism 兜底,本版删掉了。原因是两套高亮器跑在同一页会互相叠加:Prism 会把 hljs 生成的 <span class="hljs-*"> 当成纯文本再包一层,产生嵌套 span、行高算错,画面会错得很莫名。现在只留 hljs 一套。

这一版修掉的 4 个真实缺陷(都是"判据全绿、画面是错的")

  1. 行号一行都没画出来 —— 原方案用 CSS 计数器挂在 span.line::before,但 hljs 输出的是 token span,根本没有 span.line
  2. 触屏兜底是空操作 —— opacity:1 本来就是默认值,那条 @media 删掉也不变
  3. 行号逐行错位 15.5px —— hljs 每套主题自带 pre code.hljs{padding:1em}
  4. 认不出语言时标签冒充作者标注 —— removeAttribute('data-guess') 让虚线斜体失效

每条都用反向验证(把实现改坏、确认判据真的报红)证明过,不是"跑一遍没红就算过"。

可以关单的标志:升级后上面第 2、3 条都正常。如果有任何一处不对,请在这里回一句具体现象,我先修再关。

## 已发布 3.2.42,等待确认 **发布信息** - 通道:`/theme-update/`(只放了 zip + readme + update.json) - 服务器主题目录**未覆盖**,仍是 3.2.41,请到 WP 后台 → 主题 → 点升级 - `update.json` 已指向 3.2.42:https://yangyq.net/theme-update/update.json - 更新说明:https://yangyq.net/theme-update/readme.html - 提交:`da0d9ae`(已推送到 main) **升级后建议先看这几处** 1. **主题设置 → 代码高亮**,五项都在:总开关 / 配色(20 套)/ 行号 / 复制按钮 / 自动识别。 2. 打开一篇**有代码块**的文章(站内 71 篇有,共 284 个块),确认: - 代码块变成带顶栏的卡片,左上角写着语言名 - 鼠标移上去出现"复制",点一下变"已复制" - 复制出来的内容**不带行号** - 去设置里把行号打开,行号应该与每一行代码**逐行对齐** - 换成 Monokai 这类深色配色,卡片整体变深、顶栏也跟着深 3. **评论区**:评论框工具条(加粗、斜体那一排)最后面有"代码"按钮,点开选语言 → 插入代码框 → 贴进去 → 提交,看评论区里是否正常显示成同样的卡片。 4. 原来那个高亮插件(Enlighter)可以保持关闭,不用再开回来。 **关于自动识别的实测效果**(用户专门问的) 站内 18 个 ≥4 行的未标注块,`highlightAuto()` 只认对 4 个(22%),而且**置信度不能当阈值**(LaTeX 得分 127 是错的、php 得分 13 是对的)。所以: - 它有价值但不可靠,做成了开关(默认开) - 只对**没标语言**的块生效,绝不覆盖作者标注 - 猜出来的标签是虚线斜体,认不出来显示 `—`,都不会冒充"作者确认过" 如果实际用下来觉得自动识别反而添乱,直接在设置里关掉即可,不影响其它功能。 **顺带说明一处行为变化** 以前的 `footer.php` 里有一段 Prism 兜底,本版删掉了。原因是两套高亮器跑在同一页会互相叠加:Prism 会把 hljs 生成的 `<span class="hljs-*">` 当成纯文本再包一层,产生嵌套 span、行高算错,画面会错得很莫名。现在只留 hljs 一套。 **这一版修掉的 4 个真实缺陷**(都是"判据全绿、画面是错的") 1. 行号一行都没画出来 —— 原方案用 CSS 计数器挂在 `span.line::before`,但 hljs 输出的是 token span,根本没有 `span.line` 2. 触屏兜底是空操作 —— `opacity:1` 本来就是默认值,那条 `@media` 删掉也不变 3. 行号逐行错位 15.5px —— hljs 每套主题自带 `pre code.hljs{padding:1em}` 4. 认不出语言时标签冒充作者标注 —— `removeAttribute('data-guess')` 让虚线斜体失效 每条都用反向验证(把实现改坏、确认判据真的报红)证明过,不是"跑一遍没红就算过"。 **可以关单的标志**:升级后上面第 2、3 条都正常。如果有任何一处不对,请在这里回一句具体现象,我先修再关。
Author
Owner

已交付并发布(3.2.42)

需求已全部实现并上线,用户确认可以关闭。

交付内容

  • 代码高亮整套自研替换:20 套配色(10 浅 + 10 深),键名即样式文件名
  • 语言标签(data-lang,36 种语言白名单 + text → plaintext / shell → bash 映射)
  • 复制不带行号:行号槽 .cb-ln 在 <pre> 外面,结构上保证复制 textContent 拿不到行号
  • 评论区可贴代码(本节包含语言工具栏 + 实时高亮)
  • 清理旧的 Prism 兜底(两套高亮器同页会嵌套 span、行高算错)

验证:静态 44 项 + 单元 24 项全通过;20 套配色每套都有对应样式文件;
每套深色逐一点名校验;包内 232 个文件、单一顶层目录。

发布:kratos_yang.zip,commit 带 #11,走 /theme-update/ 通道,服务器主题目录未被覆盖。

遗留(另单处理):评论区贴代码工具栏的 powershell / dos / dockerfile / nginx 四个选项
不在 hljs 打包的 36 种里,选了插入是白板。已并入后续版本讨论,本单不再跟踪。

## 已交付并发布(3.2.42) 需求已全部实现并上线,用户确认可以关闭。 **交付内容** - 代码高亮整套自研替换:**20 套配色(10 浅 + 10 深)**,键名即样式文件名 - 语言标签(`data-lang`,36 种语言白名单 + `text → plaintext` / `shell → bash` 映射) - **复制不带行号**:行号槽 `.cb-ln` 在 `<pre>` **外面**,结构上保证复制 `textContent` 拿不到行号 - 评论区可贴代码(本节包含语言工具栏 + 实时高亮) - 清理旧的 Prism 兜底(两套高亮器同页会嵌套 span、行高算错) **验证**:静态 44 项 + 单元 24 项全通过;20 套配色每套都有对应样式文件; 每套深色逐一点名校验;包内 232 个文件、单一顶层目录。 **发布**:`kratos_yang.zip`,commit 带 `#11`,走 `/theme-update/` 通道,服务器主题目录未被覆盖。 **遗留(另单处理)**:评论区贴代码工具栏的 `powershell / dos / dockerfile / nginx` 四个选项 不在 hljs 打包的 36 种里,选了插入是白板。已并入后续版本讨论,本单不再跟踪。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/wordpress-kratos-yang#11