
# Архитектура

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`](https://github.com/inline0/phasis)** (regex енджин, написан изцяло на PHP JavaScript). Той анализира изходен код на JS-RegExp заедно с флаговете и изпълнява търсения напред със семантика Oniguruma `onig_search`.

## Преобразуване от Oniguruma към JS

Граматиките TextMate са написани на Oniguruma. `Shikiphp\Oniguruma\PatternConverter`
е пренасяне на PHP на
[`oniguruma-to-es`](https://github.com/slevithan/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.
