ملحقات رائعة ، المجلد. 1. النظرية

الحياة مع مشروع متعدد الوحدات ليست بهذه البساطة. لتجنب روتين إنشاء وحدة نمطية جديدة ، أنشأنا المكون الإضافي الخاص بنا لبرنامج Android Studio. في عملية التنفيذ ، واجهنا نقصًا في التوثيق العملي ، وجربنا عدة طرق وحفرنا الكثير من العثرات. اتضح مقالين: "النظرية" و "الممارسة" . قابلني!


صورة


ما الذي سأتحدث عنه؟


  • لماذا البرنامج المساعد؟ لماذا البرنامج المساعد؟
    • وضع قائمة مرجعية
    • قائمة خيارات أتمتة
  • أساسيات تطوير البرنامج المساعد
    • تطبيقات
    • تطوير واجهة المستخدم في الإضافات
    • النتائج
  • IDEA الداخلية: مكونات ، PSI
    • وحدة IDEA الداخلية
    • PSI
    • النتائج

لماذا البرنامج المساعد؟ لماذا البرنامج المساعد؟


إذا كنت تقوم بتطوير مشروع أندرويد متعدد الوحدات ، فأنت تعرف نوع الروتين الذي تقوم به لإنشاء وحدة نمطية جديدة في كل مرة. تحتاج إلى إنشاء وحدة نمطية ، وتكوين Gradle فيها ، وإضافة التبعيات ، وانتظار المزامنة ، ولا تنسَ إصلاح شيء ما في وحدة التطبيق - كل هذا يستغرق الكثير من الوقت. أردنا أتمتة الروتين ، وبدأنا من خلال تجميع قائمة مرجعية بما نقوم به في كل مرة نقوم فيها بإنشاء وحدة نمطية جديدة.


1. أولاً ، نقوم بإنشاء الوحدة النمطية نفسها من خلال القائمة ملف -> جديد -> وحدة جديدة -> مكتبة Android.


صورة


2. نكتب المسارات إلى الوحدة النمطية في ملف settings.gradle ، لأن لدينا عدة أنواع من الوحدات - الوحدات الأساسية والوحدات النمطية للميزات ، والتي توجد في مجلدات مختلفة.


نكتب مسارات للوحدات
// settings.gradle include ':analytics project(':analytics').projectDir = new File(settingsDir, 'core/framework-metrics/analytics) ... include ':feature-worknear' project(':feature-worknear').projectDir = new File(settingsDir, 'feature/feature-worknear') 

3. قم بتغيير الثوابت compileSdk ، minSdk ، targetSdk في build.gradle الذي تم إنشاؤه: استبدلهم بالثوابت المعرفة في build.gradle الجذر.


تغيير الثوابت في build.gradle الوحدة الجديدة
 // Feature module build.gradle … android { compileSdkVersion rootProject.ext.targetSdkVersion defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion ... } } 

ملاحظة: لقد أزلنا هذا الجزء مؤخرًا من عملنا إلى المكون الإضافي Gradle ، مما يساعد على تكوين جميع المعلمات الضرورية لملف build.gradle في عدة أسطر.


4. نظرًا لأننا نكتب كل الكود الجديد في Kotlin ، كمعيار ، فإننا نربط مكونين إضافيين : kotlin-android و kotlin-kapt . إذا كانت الوحدة متصلة بطريقة أو بأخرى مع واجهة المستخدم ، فنحن نضيف بالإضافة إلى ذلك وحدة kotlin-android-extensions .


ربط الإضافات Kotlin
 // Feature module build.gradle apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' 

5. نقوم بتوصيل المكتبات العامة والوحدات الأساسية. الوحدات الأساسية هي ، على سبيل المثال ، المسجل والتحليلات وبعض المرافق العامة والمكتبات - RxJava و Moxy وغيرها الكثير.


نحن نربط المكتبات والوحدات النمطية المشتركة
 // Feature module build.gradle dependencies { def libraries = rootProject.ext.deps compileOnly project(':logger') compileOnly project(':analytics') … // Kotlin compileOnly libraries.kotlin // DI compileOnly libraries.toothpick kapt libraries.toothpickCompiler } 

