
# Architektūra

shikiphp paverčia pirminį kodą teminiu, paryškintu HTML, naudodama TextMate gramatikas ir VS Code temas. Jai nereikia jokių PHP plėtinių, išskyrus `json`/`mbstring`, Node vykdymo aplinkos ar savųjų Oniguruma sąsajų. Šiame puslapyje apžvelgiamas procesas; visa norminė specifikacija yra saugyklos `ARCHITECTURE.md`.

## Proceso eiga

```
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>
```

Viskas veikia **UTF-16 kodo vienetų** poslinkių erdvėje — tai ta pati erdvė, kurią naudoja JS regex sistema ir Shiki tokenizatorius. ASCII atveju ji sutampa su baitų poslinkiais.

## Regex vykdymo aplinka

Pačiame pagrinde yra `Shikiphp\Regex` — išsami grynojo PHP ECMAScript regex sistema, **įtraukta iš [`inline0/phasis`](https://github.com/inline0/phasis)** (grynojo PHP JavaScript sistema). Ji analizuoja JS RegExp šaltinį su vėliavėlėmis ir atlieka paiešką į priekį pagal Oniguruma `onig_search` semantiką.

## Oniguruma → JS konvertavimas

TextMate gramatikos rašomos Oniguruma kalba. `Shikiphp\Oniguruma\PatternConverter` yra PHP prievadas, perkeliantis [`oniguruma-to-es`](https://github.com/slevithan/oniguruma-to-es) funkcionalumą: jis paverčia Oniguruma šabloną į JS RegExp suderinamą šaltinio eilutę ir vėliavėlių eilutę, kurią regex sistema gali priimti. Tai tas pats kelias Oniguruma → RegExp, kuriuo naudojasi Shiki regex sistema JavaScript; todėl shikiphp gali sutapdinti jos išvestį pagal kiekvieną poslinkį. Konverteris apdoroja realiose gramatikose naudojamas konstrukcijas: POSIX klases, godžius kiekybinius operatorius ir atomines grupes, eilutines vėliavėles, pavadintas grupes ir atgalines nuorodas, Unicode savybes ir daugiau.

## Skeneris ir PCRE greitasis kelias

`Shikiphp\Oniguruma\OnigScanner` atkartoja `vscode-oniguruma` skenerio veikimą: kiekvienai taisyklei jis vieną kartą sudaromas iš šablonų sąrašo ir randa kairiausiai esantį atitikmenį nurodytoje pradinėje pozicijoje arba už jos.

Medžiu paremtas atitikmenų ieškiklis veikia teisingai, bet lėtai, todėl skeneris turi **lygiavertiškumu patvirtintą PCRE greitąjį kelią** su dviem lygiais. `PcreTranslator` perrašo konverterio JS šaltinio eilutę į savąjį PCRE šabloną tik tada, kai gali įrodyti, kad rezultatas:

- **Visas atitikmuo.** Jei vertimas veikia taip pat kaip atitikmenų ieškiklis, įskaitant kiekvieną fiksavimą, šablonas vykdomas tiesiogiai PCRE. Pavadintos grupės, atgalinės nuorodos, `\p{}`, `\b`, `\G`, atominių grupių imitavimas ir fiksavimai, kurių JavaScript semantika skiriasi nuo PCRE (kiekybiškai kartojamoje grupėje arba užnugaros patikroje), į šį lygį neįtraukiami.
- **Tik pozicija.** Jei skirtis gali tik fiksavimai, antrasis vertimas leidžia naudoti šias konstrukcijas (`\b` ir `\B` kaip tikslias ASCII užnugaros patikras, atomines grupes kaip savąsias `(?>…)` ir `\p{…}`, jei PCRE jas sukompiliuoja). Tada PCRE tik nustato kito atitikmens vietą, o atitikmenų ieškiklis iš naujo vykdomas tame poslinkyje, kad gautų tikruosius fiksavimus. Atgalinės nuorodos ir `\G` čia taip pat neleidžiamos.

Visa kita vykdoma tik pagal šablonų atitikiklį. Susietose gramatikose, esančiose Shiki 3.23.0, apie 39 % iš 14,234 skirtingų šablonų visiškai apdorojami PCRE, apie 57 % naudoja pozicijų lygmenį, o apie 4 % lieka atitikiklyje. Klasifikaciją tikrina kūrimo įrankis saugykloje (`bin/.oracle-tools/pcre-equivalence.php`), kuris lygina spartųjį kelią su atitikikliu — indeksą, pabaigą ir, pirmajame lygmenyje, kiekvieno užfiksavimo intervalo pradžią bei pabaigą — pagal scenarijų įvestis ir sintetinių eilučių rinkinį; leidžiama nulis neatitikimų.

## Gramatika ir tema

- **Gramatika** (`Shikiphp\Grammar`) yra tikslus `vscode-textmate` perkėlimas: `Registry` parenka gramatikas pagal aprėpties pavadinimą (įskaitant `include` nuorodas, įterptąsias kalbas ir įterpimus), o `Tokenizer` eilutė po eilutės tvarko taisyklių ir aprėpties stekus.
- **Tema** (`Shikiphp\Theme`) perkelia `vscode-textmate` temų parinkimo veikimą: priekinio plano spalva ir šrifto stilius parenkami pagal aprėpties parinkiklio konkretumą, atsižvelgiant į tėvinės aprėpties atitikmenis.

## Atvaizdavimas

`Shikiphp\Render\HtmlRenderer` sukuria tokį patį `pre.shiki > code > span.line >
span` HAST medį kaip Shiki, tada jį serializuoja. Vienos temos režimu įrašomos paprastos spalvos; dviejų temų režimu įrašomi `--shiki-light` / `--shiki-dark` CSS kintamieji.

## Patikrinta pagal Shiki

Pats Shiki yra etalonas; naudojama konkreti `shiki` 3.23.0 versija su jos JavaScript regex sistema. `scenarios/` kataloge yra **214** pavyzdžių: kiekvienas jų yra vienos kalbos ir vienos temos įvestis. Kartu jie aprėpia 253 iš 167 įtrauktų gramatikų, `lang: 'ansi'` ir visas 65 temas. `bin/test-regression` paryškina kiekvieną pavyzdį abiem sistemomis ir patikrina, kad HTML sutampa apkarpius pradžios ir pabaigos tarpus. Parinktys ir transformatoriai tikrinami palyginimo testais su išvestimi, gauta iš tos pačios Shiki ir `@shikijs/transformers` 4.2.0. Pagrindinė taisyklė nekinta: paryškinimo išvestis negali nukrypti nuo Shiki.
