البنية
يحوّل shikiphp الشيفرة المصدرية إلى HTML مميزة وملونة باستخدام قواعد TextMate اللغوية وقوالب VS Code، من دون امتدادات PHP إضافية سوى json/mbstring، ومن دون وقت تشغيل Node أو ربط أصلي بـOniguruma. تلخص هذه الصفحة مسار المعالجة؛ أما العقد المعياري الكامل فيوجد في ARCHITECTURE.md بالمستودع.
مسار المعالجة
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>
تعمل جميع العمليات ضمن إزاحات وحدات ترميز UTF-16 — وهي المساحة نفسها التي يستخدمها محرك تعابير JS النمطية ومحلل الرموز في Shiki. وبالنسبة إلى ASCII، تساوي هذه إزاحات البايتات.
وقت تشغيل التعابير النمطية
في الأساس يوجد Shikiphp\Regex، وهو محرك كامل نقي لـPHP لتعابير ECMAScript النمطية، مضمّن من inline0/phasis (محرك PHP نقي لـJavaScript). يحلل مصدر JS-RegExp مع أعلامه، وينفّذ عمليات بحث أمامية بدلالات Oniguruma onig_search.
تحويل Oniguruma إلى JS
تُكتب قواعد TextMate باستخدام Oniguruma. Shikiphp\Oniguruma\PatternConverter
هو منفذ PHP لـ
oniguruma-to-es: يحوّل نمطًا من Oniguruma إلى مصدر متوافق مع JS-RegExp وسلسلة أعلام يقبلها محرك التعبيرات النمطية. هذا هو مسار التحويل نفسه من Oniguruma إلى RegExp الذي يستخدمه محرك التعبيرات النمطية JavaScript في Shiki، ما يتيح لـ shikiphp مطابقة مخرجات ذلك المحرك بدقة، إزاحةً بإزاحة. يتعامل المحوّل مع تراكيب القواعد المستخدمة فعليًا: فئات POSIX، والمكررات الاستحواذية والمجموعات الذرية، والأعلام المضمنة، والمجموعات المسماة والإحالات الخلفية، وخصائص Unicode، وغير ذلك.
الماسح ومسار PCRE السريع
يحاكي Shikiphp\Oniguruma\OnigScanner الماسح في vscode-oniguruma: يُنشأ مرة واحدة لكل قاعدة من قائمة أنماط، ويعثر على أول تطابق من اليسار عند موضع البداية أو بعده.
مطابق اجتياز الشجرة صحيح لكنه بطيء، لذا يتضمن الماسح مسار PCRE سريعًا مشروطًا بالتكافؤ على مستويين. يعيد PcreTranslator كتابة مصدر JS الخاص بالمحوّل كنمط PCRE أصلي فقط عندما يمكنه إثبات النتيجة:
- تطابق كامل. عندما تكون الترجمة مطابقة للمطابق، بما في ذلك كل عمليات الالتقاط، يُنفَّذ النمط مباشرةً عبر PCRE. تُرفض من هذا المستوى المجموعات المسماة ومراجعها الخلفية، و
\p{}، و\b، و\G، ومحاكاة المجموعات الذرية، وعمليات الالتقاط التي تختلف دلالاتها في JavaScript عن PCRE (داخل مجموعة مكررة أو نظرة خلفية). - الموضع فقط. عندما يكون الاختلاف المحتمل في عمليات الالتقاط وحدها، تسمح ترجمة ثانية بهذه البنى (
\bو\Bكنظرات أمامية وخلفية ASCII دقيقة، والمجموعات الذرية كـ(?>…)أصلية، و\p{…}إذا نجح PCRE في ترجمتها). عندئذٍ يعثر PCRE على موضع التطابق التالي فقط، ثم يعيد المطابق التشغيل عند ذلك الموضع لإنتاج عمليات الالتقاط الفعلية. وتظل المراجع الخلفية و\Gمرفوضة هنا أيضًا.
تعمل كل الحالات الأخرى باستخدام المطابق وحده. بالنسبة إلى القواعد المضمّنة في Shiki 3.23.0، يعمل نحو 39% من الأنماط المميزة البالغ عددها 14,234 بالكامل عبر PCRE، ويستخدم نحو 57% مستوى الموضع، بينما يبقى نحو 4% على المطابق. تتحقق أداة تطوير في المستودع من التصنيف (bin/.oracle-tools/pcre-equivalence.php)، إذ تقارن المسار السريع بالمطابق — الفهرس والنهاية، ولكل عملية التقاط في المستوى الأول نطاقها — عبر مدخلات السيناريوهات ومجموعة من السلاسل الاصطناعية، مع اشتراط عدم وجود أي اختلاف.
القواعد والسمات
- القواعد (
Shikiphp\Grammar) منفذ أمين لـvscode-textmate: يحلRegistryالقواعد حسب اسم النطاق (بما في ذلك مراجعincludeواللغات المضمنة وعمليات الحقن)، ويحافظTokenizerعلى مكدسات القواعد والنطاقات سطرًا بسطر. - السمة (
Shikiphp\Theme) تنقل آلية مطابقة السمات فيvscode-textmate: تُحدَّد ألوان المقدمة وأنماط الخط وفق أولوية محدد النطاق، مع مطابقة النطاقات الأصلية.
العرض
ينشئ Shikiphp\Render\HtmlRenderer شجرة HAST مطابقة تمامًا لما ينشئه pre.shiki > code > span.line > span Shiki، ثم يحولها إلى تسلسل. يكتب وضع القالب الواحد ألوانًا عادية؛ أما وضع القالبين فيكتب متغيرات --shiki-light / --shiki-dark CSS.
التحقق بالمقارنة مع Shiki
Shiki نفسه هو المرجع، بإصدار مثبت عند shiki 3.23.0 ومحرك التعبيرات النمطية JavaScript الخاص به. يحتوي مجلد scenarios/ على 214 حالة اختبار، تمثل كل واحدة منها مدخلًا بلغة وسمة واحدة؛ وهي تغطي مجتمعةً 167 من أصل 253 قاعدة مضمّنة، وlang: 'ansi'، والسمات الـ65 كلها. يبرز bin/test-regression كل حالة بالمحركين ويتحقق من تطابق HTML بعد إزالة المسافات البيضاء في البداية والنهاية. وتُفحص الخيارات والمحولات باختبارات التكافؤ مع مخرجات محفوظة من إصداري Shiki و@shikijs/transformers نفسيهما 4.2.0.
القاعدة الحاسمة هي ألا تتراجع مخرجات التمييز اللوني عن Shiki.