现在是 11 月 29 号的下午四点。会赢吗
之前我在 Not A Goalkeeper 那边说的
最██的是,我发现之前使用的 hexo-renderer-kramed 是一个将近十年前的 hexo-renderer-marked 的分支,里面很多语法早就不支持了;在这十年间,hexo-renderer-marked 将 markdown 转为 html 的匹配逻辑(尤其是 em 和 strong)演变到了非常哈人的程度,把这个调好还需要研究好久。
其实非常容易绕过:如果使用 hexo-renderer-marked,它虽然确实会调用 marked,这里面确实有很多哈人的正则表达式,但是 marked 提供了扩展语法 marked.use(),而 hexo-renderer-marked 只是把它包装了一下。
marked 处理字符串的逻辑非常简单:按照某个顺序用正则表达式匹配输入的 markdown 字符串,每匹配到一段就将其删去,并在另一个列表中添加一个对应内容的 token。所以如果我有如下的 tex 代码:
1 2 3 4 5 6 7
| 测试一下 $ {A}_* $ 和 $ {B}_* $
还有 $ *_* $
以及 $ A^{**} $ 和 $ B^{**} $
最后的 $ {A}_{**} $ 与 $ B^{**}_1 $
|
那么它被 hexo-renderer-marked 搞出来的就会是
1 2 3 4 5 6
| <div class="post-body" itemprop="articleBody"><p>测试一下 $ {A}<em>* $ 和 $ {B}</em>* $</p> <p>还有 $ <em>_</em> $</p> <p>以及 $ A^{<strong>} $ 和 $ B^{</strong>} $</p> <p>最后的 $ {A}_{<strong>} $ 与 $ B^{</strong>}_1 $</p>
</div>
|
而如果装了 hexo-filter-mathjax,它又会直接生成 svg,文件又会再被搞成下面一大坨
1 2 3 4 5 6
| <div class="post-body" itemprop="articleBody"><p>测试一下 $ {A}<em>* <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.452ex;" xmlns="http://www.w3.org/2000/svg" width="2.262ex" height="2.149ex" role="img" focusable="false" viewBox="0 -750 1000 950"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><text data-variant="normal" transform="scale(1,-1)" font-size="884px" font-family="serif">和</text></g></g></g></svg></mjx-container> {B}</em>* $</p> <p>还有 $ <em>_</em> $</p> <p>以及 $ A^{<strong>} <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.452ex;" xmlns="http://www.w3.org/2000/svg" width="2.262ex" height="2.149ex" role="img" focusable="false" viewBox="0 -750 1000 950"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><text data-variant="normal" transform="scale(1,-1)" font-size="884px" font-family="serif">和</text></g></g></g></svg></mjx-container> B^{</strong>} $</p> <p>最后的 $ {A}_{<strong>} <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.452ex;" xmlns="http://www.w3.org/2000/svg" width="2.262ex" height="2.149ex" role="img" focusable="false" viewBox="0 -750 1000 950"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><text data-variant="normal" transform="scale(1,-1)" font-size="884px" font-family="serif">与</text></g></g></g></svg></mjx-container> B^{</strong>}_1 $</p>
</div>
|
这该怎么办呢?
很好的一点是,marked 特地把自定义的 token 种类放到了最前面,所以我们只需要用保留的接口自定义一个 token 来匹配数学环境,之后把内容原样输出。让 Gemini 给我写了一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
'use strict';
const markedMathExtension = { name: 'math', level: 'inline',
start(src) { return src.indexOf('$'); },
tokenizer(src, tokens) { const blockRule = /^\s*(?:\$\$|\\begin\{(equation\**|gather\**|align\**)\})([\s\S]+?)(?:\$\$|\\end\{\1\})\s*/; let match = blockRule.exec(src); if (match) { return { type: 'math', raw: match[0], text: match[1] ? `\\begin{${match[1]}}${match[2]}\\end{${match[1]}}` : match[2].trim(), displayMode: true, }; }
const inlineRule = /^\$((?:\\.|[^$])+?)\$/; match = inlineRule.exec(src); if (match) { return { type: 'math', raw: match[0], text: match[1].trim(), displayMode: false, }; } },
renderer(token) { if (token.type === 'math') { if (token.displayMode) { if (token.text.startsWith('\\begin')) { return token.text; } else { return `$$${token.text}$$`; } } else { return `$${token.text}$`; } }
return false; } };
hexo.extend.filter.register('marked:extensions', function(extensions) { extensions.push(markedMathExtension); });
|
这样一来甚至连 hexo-filter-mathjax 都不需要了。结果就是:
1 2 3 4 5 6
| <div class="post-body" itemprop="articleBody"><p>测试一下 ${A}_*$ 和 ${B}_*$</p> <p>还有 $*_*$</p> <p>以及 $A^{**}$ 和 $B^{**}$</p> <p>最后的 ${A}_{**}$ 与 $B^{**}_1$</p>
</div>
|
最终效果:
测试一下 和
还有
以及 和
最后的 与
完美。使用的时候只需要把上面那一大块丢到 scripts 文件夹下就可以。
这样一来也不需要像之前那样修改对 markdown 语法的渲染规则了,偷偷改回来应该没有人会发现。
好像不太完美,不用 hexo-filter-mathjax 好像在别处会有问题,反正没有影响还是加回来吧。这样的话还是要禁用自带的 mathjax,但总之不会出错了。
网站的排版与之前有些细微的差别,但主体已经升级完成。祝贺 brkhu.fun 终于有了评论系统!
再次更新:添加了旧版网页入口 https://legacy.brkhu.fun