ShikiPHP
以纯 PHP 编写的语法高亮器,移植自 Shiki。使用 VS Code 主题和 TextMate 语法为代码块添加样式,无需 Node;在 214 个基准对照场景中,输出与 Shiki 3.23.0 一致。
composer require shikiphp/shikiphp最新版本 v0.1.0 MIT PHP 8.2+, ext-json, ext-mbstring
use Shikiphp\Shikiphp;
echo Shikiphp::codeToHtml("\e[31merror\e[0m: something broke", [
'lang' => 'ansi',
'theme' => 'github-dark',
]);实践应用
从 PHP 模板或构建脚本中高亮代码片段,并打印其返回的 HTML。
每个代码块调用一次
Shikiphp::codeToHtml 接收代码、语言 ID 和主题 ID。它会返回完整的 pre 块,并将颜色以内联方式写入,因此无需额外样式表即可渲染。
传入 themes 映射,而不是 theme,同一个代码块就会通过 CSS 变量同时携带浅色和深色。
use Shikiphp\Shikiphp;
echo Shikiphp::codeToHtml(<<<'PHP'
<?php
function greet(string $name): string {
return "Hello, {$name}!";
}
PHP, [
'lang' => 'php',
'theme' => 'github-dark',
]);use Shikiphp\Shikiphp;
$code = 'const answer: number = 42';
echo Shikiphp::codeToHtml($code, [
'lang' => 'ts',
'themes' => ['light' => 'github-light', 'dark' => 'github-dark'],
]);真实的 TextMate 语法
忠实移植自 vscode-textmate:支持嵌入式语言、注入和嵌套仓库。同样的语法会被 Shiki 和 VS Code 用于分词。
VS Code 主题
移植自 vscode-textmate 的作用域选择器优先级和父作用域匹配。通过 CSS 变量支持单主题或明暗双主题。
输出与 Shiki 完全一致
214 个 oracle 场景涵盖 253 种内置语法中的 167 种、ANSI 和全部 65 种主题;除了开头和结尾的空白外,结果都与 Shiki 3.23.0 的 HTML 完全一致,其正则表达式引擎为 JavaScript。
纯 PHP 正则表达式引擎
来自 inline0/phasis 的随附 JavaScript RegExp 引擎,由 oniguruma-to-es 移植版本驱动。Shiki 的 JavaScript 正则表达式引擎采用相同的 Oniguruma 到 RegExp 路径。
转换器
每个 Shiki 钩子(preprocess, tokens, root, pre, code, line, span, postprocess),以及内置的注释、元数据和空白字符转换器。
完整套件
所有 tm-grammars 语言(235,加上 18 种辅助语法)和 tm-themes 主题(65 种)均已包含。还包括 ANSI 终端输出、装饰和 colorReplacements。
CLI
使用 bin/shikiphp,直接从命令行高亮文件以输出到 HTML,或列出已捆绑的语言和主题。
无需 Node
可在 PHP 8.2+ 上运行,只需 ext-json 和 ext-mbstring。无需 Node 运行时、无需原生 Oniguruma 绑定,也无需调用外部命令。
为什么选择 ShikiPHP
在 PHP 所运行的环境中运行
代码高亮在 PHP 进程内完成,无需调用外部命令运行 Node,也无需调用托管的 API。适用于 Laravel、WordPress 或静态网站构建步骤。
可缓存的输出
相同代码使用相同选项时,总会生成相同的 HTML。可在构建时进行高亮,或以代码和选项为键缓存 HTML,直到源代码变更。
一个代码块兼顾明暗主题
主题映射会将第二个主题写为同一段标记中的 CSS 变量,只需几行 CSS 即可切换。defaultColor 选项决定以内联方式写入哪个主题。
为不可信输入设定限制
正则表达式引擎会记忆失败结果并防范 ReDoS,因此遇到病态模式时会变慢,而不会卡死。tokenizeMaxLineLength 选项会将超长行作为单个纯文本令牌输出。
对比
面向 PHP 网站的其他代码高亮方式,以及 ShikiPHP 的不同之处。
| 工具 | 擅长领域 | 与 ShikiPHP 的区别 |
|---|---|---|
| Shiki | 擅长领域位于 JavaScript 中的参考实现。它可在任何现代 JavaScript 运行时中运行,无需 Node.js API;按需加载语法和主题,并提供 TypeScript Twoslash 集成。 | 与 ShikiPHP 的区别ShikiPHP 将该流水线移植到 PHP,用于在 PHP 服务器上渲染的页面。它的 oracle 测试框架会将 HTML 与 Shiki 3.23.0 进行比较,而 Shiki 的主分支已经转向 v4。 |
| Phiki | 擅长领域一种 PHP 高亮器,同样使用 TextMate 语法和 VS Code 主题。它提供一个 league/commonmark 扩展,可与 Laravel 的 Str::markdown 配合使用,还支持终端输出和命令行二进制程序。 | 与 ShikiPHP 的区别Phiki 称其分词器的设计受 vscode-textmate 启发,但并非一对一翻译。ShikiPHP 移植了 vscode-textmate 和 oniguruma-to-es,并在 214 个 oracle 场景中将其 HTML 与 Shiki 的输出进行测试比较。 |
| highlight.php | 擅长领域一种服务端 PHP 移植版,源自 highlight.js,支持 185 种语言,采用原版的语言和样式定义,并能自动检测语言。 | 与 ShikiPHP 的区别ShikiPHP 使用 TextMate 语法进行分词,并使用 VS Code 主题着色;它使用与 Shiki 相同的文件,而且每次调用都会指定语言。 |
| Torchlight | 擅长领域兼容 VS Code 的代码高亮服务。它是一个 HTTP API,支持用于高亮、聚焦和差异标注的注释,并为 Laravel、CommonMark、Statamic 和其他技术栈提供官方客户端。 | 与 ShikiPHP 的区别ShikiPHP 在你的 PHP 进程中运行,无需托管 API。其内置的标注转换器会读取用于高亮、聚焦和差异行的注释。 |
问答
来自 ShikiPHP 文档的简明解答。
传入一个包含浅色和深色条目的主题映射。浅色会以内联颜色写入,深色则会写成 --shiki-dark 变量;添加一条简短的 CSS 规则,并将其作用域限定在 html.dark .shiki,即可启用这些变量。将 defaultColor 设为 false,即可仅输出变量。
包含 tm-grammars 1.31.15 的所有语法、235 种语言以及 18 种辅助语法,还有 tm-themes 的全部 65 种主题。运行 vendor/bin/shikiphp langs 或 vendor/bin/shikiphp themes 可列出这些 ID,也可以在高亮器上调用 bundledLanguages() 和 bundledThemes()。
可以。解码 .tmLanguage.json 文件,然后使用 loadGrammar 注册,并提供一个 ID 和可选别名;也可以使用 loadTheme 注册 VS Code 主题。请先注册其包含或嵌入的任何语法。
正则表达式引擎会记忆失败结果并提供 ReDoS 防护,因此遇到异常模式时会变慢,而不会卡死。设置 tokenizeMaxLineLength 后,达到或超过该长度的行会输出为单个纯文本 token。
文档不建议这样做。对于静态页面,请在构建时进行高亮;或者按代码和选项缓存渲染后的 HTML。在同一进程中,请复用一个高亮器;Shikiphp 门面会为你处理这件事。
Oracle 测试框架使用 Shiki 的 JavaScript 正则表达式引擎,将 ShikiPHP 的 HTML 与 Shiki 3.23.0 进行比较。其 214 个场景覆盖了 253 中 167 种打包语法、ANSI 和全部 65 种主题;选项和内置转换器也各自有一致性测试。
从入门指南开始,然后根据页面需要添加转换器、自定义语法或 ANSI 输出。