6. قم بإعداد kapt لـ Toothpick. المسواك هو إطار عملنا الأساسي DI. على الأرجح تعلمون: من أجل استخدام توليد الكود بدلاً من الانعكاس في إصدار الإصدار ، تحتاج إلى تكوين معالج التعليقات التوضيحية بحيث يفهم مكان الحصول على المصانع للكائنات التي يتم إنشاؤها:


تكوين معالج التعليقات التوضيحية لـ Toothpick
 // Feature module build.gradle defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [ toothpick_registry_package_name: "ru.hh.feature_worknear" ] } } ... 

ملاحظة: في hh.ru ، نستخدم الإصدار الأول من Toothpick ، ​​في الثانية أزلنا القدرة على استخدام توليد الكود .


7. نحن تكوين kapt ل Moxy داخل الوحدة النمطية التي تم إنشاؤها. Moxy هو إطارنا الرئيسي لإنشاء MVP في تطبيق ما ، وتحتاج إلى تحريفه قليلاً حتى يتمكن من العمل في مشروع متعدد الوحدات. على وجه الخصوص ، قم بتسجيل حزمة الوحدة النمطية التي تم إنشاؤها في وسائط kapt:


تكوين kapt لـ Moxy
 // Feature module build.gradle android { ... kapt { arguments { arg("moxyReflectorPackage", "ru.hh.feature_worknear") } } ... 

ملاحظة: لقد انتقلنا بالفعل إلى الإصدار الجديد من Moxy ، وفقد هذا الجزء من إنشاء الشفرة أهميته.


8. نقوم بإنشاء مجموعة من الملفات الجديدة. لا أقصد تلك الملفات التي يتم إنشاؤها تلقائيًا (AndroidManifest.xml ، build.gradle ، .gitignore) ، ولكن الإطار العام للوحدة النمطية الجديدة: المتفاعلات ، المستودعات ، وحدات DI ، العروض ، الأجزاء. هناك الكثير من هذه الملفات ، لديهم نفس البنية في البداية ، وإنشائها يعد روتينًا.


صورة


9. نقوم بتوصيل الوحدة النمطية التي تم إنشاؤها بوحدة التطبيق. في هذه الخطوة ، يجب أن تتذكر تكوين Toothpick في ملف build.gradle بوحدة التطبيق. للقيام بذلك ، نضيف حزمة الوحدة النمطية التي تم إنشاؤها إلى معالج شرح الوسيطة الخاص - toothpick_registry_children_package_names .


ضبط مسواك
 // App module build.gradle defaultConfig { … javaCompileOptions { annotationProcessorOptions { arguments = [ toothpick_registry_package_name: "ru.hh.android", toothpick_registry_children_package_names: [ "ru.hh.analytics", "ru.hh.feature_worknear", ... ].join(",") ] } } … 

بعد ذلك ، نقوم بتكوين Moxy في وحدة التطبيق. لدينا فئة تتميز بتعليق توضيحي RegisterMoxyReflectorPackages - حيث نضيف اسم حزمة الوحدة النمطية التي تم إنشاؤها:


تكوين MoxyReflectorStub
 // App module file @RegisterMoxyReflectorPackages( "ru.hh.feature_force_update", "ru.hh.feature_profile", "ru.hh.feature_worknear" ... ) class MoxyReflectorStub 

وفي النهاية ، لا تنس توصيل الوحدة النمطية التي تم إنشاؤها بكتلة الاعتمادات في وحدة التطبيق:


مضيفا التبعيات
 // Application module build.gradle dependencies { def libraries = rootProject.ext.deps implementation project(':logger') implementation project(':dependency-handler') implementation project(':common') implementation project(':analytics') implementation project(':feature_worknear') ... 

حصلنا على قائمة تسع نقاط.


نظرًا لوجود العديد من النقاط ، فمن المحتمل أن تنسى شيئًا ما. ثم أمضِ ساعات في التساؤل عما حدث ولماذا لن يتم تنفيذ المشروع.


قررنا أنه لا يمكنك العيش بهذه الطريقة وتحتاج إلى تغيير شيء ما.


قائمة خيارات أتمتة


بعد تجميع قائمة التحقق ، بدأنا في البحث عن خيارات لأتمتة عناصرها.


