在做独立博客的时候,特别是对于程序员来说,代码高亮是很重要的一个组件。我也接触过几款不同的代码高亮引擎。衡量一个高亮引擎的好坏有很多不同的方面:分词、性能、稳定性、主题丰富性。本文将专注分词的表现,对几款流行的高亮引擎以及 IDE 做一个横向对比。
什么是分词
要把一段代码高亮输出,主要工作流程大概如下:
分词的过程就类似于画画的线稿,线稿越精细,上色的自由度就越高,最终得到的输出就有可能越丰富好看。作为一个面向颜值的工程师,对颜值可以说非常看重了。不管着色主题好看与否,分词的精细程度才是关键之处。分词分好了,怎么上色无非是主题作者的事情。
对比的对象
测试例子代码是 Python,因为我也主要关注 Python 代码的分词表现,主题统一用 Monokai 并做了微调以求尽量统一。根据分词进行在前端或者后端,本次参加对比的选手有:
- 前端分词:Highlight.js, Prism.js,送到 HTML 中的是未标注的代码段
- Python 后端分词:Pygments, 送到 HTML 中的是已标注的代码段
另外请到了几位大佬下场指导:他们分别是编辑器界扛把子 Vim、GUI 编辑器扛把子 VSCode,以及专用 IDE 扛把子 PyCharm(没有人比我更懂 Python 分词)。 他们仅作为天花板的参考。编辑器都尽量用最简单的配置,禁用多余的扩展。
对比结果
废话少说,我拉了一个清单,把例子代码中涉及到的语法元素做了大概的总结,渲染结果可以在这里查看。
Highlight.js | Prism.js | Pygments | Vim | VSCode | PyCharm | |
---|---|---|---|---|---|---|
区分 built-in | ✔️1 | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
识别 operator | ✔️ | ✔️ | ✔️ | ✔️ | ||
区分 import keywords | ✔️ | ✔️ | ✔️ | |||
区分 magic method | ✔️ | ✔️ | ||||
区分 doc-string 与 string | ✔️ | ✔️ | ✔️ | ✔️ | ||
解析 f-string | ✔️2 | ✔️ | ✔️ | ✔️ | ✔️ | |
解析 decorator | ✔️2 | ✔️ | ✔️ | ✔️2 | ✔️ | ✔️ |
区分参数与 identifier | ✔️ | ✔️ | ||||
区分 self 与参数 | ✔️ | ✔️ | ||||
区分 class 与 identifier | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
区分 annotation3 | ✔️ |
总结
我们可以看到三个对比者中 Prism.js 和 Pygments 不相上下,Prism.js 只差一点,但 Pygments 毕竟是 Python 实现所以可以理解。最差的是 Highlight.js,综合网上评价的 bug 比较多的情况,不建议选择。
用前端分词的好处是配置简单,只需要额外几个 script 就完成。用 Pygments 则需要对后端代码做适当改动。不过python-markdown和Marko都提供了对应的扩展,可以在 Markdown 转换 HTML 的时候就通过 Pygments 标注好代码段,这也不是很大的问题。考虑到 Prism.js 已经能有比较好的表现了,我首推 Prism.js 做博客的代码高亮。
而三个产品距离专业的代码编辑器都还有很大的距离。至于 Vim,因为我不会用或者不会配,可能会有更好的表现,希望懂的同学补充。
更新于 2021-11-24
最近发现了一款新的高亮引擎 shiki,它底层用的 lexer 是 TextMate 的 language 文件,这也是 VSCode 所采用的。所以 shiki 可以支持和 VSCode 几乎一样的的语法高亮。我的博客也最近切换到了 shiki,它是我现在最推荐的高亮引擎。
Footnotes
- Highlight.js 很奇怪,
int
,object
能识别,但float
却没有 ↩ - 整体识别,而没有细致分词 ↩ ↩2 ↩3
- 只是一个例子,PyCharm 还有很多其他独有的分词元素 ↩