Hoppa till innehåll

Arkitektur

shikiphp omvandlar källkod till temafärgad, markerad HTML med hjälp av TextMate-grammatiker och VS Code-teman, utan några PHP-tillägg utöver json/mbstring, ingen Node- körmiljö och ingen inbyggd Oniguruma-bindning. Den här sidan sammanfattar flödet; det fullständiga normativa avtalet finns i ARCHITECTURE.md i arkivet.

Flödet

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

Allt arbetar med offsetar i UTF-16-kodenheter — samma utrymme som regexmotorn JS och tokeniseraren i Shiki. För ASCII motsvarar detta byteoffsetar.

Regexkörmiljön

I botten finns Shikiphp\Regex, en komplett ECMAScript-regexmotor i ren PHP medföljande från inline0/phasis (en regexmotor i ren PHP JavaScript). Den tolkar en JS-RegExp-källa plus flaggor och kör framåtsökningar med semantik enligt Oniguruma onig_search.

Konvertering från Oniguruma till JS

TextMate-grammatiker skrivs i Oniguruma. Shikiphp\Oniguruma\PatternConverter är en PHP-portering av oniguruma-to-es: den omvandlar ett Oniguruma-mönster till en källa och en flaggsträng som är kompatibla med JS-RegExp och som regexmotorn godtar. Det är samma väg från Oniguruma till RegExp som regexmotorn i Shiki JavaScript följer, vilket gör att shikiphp kan matcha motorns resultat offset för offset. Konverteraren hanterar de konstruktioner som används i verkliga grammatiker: POSIX-klasser, possessiva kvantifierare och atomära grupper, inline-flaggor, namngivna grupper och bakåtreferenser, Unicode-egenskaper med mera.

Skannern och dess snabba PCRE-väg

Shikiphp\Oniguruma\OnigScanner efterliknar skannern i vscode-oniguruma: den byggs en gång per regel från en lista med mönster och hittar den vänstraste matchningen vid eller efter en startposition.

Matcharen som går igenom trädet är korrekt men långsam, så skannern har en PCRE-snabbväg med ekvivalenskontroll i två nivåer. En PcreTranslator skriver om konverterarens JS-källa till ett inbyggt PCRE-mönster endast när den kan bevisa resultatet:

  • Fullständig matchning. När översättningen fungerar identiskt med matcharen, inklusive varje fångst, körs mönstret direkt i PCRE. Namngivna grupper, bakåtreferenser, \p{}, \b, \G, emulering av atomära grupper och fångster vars semantik för JavaScript skiljer sig från PCRE (inuti en kvantifierad grupp eller en lookbehind) avvisas på den här nivån.
  • Endast position. När bara fångsterna kan skilja sig tillåter en andra översättning dessa konstruktioner (\b och \B som exakta ASCII-lookarounds, atomära grupper som inbyggd (?>…), \p{…} när PCRE kan kompilera det). PCRE hittar då bara positionen för nästa matchning, och matcharen körs igen vid den offseten för att ta fram de faktiska fångsterna. Bakåtreferenser och \G avvisas även här.

Allt annat körs enbart med matcharen. För de paketerade grammatikerna vid Shiki 3.23.0 körs cirka 39 % av de 14,234 distinkta mönstren helt i PCRE, cirka 57 % använder positionsnivån och cirka 4 % körs med matcharen. Klassificeringen kontrolleras av ett utvecklingsverktyg i arkivet (bin/.oracle-tools/pcre-equivalence.php), som jämför snabbvägen med matcharen — index, slut och, för den första nivån, varje fångstintervall — för scenariernas indata och en uppsättning syntetiska strängar, utan att några avvikelser tillåts.

Grammatik och tema

  • Grammatik (Shikiphp\Grammar) är en trogen portering av vscode-textmate: en Registry löser grammatiker efter scope-namn (inklusive include-referenser, inbäddade språk och injektioner), och en Tokenizer hanterar regel- och scope-stackarna rad för rad.
  • Tema (Shikiphp\Theme) porterar temamatchningen i vscode-textmate: förgrund och teckensnittsformat löses utifrån scope-väljarens specificitet och matchning av överordnade scope.

Rendering

Shikiphp\Render\HtmlRenderer bygger det exakta pre.shiki > code > span.line > span HAST-trädet Shiki bygger och serialiserar det sedan. I läget med ett tema skrivs vanliga färger; i läget med två teman skrivs variablerna --shiki-light / --shiki-dark CSS.

Validerat mot Shiki

Shiki är själv facit, låst till shiki 3.23.0 med sin JavaScript-regexmotor. Katalogen scenarios/ innehåller 214 testfall, där varje testfall är en indata i ett språk och ett tema. Tillsammans täcker de 167 av de 253 paketerade grammatikerna, lang: 'ansi' och alla 65 teman. bin/test-regression markerar varje kodprov med båda motorerna och kontrollerar att resultatet i HTML är identiskt efter att inledande och avslutande blanksteg tagits bort. Alternativ och transformatorer kontrolleras med paritetstester mot resultat som fångats från samma Shiki och @shikijs/transformers 4.2.0. Den ofrånkomliga regeln är att markeringsresultatet inte får försämras jämfört med Shiki.