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
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 (
\boch\Bsom 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\Gavvisas ä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 avvscode-textmate: enRegistrylöser grammatiker efter scope-namn (inklusiveinclude-referenser, inbäddade språk och injektioner), och enTokenizerhanterar regel- och scope-stackarna rad för rad. - Tema (
Shikiphp\Theme) porterar temamatchningen ivscode-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.