Към съдържанието

Архитектура

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.