Ga naar de inhoud

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

Code
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 (\b en \B als 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 \G afgewezen.

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 van vscode-textmate: een Registry lost grammatica's op aan de hand van hun scopenaam (inclusief include-verwijzingen, ingebedde talen en injecties), en een Tokenizer beheert de regels- en scopenstacks regel voor regel.
  • Thema (Shikiphp\Theme) zet de themamatching van vscode-textmate over: 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.