Architectuur
shikiphp zet broncode om in gemarkeerde HTML met thema's, met grammaticaregels van TextMate en thema's van VS Code, zonder PHP-extensies buiten json/mbstring, zonder Node-runtime en zonder native Oniguruma-binding. Deze pagina vat de pipeline samen; het volledige normatieve contract staat in ARCHITECTURE.md in de repository.
De pipeline
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>
Alles werkt met offsets in UTF-16-code-eenheden — dezelfde ruimte als de regex-engine JS en de tokenizer van Shiki. Voor ASCII zijn deze gelijk aan byte-offsets.
De regex-runtime
Onderaan staat Shikiphp\Regex, een volledige pure PHP ECMAScript-regex-engine, meegeleverd vanuit inline0/phasis (een pure PHP-JavaScript-engine). Deze verwerkt een JS-RegExp-bron plus flags en voert zoekopdrachten vooruit uit met semantiek Oniguruma onig_search.
Conversie van Oniguruma naar JS
TextMate-grammatica's zijn geschreven in Oniguruma. Shikiphp\Oniguruma\PatternConverter is een PHP-port van oniguruma-to-es: het zet een Oniguruma-patroon om in een bron- en flags-string die compatibel zijn met JS-RegExp en die de regex-engine accepteert. Dit is hetzelfde pad Oniguruma → RegExp dat de regex-engine van Shiki's JavaScript volgt, waardoor shikiphp de uitvoer van die engine offset voor offset kan evenaren. De converter verwerkt de constructies die in echte grammatica's worden gebruikt: POSIX-klassen, possessieve kwantoren en atomic groups, inline flags, benoemde groepen en backreferences, Unicode-eigenschappen en meer.
De scanner en de PCRE-snelroute
Shikiphp\Oniguruma\OnigScanner weerspiegelt de scanner van vscode-oniguruma: deze wordt eenmaal per regel opgebouwd op basis van een lijst patronen en vindt de meest linkse overeenkomst op of na een startpositie.
De boomwandelende matcher is correct maar niet snel, dus heeft de scanner een op equivalentie gecontroleerde PCRE-snelroute met twee niveaus. Een PcreTranslator herschrijft de JS-bron van de converter alleen naar een native PCRE-patroon wanneer het resultaat bewezen kan worden:
- Volledige overeenkomst. Als de vertaling zich identiek gedraagt aan de matcher, inclusief elke capture, wordt het patroon direct in PCRE uitgevoerd. Benoemde groepen, backreferences,
\p{},\b,\G, atomic emulation en captures waarvan de semantiek van JavaScript afwijkt van PCRE (binnen een herhaalde groep of een lookbehind) worden op dit niveau afgewezen. - Alleen positie. Als alleen captures kunnen verschillen, accepteert een tweede vertaling die constructies (
\ben\Bals exacte ASCII-lookarounds, atomic groups als native(?>…),\p{…}wanneer PCRE dit compileert). PCRE vindt dan alleen de positie van de volgende overeenkomst; de matcher wordt op die offset opnieuw uitgevoerd om de echte captures te produceren. Ook hier blijven backreferences en\Gafgewezen.
Al het overige wordt alleen door de matcher uitgevoerd. Van de gebundelde grammatica's op Shiki 3.23.0 wordt ongeveer 39% van de 14,234 unieke patronen volledig met PCRE uitgevoerd, gebruikt ongeveer 57% het positieniveau en blijft ongeveer 4% bij de matcher. Een ontwikkeltool in de repository (bin/.oracle-tools/pcre-equivalence.php) controleert de classificatie door de snelroute met de matcher te vergelijken — index, einde en voor het eerste niveau elke capture-span — op basis van de scenario-invoer en een reeks synthetische strings, waarbij geen enkele afwijking is toegestaan.
Grammatica en thema
- Grammatica (
Shikiphp\Grammar) is een getrouwe port vanvscode-textmate: eenRegistrylost grammatica's op aan de hand van hun scopenaam (inclusiefinclude-verwijzingen, ingebedde talen en injecties), en eenTokenizerbeheert de regels- en scopenstacks regel voor regel. - Thema (
Shikiphp\Theme) zet de themamatching vanvscode-textmateover: voorgrondkleur en letterstijl worden bepaald op basis van de specificiteit van de scope-selector, met matching van bovenliggende scopes.
Weergave
Shikiphp\Render\HtmlRenderer bouwt exact dezelfde HAST-boom pre.shiki > code > span.line > span als Shiki en serialiseert die vervolgens. De modus met één thema schrijft gewone kleuren; de modus met twee thema’s schrijft de CSS-variabelen --shiki-light / --shiki-dark.
Gevalideerd aan de hand van Shiki
Shiki zelf is de oracle, vastgepind op shiki 3.23.0 met zijn JavaScript-regex-engine. De map scenarios/ bevat 214 fixtures, elk met één invoer in één taal en één thema; samen dekken ze 167 van de 253 gebundelde grammatica's, lang: 'ansi' en alle 65 thema's. bin/test-regression markeert elk ervan met beide engines en controleert dat de HTML identiek is na het verwijderen van witruimte aan het begin en einde. Opties en transformers worden gecontroleerd met pariteitstests aan de hand van uitvoer die is vastgelegd van dezelfde Shiki en @shikijs/transformers 4.2.0. De harde eis is dat de markeringsuitvoer niet mag verslechteren ten opzichte van Shiki.