Architektúra
shikiphp mení zdrojový kód na zvýraznené HTML so štýlmi tém pomocou gramatík TextMate a tém VS Code, bez rozšírení PHP okrem json/mbstring, bez runtime prostredia Node a bez natívnej väzby Oniguruma. Táto stránka sumarizuje proces; úplná normatívna špecifikácia sa nachádza v ARCHITECTURE.md v repozitári.
Proces spracovania
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>
Všetko pracuje s posunmi v priestore kódových jednotiek UTF-16 — rovnakom ako v regexovom engine JS a v tokenizátore Shiki. Pri ASCII sa tieto posuny rovnajú bajtovým posunom.
Runtime prostredie regexov
Základom je Shikiphp\Regex, úplný čistý regexový engine ECMAScript PHP, prevzatý z inline0/phasis (čistý engine PHP JavaScript). Parsuje zdrojový kód JS-RegExp aj príznaky a vykonáva dopredné vyhľadávanie so sémantikou Oniguruma onig_search.
Konverzia Oniguruma → JS
Gramatiky TextMate sú napísané v jazyku Oniguruma. Shikiphp\Oniguruma\PatternConverter je port PHP projektu oniguruma-to-es: prevádza vzor Oniguruma na zdrojový kód a reťazec príznakov kompatibilné s JS-RegExp, ktoré regexový engine dokáže spracovať. Ide o rovnaký prevod Oniguruma → RegExp, aký používa regexový engine ShikiJavaScript, vďaka čomu môže shikiphp presne porovnať jeho výstup vrátane posunov. Konvertor spracuje aj konštrukcie používané v reálnych gramatikách: triedy POSIX, výlučné kvantifikátory a atómové skupiny, vložené príznaky, pomenované skupiny a spätné odkazy, vlastnosti Unicode a ďalšie.
Skener a jeho rýchla cesta PCRE
Shikiphp\Oniguruma\OnigScanner napodobňuje skener vscode-oniguruma: zostaví sa raz pre každé pravidlo zo zoznamu vzorov a nájde najskoršiu zhodu na danej pozícii alebo za ňou.
Matcher, ktorý prechádza strom, je správny, ale pomalý, preto má skener rýchlu cestu PCRE podmienenú ekvivalenciou s dvoma úrovňami. Konvertor PcreTranslator prepíše zdrojový kód JS na natívny vzor PCRE iba vtedy, keď dokáže výsledok zaručiť:
- Úplná zhoda. Ak sa preklad správa rovnako ako porovnávač vrátane všetkých zachytení, vzor sa vykoná priamo v PCRE. Pomenované skupiny, spätné odkazy,
\p{},\b,\G, emulácia atómových skupín a zachytenia, ktorých sémantika JavaScript sa líši od PCRE (vo vnútri kvantifikovanej skupiny alebo spätného náhľadu), sú z tejto úrovne vylúčené. - Iba pozícia. Ak sa môžu líšiť len zachytenia, druhý preklad povolí tieto konštrukcie (
\ba\Bako presné ASCII spätné náhľady, atómové skupiny ako natívne(?>…),\p{…}, ak ich PCRE skompiluje). PCRE potom iba nájde pozíciu ďalšej zhody a porovnávač sa na tomto posune spustí znova, aby vytvoril skutočné zachytenia. Spätné odkazy a\Gzostávajú aj tu vylúčené.
Všetko ostatné spracúva iba matcher. Pri gramatikách dodávaných v Shiki 3.23.0 sa približne 39 % z 14,234 rôznych vzorov spracúva úplne cez PCRE, približne 57 % využíva úroveň pozície a približne 4 % zostávajú na matcheri. Klasifikáciu kontroluje vývojový nástroj v repozitári (bin/.oracle-tools/pcre-equivalence.php), ktorý porovnáva rýchlu cestu s matcherom — index, koniec a pri prvej úrovni aj rozsah každej zachytenej skupiny — pre scenáre a množinu syntetických reťazcov. Nulový počet odchýlok je povinný.
Gramatika a téma
- Gramatika (
Shikiphp\Grammar) je verný portvscode-textmate:Registryrozlišuje gramatiky podľa názvu oblasti platnosti (vrátane odkazovinclude, vložených jazykov a injekcií) aTokenizerspravuje zásobníky pravidiel a oblastí platnosti po jednotlivých riadkoch. - Téma (
Shikiphp\Theme) prenáša spôsob priraďovania tém vvscode-textmate: farba popredia a štýl písma sa určujú podľa špecifickosti selektora oblasti platnosti a zhody s nadradenou oblasťou.
Vykresľovanie
Shikiphp\Render\HtmlRenderer vytvorí presne taký strom HAST pre.shiki > code > span.line > span, aký vytvára Shiki, a potom ho serializuje. Režim jednej témy zapisuje obyčajné farby; režim dvoch tém zapisuje premenné --shiki-light / --shiki-dark CSS.
Overené voči Shiki
Samotné Shiki slúži ako referenčná implementácia a je pripnuté k shiki 3.23.0 s regexovým enginom JavaScript. Adresár scenarios/ obsahuje 214 testovacích prípadov; každý predstavuje jeden vstup v jednom jazyku a jednej téme. Spolu pokrývajú 167 z 253 pribalených gramatík, lang: 'ansi' a všetkých 65 tém. bin/test-regression zvýrazní každý prípad oboma enginmi a overí, že HTML je po odstránení úvodných a koncových medzier totožný. Možnosti a transformátory sa kontrolujú testami zhody s výstupom zachyteným z rovnakého Shiki a @shikijs/transformers 4.2.0. Neprekročiteľným pravidlom je, že výstup zvýrazňovania sa nesmie zhoršiť oproti Shiki.