كان الخيار الأول محاولة للقيام بـ "Ctrl + C ، Ctrl + V" . حاولنا العثور على تطبيق لإنشاء وحدة مكتبة Android ، والتي تتوفر لنا "خارج الصندوق". في المجلد الذي يحتوي على Android Studio (لأجهزة MacO: / Applications / Android \ Studio.app/Contents/plugins/android/lib/templates/gradle-projects/ ) ، يمكنك العثور على مجلد خاص به قوالب للمشاريع التي تراها عند تحديد ملف - > جديد -> وحدة جديدة. حاولنا نسخ قالب NewAndroidModule عن طريق تغيير المعرف داخل ملف template.xml.ftl . ثم أطلقوا IDE ، وبدأوا في إنشاء وحدة نمطية جديدة ، ... تعطلت Android Studio لأن قائمة الوحدات النمطية التي تراها في القائمة لإنشاء وحدة نمطية جديدة مشفرة ، لا يمكنك تغييرها باستخدام لصق نسخ أولي. عند محاولة أخذ عنصر أو إضافته أو حذفه أو تغييره ، يتعطل Android Studio.


صورة


كان الخيار الثاني لأتمتة قائمة الفحص هو محرك قوالب FreeMarker . بعد محاولة لصق نسخ غير ناجحة ، قررنا إلقاء نظرة فاحصة على قوالب الوحدة النمطية ووجدنا قوالب FreeMarker أسفل الغطاء.


لن أخبرك ما هو FreeMarker بالتفصيل - هناك مقال جيد من RedMadRobot وفيديو من MosDroid من Lesha Bykov . ولكن باختصار - هذا هو محرك لإنشاء ملفات باستخدام القوالب وكائنات جافا Map-ki الخاصة. يمكنك تغذية القوالب والكائنات ، ويقوم FreeMarker بإنشاء رمز في الإخراج.


لكن انظر مرة أخرى إلى قائمة التحقق:


صورة


إذا نظرت عن كثب ، يمكنك أن ترى أنها مقسمة إلى مجموعتين كبيرتين من المهام:


  • مهام إنشاء كود جديد (1 ، 3 ، 4 ، 5 ، 6 ، 7 ، 8) و
  • مهام تعديل الكود الموجود (2 ، 7 ، 8 ، 9)

وإذا تعامل FreeMarker مع المهام من المجموعة الأولى مع اثارة ضجة ، فإنه لا يتعامل مع الثانية على الإطلاق. كمثال صغير: في التطبيق الحالي لتكامل FreeMarker في Android Studio ، عندما تحاول إدراج سطر في ملف settings.gradle الذي لا يبدأ بالكلمة "include" ، سيتعطل الاستوديو . هنا وقعنا في الحزن ، وقررنا التخلي عن استخدام FreeMarker.


بعد فشل في FreeMarker ، ظهرت الفكرة لكتابة أداة التحكم الخاصة بي لأداء قائمة مرجعية. داخل Intellij IDEA ، من الممكن استخدام الجهاز ، فلماذا لا؟ دعنا نكتب السيناريو على باش ، إجمالي الأعمال:


صورة


ولكن نظرًا لأننا نريد أن نكون قادرين على تكوين الوحدة النمطية التي تم إنشاؤها بمرونة ، فسيتعين علينا إدخال العديد من الأعلام المختلفة ، والتي لن تكون ملائمة للغاية للطباعة في وحدة التحكم.


بعد ذلك ، اتخذنا خطوة إلى الوراء وتذكرنا أننا كنا نعمل داخل Intellij IDEA. وكيف يتم ترتيبها؟ هناك مجموعة أساسية من الفصول ، محرك يتم توصيل العديد من المكونات الإضافية به ، مما يضيف الوظيفة التي نحتاجها.


كم منكم تراه في لقطة الشاشة أكثر من مكونين إضافيين متصلين؟


صورة


أن ننظر فيها؟ ..

صورة


هنا ترتبط ثلاثة على الأقل. إذا كنت تعمل مع Kotlin ، فيمكنك تمكين المكون الإضافي لـ Kotlin. إذا كنت تعمل في مشروع مع Gradle ، فسيتم أيضًا تضمين مكون Gradle الإضافي. إذا كنت تعمل في مشروع مع نظام للتحكم في الإصدار - Git أو SVN أو أي شيء آخر - لديك المكون الإضافي المناسب المضمّن لدمج VCS هذا.


