diff --git "a/text/0000-\330\245\331\203\331\205\330\247\331\204-\330\257\331\210\330\247\331\204-UICore-\331\201\331\212-\330\247\331\204\331\205\330\252\330\261\330\254\331\205.md" "b/text/0000-\330\245\331\203\331\205\330\247\331\204-\330\257\331\210\330\247\331\204-UICore-\331\201\331\212-\330\247\331\204\331\205\330\252\330\261\330\254\331\205.md" new file mode 100644 index 0000000..940b7f3 --- /dev/null +++ "b/text/0000-\330\245\331\203\331\205\330\247\331\204-\330\257\331\210\330\247\331\204-UICore-\331\201\331\212-\330\247\331\204\331\205\330\252\330\261\330\254\331\205.md" @@ -0,0 +1,54 @@ +- **عنوان المقترح:** إكمال دوال UICore (corui) الستّ في مترجم LLVM بتكافؤ كامل مع المفسّر +- **النطاق:** لغة `text/` (نواة الواجهة `features/graphics` + جسر المترجم) +- **تاريخ البدء:** 2026-07-02 +- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج) +- **الحالة:** مقترَح (PR مفتوح) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +إكمال الدوال الستّ المتبقّية من نواة الواجهة UICore في **مترجم LLVM** (`sad-build`) لتبلغ التكافؤ الكامل مع المفسّر (`sad-run`): `توليد_ويب`، `انتقل_بتحريك_كامل`، `تحديث_حالة`، `عين_الحالة`، `عنوان_النافذة`، `أغلق_النافذة`. بذلك يصير المترجم مكافئًا للمفسّر في **كامل كتالوج UICore**. المنطق كلّه في مكتبة الرسومات (`features/graphics`)؛ المحرّكان جسرٌ رفيع لا أكثر. + +# الدافع (Motivation) + +كان المفسّر يدعم الدوال الستّ بينما المترجم لا (فجوة تكافؤ S/L). الأخطر: عمليّات النافذة (عنوان/إغلاق) لم يكن لها نظيرٌ مكتبيّ مشترك — المفسّر يلمس نافذته مباشرةً، ولا سبيل للمترجم للوصول إلى نافذته المحلّيّة في `sad_app_run`. أيضًا `توليد_ويب` (تحويل شجرة العنصر إلى HTML) كان حكرًا على المفسّر رغم أنّ منطقه (`HtmlCodegen`) يعيش في المكتبة سلفًا. + +# الشرح التوجيهي (Guide-level explanation) + +الدوال الستّ تعمل الآن في المحرّكين بمخرَجٍ متطابق: + +- `توليد_ويب(عنصر, عنوان؟)` ⇒ نصّ HTML كامل (يقبل عنصرًا أو دالّة بناء). +- `انتقل_بتحريك_كامل(صفحة, دخول, خروج, مدة؟)` ⇒ تنقّل + انتقال دخول بصريّ. +- `تحديث_حالة()` / `عين_الحالة(دالّة_تحديث؟)` ⇒ إعادة رسم (والأخيرة تستدعي دالّة التحديث أوّلًا). +- `عنوان_النافذة(نص)` / `أغلق_النافذة()` ⇒ التحكّم بالنافذة الحيّة. + +# الشرح المرجعي (Reference-level explanation) + +- **مصدر الحقيقة (`language-truth/`):** لا تغيير — الدوال الستّ مُعرَّفة سلفًا في `builtins` (تصنيف UICore)؛ لا توسيع SoT (يلتزم قاعدة «الأدوات لا توسّع SoT»؛ توسيع أخطاء المترجم قرارٌ لغويّ مأذون). +- **المكتبة (`features/graphics`):** + - **متحكّم نافذة جديد** `sad::ui::WindowController` (`core/include/sad_ui/window_control.h` + `core/src/window_control.cpp`): singleton مُسرَّب (never-destroyed) نظير `nav()`. نموذج **مؤجَّل**: العمليّة (عنوان/إغلاق) تُكتَب إليه، وحلقة `DesktopWindow::run()` المشتركة تستهلكها كلّ إطار (poll بعد `processEvents`) فتطبّقها على النافذة الفعليّة. لا يعتمد على أنواع المحرّكات ولا على SDL ⇒ سلوكٌ موحَّد بالبناء. تُصفَّر عند إنهاء كلّ تشغيل نافذة. + - `nav().markDirty()` لإعادة الرسم دون تغيير المكدّس. + - `توليد_ويب` يستهلك `sad::ui::web::HtmlCodegen` القائم (لا منطق جديد). +- **المفسّر:** `UIBridge::setWindowTitle/closeWindow` أُعيد توجيههما إلى `windowController()` بدل لمس `activeWindow_` مباشرةً ⇒ **مصدر حقيقة واحد** للمحرّكين (تغيّر السلوك من فوريّ إلى الإطار التالي، بلا انحدار وظيفيّ). تُصفَّر عند الخروج و Hot Restart. +- **المترجم:** جسورٌ C ABI (`sad_generate_web`، `sad_navigate_exit_transition(_builder)`، `sad_update_state`، `sad_set_window_title`، `sad_close_window`) في `runtime/sad_ui_runtime.cpp`، وتوصيل **9 مواقع** (opcode enum، خريطة الأسماء، الخفض، التصريح + المُمرِّر، الـemit، switch، حماية CSE) نظير شريحتَي الثيم والتنقّل. `عين_الحالة` يستدعي دالّة التحديث **تزامنيًّا** عبر ثانك الإغلاق القائم `void(i64 __env)` (يتجاوز كسر التقاط ردّ النداء لأنّ النداء تزامنيّ لا مُخزَّن). `توليد_ويب` يُرجع `String` (نصّ heap مملوك للمستدعي، نظير `sad_readline`). أسماء الرسائل مشتقّة من `Bn::UICore::*` والمتوقَّع من `sirTypeToString` — بلا نصوص حرفيّة. +- **التوافق الخلفي:** إضافيّ بالكامل؛ لا تغيير في السلوك القائم للمفسّر عدا تأجيل تطبيق عنوان/إغلاق النافذة إطارًا واحدًا (غير محسوس). + +# السلبيات (Drawbacks) + +- تباعدات S/L ضيّقة موثَّقة على مدخلاتٍ خاطئة/سوء استخدام (المفسّر يُجهِض، المترجم يُشخّص-ويكمل — النمط القائم للـfrontend): `توليد_ويب` على جذرٍ فارغ يُرجع نصًّا فارغًا؛ `عين_الحالة` لا يستدعي **كائنًا قابلًا للاستدعاء** (Function فقط، لأنّ ثانك الإغلاق يفترض تخطيط إغلاق). +- انتقال الخروج (`exitType`) في `انتقل_بتحريك_كامل` تحسينٌ بصريّ حيّ غير مُستهلَك بعدُ في حلقة نافذة المترجم (نظير `انتقل_بتحريك`)؛ أثر المكدّس (العمق/الصفحة الحاليّة) مطابقٌ بالبناء. + +# المبرّرات والبدائل (Rationale and alternatives) + +- **متحكّم نافذة مكتبيّ موحَّد** بدل جسرٍ لكلّ محرّك: يجعل المكتبة مصدر الحقيقة الوحيد ويمنع تباعد المحرّكين بالبناء (نظير `nav()`/الثيم). البديل (جسر مباشر لكلّ محرّك) يكرّر المنطق ويُخاطِر بالتباعد. +- **النموذج المؤجَّل (poll)** بدل نداءٍ فوريّ: يتفادى مشكلات ملكيّة/عمر مؤشّر النافذة عبر المحرّكين، ويوحّد المسار (نظير `nav.dirty`). + +# أعمال سابقة (Prior art) + +Flutter (`runApp`/`setState`/`Navigator` منطقها في الإطار المشترك، الغلاف رفيع)، والويب (`toString`/render إلى DOM). النموذج الموحَّد: منطق الحالة/النافذة/التوليد في طبقةٍ واحدة يجسر إليها الواجهات. + +# أسئلة غير محسومة (Unresolved questions) + +- دعم **الكائن القابل للاستدعاء** في `عين_الحالة` (يحتاج مسار `buildCallableObjectInvoke` بدل ثانك الإغلاق) — شريحة لاحقة. +- استهلاك انتقال الخروج على الصفحة القديمة في حلقة نافذة المترجم — تحسينٌ بصريّ لاحق. +- توحيد رسائل خطأ المدخل الباطل (إجهاض مقابل تشخيص-وإكمال) بين المحرّكين — قرارٌ عامّ خارج نطاق هذا المقترح.