Архитектура
shikiphp преобразува изходния код в оцветени HTML с граматики TextMate и теми VS Code, без разширения PHP извън json/mbstring, без среда за изпълнение на Node и без собствена обвивка Oniguruma. Тази страница обобщава конвейера; пълният нормативен договор се намира в ARCHITECTURE.md в хранилището.
Конвейерът
source code
└─ Highlighter::codeToTokens()
├─ Grammar\Registry loads the grammar (+ its includes / embedded langs)
├─ Grammar\Tokenizer line by line, driving an OnigScanner per rule state
│ └─ Oniguruma\OnigScanner.findNextMatch()
│ └─ Oniguruma\PatternConverter Oniguruma pattern → JS regex
│ └─ Shikiphp\Regex (Parser + Matcher) JS RegExp runtime
├─ Theme\Theme.match(scopeStack) → StyleAttributes per token
└─ Render\ThemedToken[] (text + style) per line
└─ Render\HtmlRenderer → <pre class="shiki">…</pre>
Всичко работи в пространството на отместванията на 16-битовите кодови единици на UTF-16 — същото като regex енджина JS и токенизатора на Shiki. За ASCII това съвпада с отместванията в байтове.
Средата за изпълнение на regex
В основата е Shikiphp\Regex, пълен ECMAScript regex енджин, написан изцяло на PHP и взет от inline0/phasis (regex енджин, написан изцяло на PHP JavaScript). Той анализира изходен код на JS-RegExp заедно с флаговете и изпълнява търсения напред със семантика Oniguruma onig_search.
Преобразуване от Oniguruma към JS
Граматиките TextMate са написани на Oniguruma. Shikiphp\Oniguruma\PatternConverter
е пренасяне на PHP на
oniguruma-to-es: преобразува
шаблон Oniguruma в изходен код и низ с флагове, съвместими с JS-RegExp, които regex енджинът приема. Това е същият път от Oniguruma към RegExp, който използва regex енджинът на Shiki JavaScript, което позволява на shikiphp да съвпада с изхода на този енджин отместване по отместване. Конверторът
обработва използваните в реални граматики конструкции: POSIX класове, притежателни квантификатори и атомарни групи, вградени флагове, именувани групи и обратни препратки,
свойства Unicode и още.
Скенерът и бързият път на PCRE
Shikiphp\Oniguruma\OnigScanner следва скенера на vscode-oniguruma: изгражда се веднъж за всяко правило от списък с шаблони и намира най-лявото съвпадение на или след началната позиция.
Съпоставянето чрез обхождане на дървото е коректно, но бавно, затова скенерът има бърз път на PCRE с проверка за еквивалентност, на две нива. PcreTranslator преобразува изходния код JS на конвертора в нативен шаблон на PCRE само когато може да докаже резултата:
- Пълно съвпадение. Когато преобразуването се държи идентично на съпоставителя, включително за всяка група за улавяне, шаблонът се изпълнява директно в PCRE. Именувани групи, обратни препратки,
\p{},\b,\G, емулация на атомарни групи и улавяния със семантика JavaScript, различна от PCRE (вътре в квантифицирана група или поглед назад), се изключват от това ниво. - Само позиция. Когато могат да се различават само улавянията, второ преобразуване допуска тези конструкции (
\bи\Bкато точни ASCII погледи, атомарни групи като нативни(?>…),\p{…}ако PCRE го компилира). PCRE намира само позицията на следващото съвпадение, а съпоставителят изпълнява повторно търсене от това отместване, за да получи реалните улавяния. Обратните препратки и\Gсъщо остават изключени тук.
Всичко останало се обработва само от съпоставителя. За включените граматики при Shiki 3.23.0 около 39% от 14,234 различни шаблона се изпълняват изцяло в PCRE, около 57% използват нивото за позиция, а около 4% остават при съпоставителя. Класификацията се проверява с инструмент за разработка в хранилището (bin/.oracle-tools/pcre-equivalence.php), който сравнява бързия път със съпоставителя — индекс, край и за първото ниво всеки диапазон на улавяне — върху входните сценарии и набор синтетични низове, като не се допуска нито едно разминаване.
Граматика и тема
- Граматика (
Shikiphp\Grammar) е прецизно пренасяне наvscode-textmate:Registryразрешава граматиките по име на обхват (включително препраткиinclude, вградени езици и инжекции), аTokenizerподдържа стековете с правила и обхвати ред по ред. - Тема (
Shikiphp\Theme) пренася съпоставянето на теми наvscode-textmate: цветът на предния план и стилът на шрифта се определят според специфичността на селектора за обхват и съвпадението с родителски обхвати.
Визуализиране
Shikiphp\Render\HtmlRenderer изгражда точното дърво HAST pre.shiki > code > span.line > span, създадено от Shiki, след което го сериализира. В режим с една тема се записват обикновени цветове; в режим с две теми — променливи --shiki-light / --shiki-dark CSS.
Проверено спрямо Shiki
Самият Shiki служи за еталон и е фиксиран към shiki 3.23.0 със своя regex енджин JavaScript. Директорията scenarios/ съдържа 214 примерни набора, всеки с един входен текст, един език и една тема; общо те обхващат 167 от 253 включените граматики, lang: 'ansi' и всички 65 теми. bin/test-regression оцветява всеки от тях с двата енджина и проверява, че HTML е идентичен след изрязване на началните и крайните интервали. Опциите и трансформаторите се проверяват с тестове за съответствие спрямо изход, заснет от същите Shiki и @shikijs/transformers 4.2.0.
Основното изискване е оцветяването да не се влошава спрямо Shiki.