لقد بحثنا في مستودع المكونات الإضافية JetBrains الرسمي ، واتضح أن هناك بالفعل أكثر من 4000 مكون إضافي مسجل رسميًا! يكتب العالم كله تقريبًا مكونات إضافية ، ويمكن لهذه المكونات الإضافية أن تفعل أي شيء: بدءًا من دمج لغة برمجة في IDEA وانتهاءً بأدوات محددة يمكن تشغيلها من داخل IDEA.


باختصار ، قررنا كتابة البرنامج المساعد الخاص بنا.


أساسيات تطوير البرنامج المساعد


ننتقل إلى أساسيات تطوير البرنامج المساعد. للبدء ، ما عليك سوى ثلاثة أشياء:


  1. IntelliJ IDEA ، الحد الأدنى من Community Edition (يمكنك العمل في الإصدار Ultimate ، لكنه لن يعطي مزايا خاصة عند تطوير المكونات الإضافية) ؛
  2. البرنامج المساعد DevKit المتصل به هو ملحق خاص يضيف القدرة على كتابة مكونات إضافية ؛
  3. وأي لغة JVM التي تريد كتابة البرنامج المساعد. يمكن أن يكون Kotlin ، جافا ، رائع - أي شيء.

نبدأ من خلال إنشاء مشروع البرنامج المساعد. نختار مشروعًا جديدًا ، ونقطة Gradle ، ونضع علامة على IntelliJ Platform Plugin وننشئ المشروع.


صورة


ملاحظة: إذا لم تشاهد مربع الاختيار IntelliJ Platform Plugin ، فهذا يعني أنك لم تقم بتثبيت المكون الإضافي DevKit.


بعد ملء الحقول المطلوبة ، سنرى هيكل إضافي فارغ.


صورة


دعونا نلقي نظرة فاحصة على ذلك. يتكون من:


  • المجلدات التي ستكتب فيها رمز المشروع في المستقبل ؛ ( الرئيسي / جافا ، الرئيسي / kotlin ، الخ) ؛
  • ملف build.gradle ، الذي ستعلن فيه تبعيات المكون الإضافي الخاص بك على بعض المكتبات ، وأيضًا ستقوم بتكوين شيء مثل gradle-intellij-plugin .

gradle-intellij-plugin - البرنامج المساعد Gradle الذي يسمح لك باستخدام Gradle كنظام لبناء البرنامج المساعد. يعد هذا الأمر مناسبًا لأن كل مطور يعمل بنظام Android تقريبًا على دراية بـ Gradle ويعرف كيفية التعامل معه. بالإضافة إلى ذلك ، يضيف gradle-intellij-plugin مهام gradle مفيدة إلى مشروعك ، على وجه الخصوص:


  • runIde - تطلق هذه المهمة مثيل IDEA منفصلًا ببرنامج إضافي تقوم بتطويره حتى تتمكن من تصحيحه ؛
  • buildPlugin - يجمع أرشيف الرمز البريدي للمكون الإضافي الخاص بك بحيث يمكنك توزيعه إما محليًا أو من خلال مستودع IDEA الرسمي ؛
  • checkPlugin - تقوم هذه المهمة بفحص المكون الإضافي الخاص بك بحثًا عن أخطاء جسيمة قد لا تسمح له بالاندماج في Android Studio أو بعض IDEA آخر.

ما الذي يقدمه gradle-intellij-plugin ؟ بفضل مساعدته ، يصبح من السهل إضافة التبعيات إلى المكونات الإضافية الأخرى ، لكننا سنتحدث عن ذلك لاحقًا ، لكن في الوقت الحالي أستطيع أن أقول أن gradle-intellij-plugin هو إخوانك ، استخدمه.


العودة إلى هيكل البرنامج المساعد. الملف الأكثر أهمية لأي مكون إضافي هو plugin.xml .


plugin.xml
 <idea-plugin> <id>com.experiment.simple.plugin</id> <name>Hello, world</name> <vendor email="myemail@yourcompany.com" url="http://www.mycompany.com"> My company </vendor> <description><![CDATA[ My first ever plugin - try to open Hello world dialog<br> ]]></description> <depends>com.intellij.modules.lang</depends> <depends>org.jetbrains.kotlin</depends> <depends>org.intellij.groovy</depends> <idea-version since-build="163"/> <actions> <group description="My actions" id="MyActionGroup" text="My actions"> <separator/> <action id="com.experiment.actions.OpenHelloWorldAction" class="com.experiment.actions.OpenHelloWorldAction" text="Show Hello world" description="Open dialog"> <add-to-group group-id="NewGroup" anchor="last"/> </action> </group> </actions> <idea-plugin> 

