Preskočiť na obsah

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

Kód
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 (\b a \B ako 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 \G zostá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ý port vscode-textmate: Registry rozlišuje gramatiky podľa názvu oblasti platnosti (vrátane odkazov include, vložených jazykov a injekcií) a Tokenizer spravuje zásobníky pravidiel a oblastí platnosti po jednotlivých riadkoch.
  • Téma (Shikiphp\Theme) prenáša spôsob priraďovania tém v vscode-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.