ربما
في مقالة المراجعة هذه ، سنحاول النظر في بعض أساسيات بنية Eclipse كمنصة لبناء أدوات تطوير متكاملة وإعطاء فكرة أولية عن مكونات Eclipse التي تشكل أساس النظام الأساسي التكنولوجي لـ " المكوّن الجديد ”1C: المؤسسة ،
مقدمة في هندسة الكسوف
لنلقِ نظرة أولاً على بعض الجوانب العامة لبنية Eclipse باستخدام مثال
بادئ ذي بدء ، تجدر الإشارة إلى أن Eclipse يتميز بتقسيم معماري واضح إلى حد ما ، مع فصل وظائف اللغة المستقلة عن الوظيفة المصممة لدعم لغات برمجة معينة ، وفصل "النواة" (الأساسية) المستقلة عن واجهة المستخدم المكونات من المكونات المتعلقة بدعم المستخدم واجهة.
على سبيل المثال ، تعرف منصة Eclipse بنية أساسية مشتركة مستقلة عن اللغة ، وتضيف أدوات تطوير Java IDE كامل الميزات إلى Eclipse. يتكون كل من Eclipse Platform و JDT من عدة مكونات ، كل منها إما "نواة" مستقلة عن واجهة المستخدم أو طبقة واجهة مستخدم (الشكل 1).
أرز. 1. منصة الكسوف و JDT
ندرج المكونات الرئيسية لمنصة Eclipse:
- وقت التشغيل - يحدد البنية التحتية للبرنامج المساعد. الكسوف له بنية معيارية. بشكل أساسي ، فإن Eclipse عبارة عن مجموعة من "نقاط الامتداد" و "الامتدادات".
- مساحة العمل - يدير مشروعًا واحدًا أو أكثر. يتكون المشروع من مجلدات وملفات يتم تعيينها مباشرة إلى نظام الملفات.
- مجموعة أدوات القطعة القياسية (SWT) - يوفر عناصر واجهة المستخدم الأساسية التي تتكامل مع نظام التشغيل.
- جي فيس - يوفر مجموعة من أطر عمل واجهة المستخدم المبنية على SWT.
- طاولة العمل - يحدد نموذج Eclipse UI: المحررين ، وجهات النظر ، ووجهات النظر.
يجب أن أقول إن منصة Eclipse توفر العديد من المكونات المفيدة الأخرى لبناء أدوات تطوير متكاملة ، من بينها التصحيح والمقارنة والبحث والفريق. يجب أن نذكر أيضًا JFace Text - الأساس لبناء "محررين أذكياء" للشفرة المصدرية. لسوء الحظ ، حتى إجراء مراجعة سريعة لهذه المكونات ، بالإضافة إلى مكون طبقة واجهة المستخدم ، غير ممكن ضمن إطار عمل هذه المقالة ، لذلك في بقية هذا القسم ، سنقتصر على مراجعة المكونات "الأساسية" الرئيسية لـ Eclipse المنصة و JDT.
وقت التشغيل الأساسي
يعتمد Eclipse Plugin Framework على
مساحة العمل الأساسية
تقريبًا أي IDE مبني أعلى منصة Eclipse يعمل مع مساحة عمل Eclipse. إنها مساحة العمل التي تحتوي عادةً على الكود المصدري للتطبيق الذي يتم تطويره في IDE. يتم تعيين مساحة العمل مباشرة إلى نظام الملفات وتتكون من المشاريع التي تحتوي على مجلدات وملفات. تسمى هذه المشاريع والمجلدات والملفات مصادر مساحة العمل. يعمل تنفيذ مساحة العمل في Eclipse كذاكرة تخزين مؤقت فيما يتعلق بنظام الملفات ، مما قد يؤدي إلى تسريع عملية اجتياز شجرة الموارد بشكل كبير. بالإضافة إلى ذلك ، توفر مساحة العمل عددًا من الخدمات الإضافية ، بما في ذلك
مكون الموارد الأساسية (المكون الإضافي org.eclipse.core.resources) مسؤول عن دعم مساحة العمل ومواردها. على وجه الخصوص ، يوفر هذا المكون وصول برمجي إلى مساحة العمل في النموذج نماذج الموارد. للعمل بفعالية مع هذا النموذج ، يحتاج العملاء إلى طريقة بسيطة لتمثيل ارتباط إلى مورد. في الوقت نفسه ، من المستحسن إخفاء الكائن الذي يخزن مباشرة حالة المورد في النموذج من وصول العميل. خلاف ذلك ، في حالة ، على سبيل المثال ، حذف ملف ، يمكن للعميل الاستمرار في الاحتفاظ بكائن لم يعد موجودًا في النموذج ، مع المشكلات اللاحقة. Eclipse يحل هذه المشكلة باستخدام ما يسمى ب مقبض الموارد. يعمل المقبض كمفتاح (فهو يعرف فقط المسار إلى المورد في مساحة العمل) ويتحكم بشكل كامل في الوصول إلى كائن النموذج الداخلي ، والذي يخزن بشكل مباشر المعلومات حول حالة المورد. هذا التصميم هو اختلاف في النمط
أرز. 2 يوضح المصطلح المقبض / الجسم كما هو مطبق على نموذج الموارد. تمثل واجهة IResource مقبض المورد وهي API ، على عكس فئة Resource التي تنفذ هذه الواجهة ، وفئة ResourceInfo التي تمثل الجسم ، وهي ليست واجهات برمجة تطبيقات. نؤكد أن المقبض يعرف فقط المسار إلى المورد المتعلق بجذر مساحة العمل ولا يحتوي على ارتباط إلى معلومات المورد. تشكل كائنات معلومات المورد ما يعرف باسم "شجرة العناصر". تم تجسيد بنية البيانات هذه بالكامل في الذاكرة. للعثور على مثيل معلومات مورد يتوافق مع بعض المقابض ، يتم اجتياز شجرة العناصر وفقًا للمسار المخزن في هذا المقبض.
أرز. 2. IResource و ResourceInfo
كما سنرى لاحقًا ، يتم استخدام التصميم الأساسي لنموذج المورد (يمكنك تسميته مستندًا إلى المقبض) في Eclipse وللنماذج الأخرى. في غضون ذلك ، إليك بعض السمات المميزة لهذا التصميم:
- المقبض هو كائن ذو قيمة. كائنات القيمة هي أشياء ثابتة لا تستند مساواتها إلى الهوية. يمكن استخدام هذه الكائنات بأمان كمفتاح في الحاويات المجزأة. يمكن أن تشير مثيلات متعددة من المقبض إلى نفس المورد. لمقارنتها ، استخدم طريقة يساوي (كائن).
- يحدد المؤشر سلوك المورد ، لكنه لا يحتوي على معلومات حول حالة المورد (البيانات الوحيدة التي يخزنها هي "المفتاح" ، المسار إلى المورد).
- يمكن أن يشير المؤشر إلى مورد غير موجود (إما مورد لم يتم إنشاؤه بعد ، أو مورد تم حذفه بالفعل). يمكن التحقق من وجود مورد باستخدام طريقة IResource.exists ().
- يمكن تنفيذ بعض العمليات بناءً على المعلومات المخزنة في المقبض نفسه فقط (ما يسمى بعمليات المقبض فقط). ومن الأمثلة IResource.getParent () و getFullPath () وما إلى ذلك. لا يحتاج المورد إلى الوجود حتى تنجح مثل هذه العملية. العمليات التي تتطلب وجود المورد من أجل النجاح تطرح استثناء (CoreException) إذا لم يكن المورد موجودًا.
يوفر Eclipse آلية فعالة لإخطار التغييرات في موارد مساحة العمل (الشكل 3). يمكن أن تتغير الموارد نتيجة للإجراءات التي يتم تنفيذها في بيئة تطوير Eclipse نفسها ، ونتيجة للتزامن مع نظام الملفات. في كلتا الحالتين ، يتم تزويد العملاء الذين اشتركوا في الإخطارات بمعلومات مفصلة حول التغييرات في شكل "دلتا الموارد" (دلتا المورد). تصف دلتا التغييرات بين حالتين من شجرة موارد مساحة العمل (الفرعية) وهي في حد ذاتها شجرة ، تصف كل عقدة تغييرًا في بعض الموارد وتحتوي على قائمة دلتا المستوى التالي التي تصف التغييرات في الموارد التابعة.
أرز. 3. IResourceChangeEvent و IResourceDelta
تتميز آلية الإخطار المستندة إلى دلتا الموارد بالخصائص التالية:
- يتم وصف التغيير الفردي والكثير من التغييرات باستخدام نفس البنية ، حيث تم بناء دلتا وفقًا لمبدأ التكوين العودي. يمكن للعملاء المشتركين معالجة إشعارات تغيير المورد عن طريق التنازلي المتكرر لشجرة دلتا.
- تحتوي الدلتا على معلومات كاملة حول تغيير المورد ، بما في ذلك حركته و / أو تغيير "العلامات" المرتبطة به (تمثل العلامات ، على سبيل المثال ، أخطاء التجميع).
- نظرًا لأنه يتم إجراء مراجع الموارد من خلال المقبض ، يمكن أن تشير دلتا بشكل طبيعي إلى مورد بعيد.
كما سنرى قريبًا ، فإن عناصر التصميم الرئيسية لآلية الإخطار بتغيير نموذج الموارد ذات صلة بالنماذج الأخرى المستندة إلى المقبض أيضًا.
JDT كور
نموذج مورد مساحة عمل Eclipse هو نموذج أساسي لا يعتمد على اللغة. يوفر مكون JDT Core (المكون الإضافي org.eclipse.jdt.core) واجهة برمجة تطبيقات للتنقل وتحليل بنية مساحة العمل من منظور Java ، ما يسمى "نموذج Java" (نموذج جافا). يتم تعريف واجهة برمجة التطبيقات هذه من حيث عناصر Java ، على عكس واجهة برمجة التطبيقات (API) الخاصة بنموذج المورد الأساسي ، والتي يتم تحديدها من حيث المجلدات والملفات. يتم عرض الواجهات الرئيسية لشجرة عنصر Java في الشكل. 4.
أرز. 4. عناصر نموذج جافا
يستخدم نموذج Java نفس لغة المقبض / الجسم مثل نموذج المورد (الشكل 5). IJavaElement هو المقبض و JavaElementInfo هو الجسم. تحدد واجهة IJavaElement بروتوكولًا مشتركًا لجميع عناصر Java. بعض أساليبها هي handle-only: getElementName () و getParent () وما إلى ذلك. يخزن كائن JavaElementInfo حالة العنصر المقابل: هيكله وسماته.
أرز. 5. IJavaElement و JavaElementInfo
يحتوي نموذج Java على بعض الاختلافات في تنفيذ تصميم المقبض / الجسم الأساسي مقارنة بنموذج المورد. كما هو مذكور أعلاه ، في نموذج الموارد ، يتم تضمين شجرة العناصر التي تكون عقدها كائنات معلومات الموارد بالكامل في الذاكرة. ولكن يمكن أن يحتوي نموذج Java على عدد من العناصر أكبر بكثير من شجرة الموارد ، لأنه يحتوي أيضًا على البنية الداخلية لملفات .java و .class: الأنواع والحقول والأساليب.
لتجنب تجسيد شجرة العناصر بالكامل في الذاكرة ، يستخدم تطبيق نموذج Java ذاكرة تخزين LRU ذات حجم محدود لمعلومات العنصر ، حيث يكون المفتاح هو مقبض IJavaElement. يتم إنشاء كائنات معلومات العنصر عند الطلب أثناء التنقل في شجرة العناصر. في هذه الحالة ، يتم إخراج العناصر الأقل استخدامًا من ذاكرة التخزين المؤقت ، ويظل استهلاك الذاكرة للنموذج مقيدًا بحجم ذاكرة التخزين المؤقت المحدد. هذه ميزة أخرى للتصميم المستند إلى المقبض ، والتي تخفي تمامًا تفاصيل التنفيذ هذه عن كود العميل.
تشبه آلية الإخطار بالتغييرات في عناصر Java إلى حد كبير آلية تتبع تغييرات موارد مساحة العمل التي تمت مناقشتها أعلاه. يشترك العميل الذي يريد تتبع التغييرات في نموذج Java في الإخطارات ، والتي يتم تمثيلها ككائن ElementChangedEvent الذي يحتوي على IJavaElementDelta (الشكل 6).
أرز. 6.ElementChangedEvent و IJavaElementDelta
لا يحتوي نموذج Java على معلومات حول مجموعة الأساليب أو تحليل الاسم ، لذلك من أجل تحليل مفصل للكود المكتوب بلغة Java ، يوفر JDT Core نموذجًا إضافيًا (لا يعتمد على المقبض):
نظرًا لأن أشجار بناء الجملة يمكن أن تستهلك قدرًا كبيرًا من الذاكرة ، فإن JDT تخزن AST واحدًا فقط ، لكل محرر نشط. على عكس نموذج Java ، يُنظر إلى AST عمومًا على أنه نموذج "متوسط" ، "مؤقت" لا ينبغي للعملاء الاحتفاظ بعناصره خارج سياق العملية التي أنشأت AST.
تشكل هذه النماذج الثلاثة (نموذج Java ، AST ، روابط) معًا الأساس لبناء "أدوات تطوير ذكية" في JDT ، بما في ذلك محرر Java قوي مع "مساعدين" مختلفين ، وإجراءات متنوعة لمعالجة كود المصدر (بما في ذلك تنظيم قائمة استيراد الاسم و التنسيق وفقًا للأسلوب المخصص) ، وأدوات البحث وإعادة البناء. في هذه الحالة ، يلعب نموذج Java دورًا خاصًا ، حيث يتم استخدامه كأساس للتمثيل المرئي لهيكل التطبيق المطور (على سبيل المثال ، في Package Explorer و Outline و Search و Call Hierarchy و اكتب التسلسل الهرمي).
مكونات Eclipse المستخدمة في 1C: Enterprise Developments Tools
على التين. يوضح الشكل 7 مكونات Eclipse التي تشكل الأساس لمنصة التكنولوجيا لـ 1C: Enterprise Development Tools.
أرز. 7. الكسوف كمنصة لـ 1C: أدوات تطوير المؤسسة
منصة الكسوف يوفر البنية التحتية الأساسية. لقد غطينا بعض جوانب هذه البنية التحتية في القسم السابق.
مثل أي أداة متعددة الاستخدامات حقًا ، فإن EMF مناسبة لمجموعة واسعة من مهام النمذجة ، لكن بعض فئات النماذج (على سبيل المثال ، النماذج القائمة على المقبض التي تمت مناقشتها أعلاه) قد تحتاج إلى أدوات نمذجة أكثر تخصصًا. إن الحديث عن EMF مهمة غير مجدية ، لا سيما ضمن الإطار المحدود لمقال واحد ، حيث أن هذا موضوع كتاب منفصل ، وموضوع سميك إلى حد ما. نلاحظ فقط أن النظام النوعي للتعميمات الكامنة وراء EMF سمح بولادة مجموعة كاملة من مشاريع النمذجة المضمنة في مشروع المستوى الأعلى
1C: تستخدم أدوات تطوير المؤسسات بشكل نشط كلاً من EMF نفسه وعددًا من مشاريع Eclipse Modeling الأخرى. على وجه الخصوص ، Xtext هو أحد أسس أدوات التطوير لمثل 1C: لغات المؤسسة مثل لغة البرمجة المدمجة ولغة الاستعلام. أساس آخر لأدوات التطوير هذه هو مشروع Eclipse Handly ، والذي سوف نتعمق فيه بمزيد من التفصيل (من مكونات Eclipse المدرجة ، لا يزال أقلها شهرة).
تمت مناقشة المبادئ المعمارية الأساسية للنماذج القائمة على المقبض ، مثل لغة المقبض / الجسم ، أعلاه باستخدام نموذج الموارد ونموذج Java كمثال. كما أشار إلى أن كلا من نموذج الموارد ونموذج Java هما أساسين مهمين لأدوات تطوير Eclipse Java (JDT). وبما أن جميع مشاريع Eclipse * DT تقريبًا لها بنية مشابهة لـ JDT ، فلن يكون من المبالغة الكبيرة أن نقول إن النماذج القائمة على المقبض تكمن وراء العديد ، إن لم يكن كل ، IDEs المبنية على قمة Eclipse Platform. على سبيل المثال ، يحتوي Eclipse C / C ++ Development Tooling (CDT) على نموذج C / C ++ قائم على المقبض ويلعب نفس الدور في بنية CDT كما يفعل نموذج Java في JDT.
قبل Handly ، لم يقدم Eclipse مكتبات متخصصة لبناء نماذج لغة قائمة على المقابض. تم إنشاء النماذج الموجودة اليوم بشكل أساسي من خلال تكييف رمز نموذج Java مباشرةً (المعروف أيضًا باسم النسخ / اللصق) ، في الحالات التي تسمح بذلك رخصة Eclipse Public (EPL). (من الواضح ، بالنسبة لمشاريع Eclipse الخاصة ، على سبيل المثال ، أن هذه ليست قضية قانونية ، وهذا ليس هو الحال بالنسبة لمنتجات المصدر المغلق). عند التكيف مع الأخطاء ، وما إلى ذلك. والأسوأ من ذلك أن النماذج الناتجة تظل "أشياء في حد ذاتها" ولا تستخدم الإمكانيات الحالية للتوحيد. لكن تخصيص المفاهيم والبروتوكولات الشائعة للنماذج القائمة على التعامل مع اللغة يمكن أن يؤدي إلى إنشاء مكونات قابلة لإعادة الاستخدام للعمل معها ، على غرار ما حدث في حالة المجالات الكهرومغناطيسية.
هذا لا يعني أن Eclipse لم يكن لديه فهم لهذه المشاكل. مرة أخرى في 2005
بمعنى ما ، تم تصميم مشروع Handly لحل نفس مهام EMF تقريبًا ، ولكن للنماذج القائمة على المقابض ، والنماذج اللغوية بشكل أساسي (أي تمثيل عناصر بنية لغة البرمجة). فيما يلي أهداف التصميم الرئيسية لـ Handly:
- عزل التجريدات الرئيسية في مجال الموضوع.
- تقليل الجهد وتحسين جودة تنفيذ النماذج القائمة على التعامل مع اللغة من خلال إعادة استخدام الكود.
- توفير واجهة برمجة تطبيقات موحدة على مستوى التعريف للنماذج الناتجة ، مما يجعل من الممكن إنشاء مكونات IDE مشتركة تعمل مع النماذج القائمة على التعامل مع اللغة.
- المرونة وقابلية التوسع.
- التكامل مع Xtext (في طبقة منفصلة).
لتسليط الضوء على المفاهيم والبروتوكولات المشتركة ، تم تحليل التطبيقات الحالية للنماذج القائمة على التعامل مع اللغة. يتم عرض الواجهات الرئيسية والتطبيقات الأساسية التي يوفرها Handly في الشكل 8-XNUMX. XNUMX.
أرز. 8. واجهات مشتركة والتطبيقات الأساسية لعناصر Handly
تمثل واجهة IElement مقبض أحد العناصر وهي مشتركة مع عناصر جميع النماذج المستندة إلى Handly. ينفذ عنصر الفئة المجردة آلية مقبض / جسم عامة (الشكل 9).
أرز. 9. IElement والتنفيذ العام للمقبض / الجسم
بالإضافة إلى ذلك ، يوفر Handly آلية تبليغ معممة لتغيير عناصر النموذج (الشكل 10). كما ترى ، بشكل عام ، فهي تشبه آليات الإعلام المطبقة في نموذج الموارد ونموذج Java ، وتستخدم IElementDelta للتمثيل الموحد لمعلومات تغيير العنصر.
أرز. 10. الواجهات المشتركة والتطبيقات الأساسية لآلية الإخطار Handly
يمكن استخدام الجزء المذكور أعلاه (الشكل 9 و 10) لتمثيل أي نماذج تعتمد على المقبض تقريبًا. لخلق لغوي النماذج ، يقدم المشروع وظائف إضافية - على وجه الخصوص ، الواجهات المشتركة والتطبيقات الأساسية لعناصر بنية النص المصدر ، ما يسمى عناصر المصدر (الشكل 8). تمثل واجهة ISourceFile ملفًا مصدرًا ، ويمثل ISourceConstruct عنصرًا داخل الملف المصدر. تطبق فئات الملخصات SourceFile و SourceConstruct آليات عامة لدعم العمل مع الملفات المصدر وعناصرها ، على سبيل المثال ، العمل مع المخازن المؤقتة للنص ، والربط بإحداثيات العناصر في النص المصدر ، والتوفيق بين النموذج والمحتويات الحالية لمخزن النسخة العاملة ، إلخ. . عادةً ما يكون تنفيذ هذه الآليات تحديًا كبيرًا ، ويمكن أن يقلل Handly بشكل كبير من جهد تطوير نماذج لغة قائمة على المقابض من خلال توفير تطبيقات أساسية عالية الجودة.
بالإضافة إلى الآليات الأساسية المذكورة أعلاه ، يوفر Handly مخزنًا مؤقتًا للنص والبنية التحتية للقطات ، ودعمًا للتكامل مع برامج تحرير التعليمات البرمجية المصدر (بما في ذلك التكامل خارج الصندوق مع محرر Xtext) ، بالإضافة إلى بعض مكونات واجهة المستخدم الشائعة التي تعمل مع نماذج Handly مثل إطار المخطط التفصيلي. لتوضيح قدراته ، يقدم المشروع عدة أمثلة ، بما في ذلك تنفيذ نموذج Java في Handly. (مقارنة بالتنفيذ الكامل لنموذج Java في JDT ، تم تبسيط هذا النموذج عن قصد إلى حد ما للحصول على وضوح أفضل.)
كما ذكرنا سابقًا ، كان التصميم والتطوير الأولي لشركة Handly ولا يزال يركز بشدة على قابلية التوسع والمرونة.
من حيث المبدأ ، فإن النماذج القائمة على المقبض تتوسع بشكل جيد "حسب التصميم". على سبيل المثال ، تسمح لك لغة المقبض / الجسم بتحديد مقدار الذاكرة التي يستهلكها النموذج. ولكن هناك أيضًا فروق دقيقة. لذلك ، عند اختبار قابلية التوسع يدويًا ، تم العثور على مشكلة في تنفيذ آلية الإخطار - عند تغيير عدد كبير من العناصر ، استغرق إنشاء دلتا الكثير من الوقت. اتضح أن نفس المشكلة موجودة في نموذج Java JDT ، والذي تم تعديل الكود المقابل منه في وقت واحد. لقد أصلحنا خطأ في Handly وأعدنا تصحيحًا مشابهًا لـ JDT ، والذي تم استقباله بامتنان. هذا مجرد مثال واحد حيث يمكن أن يكون تنفيذ Handly في تطبيقات النماذج الحالية مفيدًا ، حيث سيكون من الممكن إصلاح مثل هذا الخطأ في مكان واحد فقط.
لجعل التضمين يدويًا في تطبيقات النماذج الحالية ممكنًا تقنيًا ، يجب أن تكون المكتبة مرنة للغاية. المشكلة الرئيسية هي الحفاظ على التوافق مع الإصدارات السابقة مع نموذج API. تم حل هذه المشكلة في
المرونة لها جوانب أخرى أيضًا. على سبيل المثال ، لا تفرض Handly أي قيود تقريبًا على بنية النموذج ويمكن استخدامها لنمذجة اللغات ذات الأغراض العامة بالإضافة إلى اللغات الخاصة بالمجال. عند إنشاء بنية الملف المصدر ، لا يصف Handly أي شكل معين من أشكال تمثيل AST ومن حيث المبدأ لا يتطلب حتى وجود AST نفسه ، وبالتالي ضمان التوافق مع أي آلية تحليل تقريبًا. أخيرًا ، يدعم Handly التكامل الكامل مع مساحة عمل Eclipse ، ولكن يمكنه أيضًا العمل مباشرةً مع أنظمة الملفات بفضل تكاملها مع
النسخة الحالية
كما هو مذكور أعلاه ، أحد هذه المنتجات هو 1C: أدوات تطوير المؤسسات ، حيث يتم استخدام Handly منذ البداية لنمذجة عناصر البنية عالية المستوى لـ 1C: لغات المؤسسة كلغة برمجة مضمنة ولغة استعلام. منتج آخر أقل شهرة لعامة الناس. هذا
نأمل أنه بعد إصدار الإصدار 1.0 مع ضمان استقرار API وخروج المشروع من حالة الحضانة ، سيكون لدى Handly أيضًا متبنون جدد. في غضون ذلك ، يستمر المشروع في اختبار واجهة برمجة التطبيقات وتحسينها بشكل أكبر ، مع إصدارين "كبيرين" سنويًا ، في يونيو (نفس تاريخ إصدار Eclipse المتزامن) وديسمبر ، مما يوفر جدولًا يمكن التنبؤ به يمكن للمتبنين الاعتماد عليه. يمكننا أيضًا أن نضيف أن "معدل الأخطاء" للمشروع لا يزال عند مستوى منخفض باستمرار ، وقد عمل Handly بشكل موثوق في منتجات المتبنين الأوائل منذ الإصدارات الأولى. لمزيد من الإلمام بـ Eclipse Handly ، يمكنك استخدام ملفات
المصدر: www.habr.com