两件事,都围绕"代码高亮"的使用体验。
现在后台选代码高亮配色,只看到一个下拉框里的主题名,不知道长什么样, 只能先保存再刷新前台看,不行再改回来。对比:选自动头像风格时下方有演示图, 体验好得多。
要求:选择高亮主题时,旁边/下方给出实时样例(代码片段渲染成该配色的样子)。
验收:在后台切换下拉框,无需保存、无需刷新,就能看到该配色下的代码块效果。
这个博客多年下来装过各种代码高亮插件,<pre> / <code> 上的语言标记 写法五花八门(有的是 lang,有的是别的),并不规范。
<pre>
<code>
lang
要求:
lang="xxx"
highlightAuto
plaintext
验收:
assets/css/highlight-admin.css
assets/js/highlight-admin.js
<link>
inc/theme-highlight.php
yang_hl_admin_assets()
yang_hl_admin_preview_html()
inc/theme-options.php
type=info
.hljs-keyword
assets/hljs/styles/<key>.min.css
assets/css/highlight.css
highlightElement
textContent
highlight()
data-raw
_admin_preview_test.js
_admin_preview_falsify.js
hljs.highlight
span 0 → 17
普查全库(直连 MySQL,零抓页)的结果与直觉相反:
<pre
87 个无效标记的构成:text 47(Prism 遗留)、generic 28 + raw 8(Enlighter 的「不高亮」语义)、 jsp 2 与 latex 2(hljs 未打包,会静默白板)。
text
generic
raw
jsp
latex
所以真正的问题不是「没有标注」,而是「标注是假的」 —— 这正是此前要靠 JS highlightAuto 去猜的原因,而 autodetect 在站内实测准确率只有 22%。
语言一律写在 <pre> 自己的 lang 属性上:<pre lang="python">…</pre>
<pre lang="python">…</pre>
同时清掉所有「第二份真相」:
data-enlighter-language
class="EnlighterJSRAW"
<code class="language-xxx">
language-*
line-numbers
理由:一个块上留两种语言标注早晚会打架,而且以后再统计又是不一致。
判定表的优先级必须高于「沿用旧标注」,这是本轮修掉的一个实质 bug: 产品会把 generic/raw/text 兜底成 plaintext,而 plaintext 本身在白名单里 ⇒ 旧逻辑 in_array($cur,$WHITE) 成立 ⇒ 走「保留」⇒ 判定表被静默丢弃。 第一版实测 87 条只有 4 条生效,其余 42 条非 plaintext 判定全丢, 而且结果看起来是成功的(每块都有 lang,只是大部分是 plaintext)。
in_array($cur,$WHITE)
最终分布:
root@host#
nginx['enable']=true
45 个标 plaintext 的不是「判不出来」,而是内容本来就不该高亮(报错散文、LaTeX 片段、中文提示)。 按「判不出来给纯文本」的要求,这些正好落在该有的位置。
/tmp/lang_norm_20261026_113042/
rollback.sql
orig_posts.json
new_posts.json
post_type='post' AND post_status='publish'
post_id + 文内第几块
踩到一个会静默写错块的坑:同一篇文章里有 11 对块原文完全相同 (如 post=5074 的 idx 4 与 15)。用 str_replace($orig,$new,$content) 会全局替换, 如果这两块该得到不同语言就会整片标错。改成 preg_replace_callback + 计数器按序号替换。
str_replace($orig,$new,$content)
preg_replace_callback
--verify
figure.cb
data-guess
PHP 变量名会吞掉全角括号:"无 lang 的块 = $noLang(必须 0)" 实际解析成 $noLang(必须 —— 未定义变量 ⇒ 输出空 ⇒ '' === 0 恒真。 审计第一版 4 条核心断言全是空壳,却显示「全部通过」。 修法:插值一律写 {$var}。(同族红线:否定式断言在空输出上恒真。)
"无 lang 的块 = $noLang(必须 0)"
$noLang(必须
'' === 0
{$var}
判据被前面的 continue 遮蔽:注入 <pre data-enlighter-language="generic" lang="javascript"> 时,判据 B 用产品函数校验会先读到 data-enlighter 返回 plaintext ≠ javascript ⇒ 立刻 continue ⇒ 判据 C(残留 Enlighter)永远走不到,成了「从来没红过」的绿灯。 修法:三条判据先各自算布尔,最后统一判定,谁命中就报谁。
<pre data-enlighter-language="generic" lang="javascript">
评论区代码块工具栏(.comment-code-lang 那排按钮)里有 powershell / dos / dockerfile / nginx 四个选项,但 hljs 打包的 36 种语言里没有这四个。用户选完插入,代码块会是白板。 与本单无关(本单只改文章内容),建议另开一单处理。
.comment-code-lang
https://yangyq.net/theme-update/
03b0bc6
#13
需求 A(约 30 秒)
GitHub
Monokai
Night Owl
需求 B(约 1 分钟)
数据改写有完整回滚:
kratos_yang-3.2.32.zip
① 顺手补了 3.2.43 的更新记录。 上一批(#12)版本号升到了 3.2.43,但更新说明里忘了加这一条, 线上 readme 最新还停在 3.2.42。这次补上了,现在 readme 顶部是 3.2.44 → 3.2.43 → 3.2.42。
② 发现一个与本单无关的独立问题,建议另开一单: 评论区贴代码的那个工具栏,「选语言」那排按钮里有 PowerShell / Batch(dos) / Dockerfile / Nginx 四个选项,但主题打包的高亮库(36 种语言)里没有这四种。 用户选完这四个插入代码块,在页面上会是白板(不上色、语言标签也不对)。 本单只改文章正文内容,没动评论区工具栏。要修的话是另一件事。
需求已全部实现并上线,用户确认可以关闭。
下拉框旁加预览面板,切换配色立刻生效、不用保存/刷新。
removeChild
直连库统计:正文 284 块(71 篇),评论中 0 块,revision 21 篇 119 块(历史修订,不动)。 完全无语言标记的为 0 —— 所以问题不是"没标",是"标了但不认"(87 块标注无效: text 47 / generic 28 / raw 8 / jsp 2 / latex 2)。
大模型判定 87 条后统一写库:--apply 需改 267 / 已合规 17,写入 66 篇并提交事务, 备份 /tmp/lang_norm_20261026_113042/(rollback.sql + orig_posts.json); --verify 284/284 合规。
--apply
最终分布:bash 174、plaintext 45、yaml 13、ini 9、xml 8、python 8、javascript 7、 php 6、json 5、java 5、ruby 2、sql 2。
验证:探针 22/0、反向 6/0;独立复核脚本(不复用产品函数生成标签)全绿、反向 3/3 真红; 真实页面 4 篇 data-guess 全 0,anaconda 28 块全确认、LaTeX 5 块全「纯文本」。
发布:kratos_yang.zip md5 9f1cfb47d66924da9eae199e3a096194,commit 03b0bc6 带 #13, readme 补上了 3.2.43 + 3.2.44 两条(35 条版本标题、历史 33 条完整),走 /theme-update/ 通道。
kratos_yang.zip
9f1cfb47d66924da9eae199e3a096194
/theme-update/
已由 3.2.45 修掉的遗留:本版的后台预览有两个问题(后台未加载 hljs ⇒ 预览单色; 首屏跳过上色),已并入 #14 修完并发布。
No dependencies set.
The note is not visible to the blocked user.
需求(用户原话整理)
两件事,都围绕"代码高亮"的使用体验。
需求 A:后台选择高亮主题时要有预览
现在后台选代码高亮配色,只看到一个下拉框里的主题名,不知道长什么样,
只能先保存再刷新前台看,不行再改回来。对比:选自动头像风格时下方有演示图,
体验好得多。
要求:选择高亮主题时,旁边/下方给出实时样例(代码片段渲染成该配色的样子)。
验收:在后台切换下拉框,无需保存、无需刷新,就能看到该配色下的代码块效果。
需求 B:全站代码块的语言标注要统一,缺的用大模型判断
这个博客多年下来装过各种代码高亮插件,
<pre>/<code>上的语言标记写法五花八门(有的是
lang,有的是别的),并不规范。要求:
lang="xxx"。highlightAuto那条路要去掉作用)。plaintext)。验收:
lang="xxx",无一处例外。硬约束(用户之前明确要求,必须遵守)
待办
进度:需求 A(后台配色实时预览)已完成并通过验证
实现
assets/css/highlight-admin.css(只做预览框布局,不改代码块外观)assets/js/highlight-admin.js(监听下拉框 → 换<link>→ 重新上色)inc/theme-highlight.php:新增yang_hl_admin_assets()+yang_hl_admin_preview_html()inc/theme-options.php:在「代码配色」下拉框后插入type=info的预览面板几个关键取舍(都有实测依据)
<link>再插新的,不能改 href、也不能 20 套一起加载。20 套配色的规则是裸选择器(
.hljs-keyword等),同场会互相压制,最后加载的赢—— 视觉上就是「切换没反应」。
assets/hljs/styles/<key>.min.css+assets/css/highlight.css),另写一套必然和前台不一致,那预览就没意义了。
highlightElement,改为从textContent取原文重新highlight()。highlightElement会在已上色元素上再套一层,颜色变脏。所以不需要额外存
data-raw—— 那只是两份状态,不同步就是 bug 源头。已删掉该冗余。验证
_admin_preview_test.js(jsdom)22 通过 / 0 失败配色名跟随、连切 20 次不残留、上色无损且幂等、无三层嵌套 span
_admin_preview_falsify.js6 组注入全部真红,源码未被改动踩到并记录的坑
hljs.highlight比对,产品改坏也照样绿(注入 ⑤ 全绿才暴露)。改成真的切 select 让产品自己跑。
span 0 → 17那条红是基准取在"尚未上色"状态,量的其实是"有没有上色",不是"重复上色会不会套娃"。
「产品交给 hljs 的必须是纯文本原文(阈值 600 字符)」。
进度:需求 B(全站代码块语言标注统一)已完成,数据已改写并复核
一、先纠正一个前提:站内没有「完全无标注」的代码块
普查全库(直连 MySQL,零抓页)的结果与直觉相反:
<pre,是被转义的纯文本)87 个无效标记的构成:
text47(Prism 遗留)、generic28 +raw8(Enlighter 的「不高亮」语义)、jsp2 与latex2(hljs 未打包,会静默白板)。所以真正的问题不是「没有标注」,而是「标注是假的」 —— 这正是此前要靠 JS
highlightAuto去猜的原因,而 autodetect 在站内实测准确率只有 22%。
二、统一后的规范形态
语言一律写在
<pre>自己的lang属性上:<pre lang="python">…</pre>同时清掉所有「第二份真相」:
data-enlighter-language/class="EnlighterJSRAW"(别的插件的私有标记)<code class="language-xxx">里的language-*(只保留line-numbers这类纯样式类)理由:一个块上留两种语言标注早晚会打架,而且以后再统计又是不一致。
三、大模型判定:87 条,逐块看过内容
判定表的优先级必须高于「沿用旧标注」,这是本轮修掉的一个实质 bug:
产品会把
generic/raw/text兜底成plaintext,而plaintext本身在白名单里 ⇒旧逻辑
in_array($cur,$WHITE)成立 ⇒ 走「保留」⇒ 判定表被静默丢弃。第一版实测 87 条只有 4 条生效,其余 42 条非 plaintext 判定全丢,
而且结果看起来是成功的(每块都有 lang,只是大部分是 plaintext)。
最终分布:
root@host#提示符的会话nginx['enable']=true配置语法45 个标
plaintext的不是「判不出来」,而是内容本来就不该高亮(报错散文、LaTeX 片段、中文提示)。按「判不出来给纯文本」的要求,这些正好落在该有的位置。
四、改写安全性
/tmp/lang_norm_20261026_113042/rollback.sql160KB(可执行回滚)orig_posts.json/new_posts.json(逐篇逐字可比对)post_type='post' AND post_status='publish';revision、评论一律不碰post_id + 文内第几块,再加内容签名校验(判定表基于某时刻的库导出,签名不符就报错跳过,绝不盲改)
踩到一个会静默写错块的坑:同一篇文章里有 11 对块原文完全相同
(如 post=5074 的 idx 4 与 15)。用
str_replace($orig,$new,$content)会全局替换,如果这两块该得到不同语言就会整片标错。改成
preg_replace_callback+ 计数器按序号替换。五、验证
--verifyfigure.cb数与块数一致,data-guess全为 0(已确认,没有一块是猜的)六、这轮抓到的两个「判据空壳」(都值得记)
PHP 变量名会吞掉全角括号:
"无 lang 的块 = $noLang(必须 0)"实际解析成$noLang(必须—— 未定义变量 ⇒ 输出空 ⇒'' === 0恒真。审计第一版 4 条核心断言全是空壳,却显示「全部通过」。
修法:插值一律写
{$var}。(同族红线:否定式断言在空输出上恒真。)判据被前面的 continue 遮蔽:注入
<pre data-enlighter-language="generic" lang="javascript">时,判据 B 用产品函数校验会先读到 data-enlighter 返回 plaintext ≠ javascript ⇒
立刻 continue ⇒ 判据 C(残留 Enlighter)永远走不到,成了「从来没红过」的绿灯。
修法:三条判据先各自算布尔,最后统一判定,谁命中就报谁。
七、顺带发现的一个独立问题(未在本单处理)
评论区代码块工具栏(
.comment-code-lang那排按钮)里有 powershell / dos / dockerfile / nginx四个选项,但 hljs 打包的 36 种语言里没有这四个。用户选完插入,代码块会是白板。
与本单无关(本单只改文章内容),建议另开一单处理。
已发布 3.2.44,等待实测确认
交付内容
https://yangyq.net/theme-update/(只发 zip + readme + update.json,未覆盖服务器主题目录)03b0bc6(带#13)请在 WordPress 后台升级到 3.2.44,然后按这几条确认
需求 A(约 30 秒)
GitHub→Monokai→Night Owl):需求 B(约 1 分钟)
—— 以前有些块是虚线斜体(表示"这是程序猜的"),现在正文里应该一个都没有了
如果发现问题
数据改写有完整回滚:
/tmp/lang_norm_20261026_113042/rollback.sql可直接回滚 66 篇文章kratos_yang-3.2.32.zip(更新通道里还留着旧包)另外说明两件事
① 顺手补了 3.2.43 的更新记录。 上一批(#12)版本号升到了 3.2.43,但更新说明里忘了加这一条,
线上 readme 最新还停在 3.2.42。这次补上了,现在 readme 顶部是 3.2.44 → 3.2.43 → 3.2.42。
② 发现一个与本单无关的独立问题,建议另开一单:
评论区贴代码的那个工具栏,「选语言」那排按钮里有 PowerShell / Batch(dos) / Dockerfile / Nginx
四个选项,但主题打包的高亮库(36 种语言)里没有这四种。
用户选完这四个插入代码块,在页面上会是白板(不上色、语言标签也不对)。
本单只改文章正文内容,没动评论区工具栏。要修的话是另一件事。
待办
#13并推送已交付并发布(3.2.44)
需求已全部实现并上线,用户确认可以关闭。
需求 A:后台「代码配色」实时预览
下拉框旁加预览面板,切换配色立刻生效、不用保存/刷新。
assets/css/highlight-admin.css(只管布局,不改代码块外观)+assets/js/highlight-admin.js.hljs-keyword),会互相压制⇒ 切换时必须真的
removeChild旧<link>再插新<link>highlightElement会在已上色元素上再套一层 ⇒ 每轮从textContent取原文重算需求 B:全站代码块语言标注统一
直连库统计:正文 284 块(71 篇),评论中 0 块,revision 21 篇 119 块(历史修订,不动)。
完全无语言标记的为 0 —— 所以问题不是"没标",是"标了但不认"(87 块标注无效:
text 47 / generic 28 / raw 8 / jsp 2 / latex 2)。
大模型判定 87 条后统一写库:
--apply需改 267 / 已合规 17,写入 66 篇并提交事务,备份
/tmp/lang_norm_20261026_113042/(rollback.sql+orig_posts.json);--verify284/284 合规。最终分布:bash 174、plaintext 45、yaml 13、ini 9、xml 8、python 8、javascript 7、
php 6、json 5、java 5、ruby 2、sql 2。
验证:探针 22/0、反向 6/0;独立复核脚本(不复用产品函数生成标签)全绿、反向 3/3 真红;
真实页面 4 篇
data-guess全 0,anaconda 28 块全确认、LaTeX 5 块全「纯文本」。发布:
kratos_yang.zipmd59f1cfb47d66924da9eae199e3a096194,commit03b0bc6带#13,readme 补上了 3.2.43 + 3.2.44 两条(35 条版本标题、历史 33 条完整),走
/theme-update/通道。已由 3.2.45 修掉的遗留:本版的后台预览有两个问题(后台未加载 hljs ⇒ 预览单色;
首屏跳过上色),已并入 #14 修完并发布。