Перейти к содержимому

shikiphp

shikiphp — полностью реализованный на PHP порт Shiki, подсветчика синтаксиса, который использует те же грамматики TextMate и темы, что и VS Code. Он разбивает код на токены с помощью тех же грамматик TextMate и окрашивает его теми же темами VS Code, которые использует Shiki, создавая тот же HTML, что и Shiki 3.23.0, — целиком на PHP.

Без среды выполнения Node. Никаких расширений PHP, кроме json и mbstring. Никаких нативных привязок Oniguruma. Никакого запуска отдельного процесса JavaScript и никакого размещённого API.

PHP
use Shikiphp\Shikiphp;

echo Shikiphp::codeToHtml(<<<'PHP'
<?php
function greet(string $name): string {
    return "Hello, {$name}!";
}
PHP, [
    'lang'  => 'php',
    'theme' => 'github-dark',
]);

Почему shikiphp

Подсветка синтаксиса при рендеринге на сервере в PHP обычно требует одного из трёх компромиссов: запуска отдельного процесса Node, обращения к размещённому API или использования подсветчика на регулярных выражениях, который на самом деле не понимает язык. Ни один из этих вариантов не подходит для этапа сборки Laravel, WordPress или статического сайта.

shikiphp устраняет этот компромисс, перенося настоящий конвейер Shiki на PHP:

  • токенизатор грамматик TextMate (точный порт vscode-textmate), включая встроенные языки, инъекции и вложенные репозитории
  • разрешение тем VS Code с учётом специфичности селекторов областей и соответствия родительским областям
  • совместимый с Shiki HTML: двойные светлая и тёмная темы через переменные CSS, codeToHast, трансформеры (все хуки), декорации, colorReplacements, structure: 'inline' и подсветка ANSI (lang: 'ansi')
  • полный комплект Shiki — все языки tm-grammars (235 и 18 вспомогательных грамматик, которые они встраивают) и все темы tm-themes (65)

Сопоставление с Shiki 3.23.0

Результат не просто «достаточно близкий»: он проверяется по закреплённому выпуску Shiki.

Пакет Версия Назначение
shiki 3.23.0 эталон; запускается с регулярным движком JavaScript
tm-grammars 1.31.15 встроенные грамматики
tm-themes 1.12.2 встроенные темы
@shikijs/transformers 4.2.0 тесты на соответствие трансформеров

Сам Shiki служит эталоном. В набор регрессионных тестов входит 214 сценариев — в каждом образец одного языка и одной темы с параметрами по умолчанию. Каждый сценарий подсвечивают и Shiki, и shikiphp; после удаления начальных и конечных пробелов обе строки HTML должны совпадать. В совокупности сценарии охватывают 167 из 253 встроенных грамматик, lang: 'ansi' и все 65 тем. Параметры (structure, tabindex, colorReplacements, двойные темы, defaultColor и прочие), codeToTokensWithThemes и встроенные трансформеры проверяются отдельными тестами на соответствие; ожидаемый вывод для них получен из тех же версий Shiki.

Из этого следуют два ограничения. Стандартный движок Shiki — это Oniguruma, скомпилированный в WebAssembly, а в эталоне используется регулярный движок JavaScript из Shiki — тот же, что переносит shikiphp. Кроме того, более поздние выпуски Shiki (линейка 4.x) ещё не проверялись.

Как это работает

shikiphp построен на встроенном регулярном движке JavaScript с открытым исходным кодом, написанном на чистом PHP, из inline0/phasis; в его основе — порт PHP для oniguruma-to-es. Регулярный движок JavaScript из Shiki преобразует шаблоны Oniguruma в грамматиках TextMate в JavaScript RegExp, поэтому движок JS — естественная основа: он позволяет shikiphp сопоставлять результат этого движка вплоть до смещений.

Код
code → grammar tokenizer → theme resolver → themed tokens → HTML
              │
              └─ OnigScanner → PatternConverter (oniguruma-to-es) → Shikiphp\Regex (JS RegExp engine)

Полный конвейер см. в разделе Архитектура.

Требования

  • PHP 8.2 или новее (в CI набор тестов запускается на PHP 8.4)
  • ext-json и ext-mbstring (входят почти в каждую сборку PHP)

Что читать дальше

  • Начало работы — установка и создание первого блока.
  • API — полный перечень методов.
  • Параметры — все параметры, которые принимает codeToHtml.
  • Трансформеры — конвейер хуков и встроенные трансформеры.
  • CLI — bin/shikiphp highlight, langs и themes.

Лицензия

MIT, авторские права принадлежат inline0. Встроенные грамматики и темы TextMate распространяются на условиях своих исходных лицензий.