
# البنية

يحوّل 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`](https://github.com/inline0/phasis)** (محرك PHP نقي لـJavaScript). يحلل مصدر JS-RegExp مع أعلامه، وينفّذ عمليات بحث أمامية بدلالات Oniguruma `onig_search`.

## تحويل Oniguruma إلى JS

تُكتب قواعد TextMate باستخدام Oniguruma. `Shikiphp\Oniguruma\PatternConverter`
هو منفذ PHP لـ
[`oniguruma-to-es`](https://github.com/slevithan/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.