هذا ملف يحتوي على:


  • بيانات تعريف المكوّن الإضافي: المعرّف والاسم والوصف ومعلومات البائع وتغيير السجل
  • وصف التبعيات على الإضافات الأخرى ؛
  • هنا يمكنك أيضًا تحديد إصدار IDEA الذي سيعمل به المكون الإضافي بشكل صحيح
  • وصفت الإجراءات أيضا هنا.

تطبيقات


ما هي الإجراءات ؟ افترض أنك تفتح قائمة لإنشاء ملف جديد. في الواقع ، تمت إضافة كل عنصر من عناصر هذه القائمة بنوع من المكونات الإضافية:


صورة


الإجراءات هي نقاط الدخول إلى البرنامج المساعد للمستخدمين. في كل مرة يقوم المستخدم بالنقر فوق عنصر القائمة ، يمكنك التحكم داخل البرنامج المساعد ، يمكنك الرد على هذه النقرة والقيام بما هو ضروري.
كيف يتم إنشاء الإجراءات؟ فلنكتب إجراءًا بسيطًا يعرض حوارًا مع الرسالة "Hello، World".


OpenHelloWorldAction
 class OpenHelloWorldAction : AnAction() { override fun actionPerformed(actionEvent: AnActionEvent) { val project = actionEvent.project Messages.showMessageDialog( project, "Hello world!", "Greeting", Messages.getInformationIcon() ) } override fun update(e: AnActionEvent) { super.update(e) // TODO - Here we can update our action (for example, disable it) } override fun beforeActionPerformedUpdate(e: AnActionEvent) { super.beforeActionPerformedUpdate(e) // TODO - This method calls right before 'actionPerformed' } } 

لإنشاء إجراء ، نقوم أولاً بإنشاء فئة ترث من فئة AnAction . ثانياً ، يجب علينا إعادة تعريف طريقة actionPerformed ، حيث تأتي المعلمة الخاصة لفئة AnActionEvent . تحتوي هذه المعلمة على معلومات حول سياق تنفيذ الإجراء الخاص بك. يشير السياق إلى المشروع الذي تعمل فيه ، والملف المفتوح الآن في محرر كود المستخدم ، والعناصر المحددة في شجرة المشروع ، وغيرها من البيانات التي يمكن أن تساعد في معالجة المهام الخاصة بك.


لإظهار مربع الحوار "Hello، world" ، نحصل أولاً على المشروع (فقط من المعلمة AnActionEvent ) ، ثم نستخدم رسائل فئة الأداة المساعدة لعرض مربع الحوار.


ما هي الميزات الإضافية التي لدينا داخل الحركة؟ يمكننا تخطي طريقتين: التحديث و beforeActionPerformedUpdate .


تسمى طريقة التحديث في كل مرة يتغير فيها سياق تنفيذ الإجراء الخاص بك. لماذا قد يكون من المفيد لك: على سبيل المثال ، لتحديث عنصر القائمة الذي تمت إضافته بواسطة البرنامج المساعد الخاص بك. افترض أنك كتبت إجراءًا لا يعمل إلا مع ملفات Kotlin ، وأن المستخدم قد فتح ملف Groovy الآن. ثم في طريقة التحديث ، يمكنك جعل عملك غير قابل للوصول.


تشبه طريقة beforeActionPerformedUpdate طريقة التحديث ، لكن يتم استدعاؤها مباشرة قبل actionPerformed . هذه هي الفرصة الأخيرة للتأثير على عملك. توصي الوثائق بعدم القيام بأي شيء "ثقيل" في هذه الطريقة بحيث يتم تشغيله في أقرب وقت ممكن.


يمكنك أيضًا ربط الإجراءات بعناصر معينة من واجهة IDEA وتعيين مجموعات المفاتيح الافتراضية للاتصال بها - أوصي بقراءة المزيد حول هذا الموضوع هنا .


تطوير واجهة المستخدم في الإضافات


إذا كنت بحاجة إلى تصميم الحوار الخاص بك ، فسيتعين عليك العمل بجد. لقد طورنا واجهة المستخدم الخاصة بنا لأننا أردنا أن يكون لدينا واجهة رسومية مريحة يمكن من خلالها وضع علامة على بضع علامات ، والحصول على محدد لقيم التعداد ، وما إلى ذلك.


يضيف البرنامج المساعد DevKit لتطوير واجهة المستخدم بعض الإجراءات ، مثل نموذج واجهة المستخدم الرسومية والحوار. الأول ينشئ نموذجًا فارغًا بالنسبة لنا ، والثاني - نموذج يحتوي على زرين: موافق وإلغاء .


صورة


حسنًا ، هناك مصمم نماذج ، لكنه ... هكذا. بالمقارنة ، حتى مصمم Layout في Android Studio يبدو مريحًا وجيدًا. تم تطوير واجهة المستخدم بالكامل على مكتبة مثل Java Swing. ينشئ مصمم النموذج هذا ملف XML قابل للقراءة من قِبل الإنسان. إذا لم تتمكن من القيام بشيء ما في مصمم النموذج (على سبيل المثال: إدراج عناصر تحكم متعددة في خلية الشبكة نفسها وإخفاء عناصر التحكم ما عدا واحدة) ، فستحتاج إلى الانتقال إلى هذا الملف وتغييره - ستقوم IDEA بالتقاط هذه التغييرات.


يتكون كل نموذج تقريبًا من ملفين: الأول يحتوي على الامتداد .form ، هذا هو ملف XML فقط ، والثاني هو فئة Bound المسموح بها ، والتي يمكن كتابتها بلغة Java ، Kotlin ، ولكن كل ما تريد. انها بمثابة وحدة تحكم النموذج. بشكل غير متوقع ، لكن الكتابة بلغة جافا أسهل بكثير من اللغات الأخرى. لأنه ، على سبيل المثال ، لم يعد ضبط Kotlin مثاليًا بعد. عند إضافة مكونات جديدة في العمل مع فئة Java ، تتم إضافة هذه المكونات تلقائيًا إلى الفصل الدراسي ، وعندما تقوم بتغيير اسم المكون في المصمم ، يتم سحبه تلقائيًا. ولكن في حالة Kotlin ، لا تتم إضافة المكونات - لا يحدث أي تكامل ، يمكنك نسيان شيء ما ولا تفهم لماذا لا شيء يعمل.


نحن نلخص الأساسيات


  • لإنشاء مكون إضافي ، ستحتاج إلى: IDEA Community Edition و Plugin DevKit و Java متصلة به.
  • gradle-intellij-plugin هو إخوانك ، وسوف يبسط حياتك إلى حد كبير ، أوصي باستخدامه.
  • لا تكتب واجهة المستخدم الخاصة بك إلا إذا لزم الأمر. هناك العديد من فئات الأدوات المساعدة في IDEA التي تتيح لك إنشاء واجهة المستخدم الخاصة بك خارج الصندوق. إذا كنت بحاجة إلى شيء معقد - فاستعد للعمل بجد.
  • يمكن أن يحتوي البرنامج المساعد على أي عدد من الإجراءات. يمكن أن يضيف البرنامج المساعد نفسه الكثير من الوظائف إلى IDEA الخاص بك.

IDEA الداخلية: مكونات ، PSI


دعونا نتحدث عن أمعاء IDEA ، حول كيفية ترتيبها بالداخل. أنا أقول لك حتى لا ينهار أي شيء في رأسك عندما أشرح الجزء العملي ، بحيث تفهم من أين يأتي.


كيف يتم ترتيب IDEA؟ في المستوى الأول من التسلسل الهرمي توجد فئة مثل التطبيق . هذا هو مثيل IDEA منفصلة. لكل مثيل IDEA ، يتم إنشاء كائن فئة تطبيق واحد. على سبيل المثال ، إذا قمت بتشغيل AppCode و Intellij IDEA و Android Studio في نفس الوقت ، فستحصل على ثلاث حالات منفصلة لفئة التطبيق. تم تصميم هذه الفئة للتعامل مع تيار الإدخال / الإخراج.


ضع التطبيق في التسلسل الهرمي

صورة


المستوى التالي هو فئة المشروع . هذا هو المفهوم الأقرب إلى ما تراه عند فتح مشروع جديد في IDEA. عادة ما تكون هناك حاجة إلى المشروع للحصول على مكونات أخرى داخل IDEA: فئات المرافق ، والمديرين ، وأكثر من ذلك بكثير.


مكان المشروع في التسلسل الهرمي

صورة


المستوى التالي من التفاصيل هو فئة الوحدة النمطية . بشكل عام ، الوحدة النمطية هي تسلسل هرمي للفئات المجمعة في مجلد واحد. لكن هنا من خلال الوحدات ، نعني وحدات Maven ، وحدات Gradle. هذه الفئة مطلوبة ، أولاً ، لتحديد التبعيات بين الوحدات النمطية ، وثانياً ، للبحث عن الفئات داخل هذه الوحدات.


وضع الوحدة النمطية في التسلسل الهرمي

صورة


المستوى التالي من التفاصيل هو فئة VirtualFile . هذا تجريد عبر الملف الحقيقي الموجود على القرص. يمكن أن تتوافق مثيلات VirtualFile المتعددة مع كل ملف حقيقي ، لكنها كلها متساوية. في الوقت نفسه ، إذا تم حذف الملف الحقيقي ، فلن يتم حذف ملف VirtualFile من تلقاء نفسه ، ولكن ببساطة يصبح غير صالح.


VirtualFile التسلسل الهرمي مكان

صورة


يرتبط كيان مثل المستند بكل VirtualFile . إنه تجريد على نص الملف الخاص بك. هناك حاجة إلى المستند حتى تتمكن من تتبع الأحداث المتعلقة بالتغييرات في نص الملف : قام المستخدم بإدراج سطر ، وحذف سطر ، وما إلى ذلك ، إلخ.


وضع المستند في التسلسل الهرمي

صورة


يوجد جانب محرر هذا الجزء القليل من التسلسل الهرمي - إنه محرر رموز. يمكن أن يكون لكل مشروع محرر واحد. هناك حاجة لتتمكن من تتبع الأحداث المتعلقة بمحرر الشفرة: لقد أبرز المستخدم السطر الذي يوجد به علامة الإقحام وما إلى ذلك.


مكان المحرر في التسلسل الهرمي

صورة


آخر شيء أردت التحدث عنه هو PsiFile . هذا أيضًا عبارة عن تجريد على ملفات حقيقية ، ولكن من وجهة نظر تمثيل عناصر الكود . PSI لتقف على واجهة هيكل البرنامج.


PsiFile مكان في التسلسل الهرمي

صورة


وماذا يتكون كل برنامج من؟ النظر في فئة جافا العادية.


فئة جافا عادي
 package com.experiment; import javax.inject.Inject; class SomeClass { @Inject String injectedString; public void someMethod() { System.out.println(injectedString); } } 

وهو يتألف من تحديد الحزمة ، والواردات ، والفئات ، والحقول ، والأساليب ، والشروح ، والكلمات الرئيسية ، وأنواع البيانات ، والمعدلات ، والمعرفات ، ومراجع الطريقة ، والتعبيرات والرموز. ولكل عنصر يوجد تجريد من PsiElement . أي أن كل برنامج من برامجك يتكون من PsiElements .


صورة


PsiFile ، بدوره ، هو هيكل شجرة حيث يمكن لكل عنصر أن يكون له أصل والعديد من المتحدرين.


صورة


أود أن أذكر أن PSI لا تساوي شجرة بناء جملة مجردة . شجرة بناء الجملة المجردة هي شجرة تمثيل للبرنامج الخاص بك بعد اجتياز المحلل اللغوي للبرنامج ، ويتم فصله عن أي لغة برمجة. PSI ، على العكس من ذلك ، يرتبط بلغة برمجة محددة. عند العمل مع فئة Java ، فأنت تتعامل مع Java PsiElements. عند العمل مع فئة Groovy - مع Groovy PsiElements ، وما إلى ذلك. , PSI- - , , , – .


PSI – PSI- IDEA. , , , . .


IDEA


  • PSI IDEA;
  • PSI- IDEA, ;
  • PsiElement-.

, . .



Source: https://habr.com/ru/post/ar463583/


All Articles