Разработка на плъгини IntelliJ IDEA
Напоследък натрупах достатъчно материали за разработката на плъгини за IntelliJ IDEA, които смятам да споделя с общността на habra.
Среда за развитие и инфраструктура
Преди да започнете да програмирате плъгин, струва си да обмислите дизайна на средата за разработка, поддържаните функции и тяхното внедряване и, разбира се, настройката на IDE, необходима за разработване на плъгини.
Всяка съвременна версия на Intellij IDEA е подходяща за разработване на плъгини - тя вече включва пълен набор от необходими инструменти. Има няколко стъпки за настройка на средата за разработка:
- изтеглете изходните кодове на съответната версия на Intellij IDEA Community Edition;
- създайте SDK от типа "Intellij Platform Plugin SDK" (на фигурата по-долу) и посочете пътя до инсталираното Community Edition (можете да използвате Ultimate Edition, но отстраняването на грешки във вътрешните API функции работи само в CE);
- в настройките на SDK, на страницата Sourcepath, трябва да посочите пътя до изходните кодове, изтеглени в стъпка 1;
- създайте нов модул с тип "Platform Plugin" и присвоете създадения преди това SDK към него.

След това можете да започнете да разработвате плъгина като обикновен Java проект, но с допълнителната възможност да видите изходния код на вътрешния API и да проследите изпълнението му в дебъгера.
Изградете числа
Това са ограничения за диапазона от поддържани версии, използвани от рамката, за да се определи дали определен плъгин може да работи правилно. Началният и крайният номер на компилациите са посочени във файла plugin.xml, както и в друга мета-информация. Започвайки с IntelliJ IDEA 9, се използва съставно номериране на компилации: например IU-90.94. Този номер се състои от следноточасти:
- ID на продукта (IC за IDEA Community, IU за IDEA Ultimate, RM за RubyMine и PY за PyCharm);
- номер на клон;
- номер на компилация в тази тема.
Комбинираните номера на компилации могат да се използват в таговете since-build и until-build във файла plugin.xml. Обикновено идентификаторът на продукта се пропуска, като се използва само клонът и номерът на компилация:
Съвместимост на плъгини с продукти на платформа IntelliJ
Всички продукти, базирани на платформата IntelliJ (IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm и AppCode), споделят общ базов API на платформата. По този начин плъгините, които не използват никаква конкретна функционалност на Java, могат да бъдат маркирани като съвместими с други продукти, а не само със самата IDEA. Можете да направите това, като дефинирате зависимостите на модула във файла plugin.xml. Зависимостите се поставят вътре в тага Ако даден плъгин не включва тагове за зависимости в plugin.xml, той е остарял и може да работи само в IDEA. Ако plugin.xml съдържа поне един такъв таг, той ще бъде зареден, ако продуктът съдържа всички модули, за които се отнася. В момента във всички продукти от фамилията IntelliJ са налични следните модули:
- com.intellij.modules.platform
- com.intellij.modules.lang;
- com.intellij.modules.vcs
- com.intellij.modules.xml
- com.intellij.modules.xdebugger.
- com.intellij.modules.java - IntelliJ IDEA;
- com.intellij.modules.ruby - RubyMine;
- com.intellij.modules.python - PyCharm
- com.intellij.modules.objc - AppCode.
Преди да направите плъгин съвместим с други продукти, струва си да се уверите, че не се използват функции, специфични за IntelliJ IDEA API. За да направите това, трябва да създадете SDK, който сочи към инсталирания RubyMine или PyCharm, да компилирате плъгина с този SDK и да проверите дали работи.
Структура на приставката IntelliJ IDEA
Плъгините са единственият поддържан начин за разширяване на функционалността на IDEA. Приставката използва предоставения API на средата или други приставки, за да реализира собствената си функционалност. Нека обърнем внимание на структурата и жизнения цикъл на плъгина.
Съдържание на плъгина
Има три начина за организиране на съдържанието на плъгина. Първо, приставката съдържа един jar файл, намиращ се в папката на приставките. Архивът трябва да съдържа конфигурационен файл (META-INF/plugin.xml) и класове, които изпълняват функционалността на приставката. Конфигурационният файл дефинира името на плъгина, описанието, подробностите за разработчика, поддържаната IDE версия, компонентите, действията, групите действия.
Вторият начин - файловете на плъгина се намират в папката:
Класовете и lib се добавят автоматично към classpath. Трети начин - файловете на плъгина се поставят в jar файл, намиращ се в папката lib:
Товарачи за класове
За да зареди класовете на всеки плъгин, IDEA използва отделни програми за зареждане на класове. Това позволява да се използват различни версии на библиотеката, дори ако се използват от самата IDEA или от друг плъгин. По подразбиране основното средство за зареждане на класове зарежда само тези класове, които не са намерени от товарача на приставката. Въпреки това, в plugin.xml, в раздела за зависимости, можете да дефинирате зависимости от други добавки. В такъв случай програмите за зареждане на класове на тези добавки ще бъдат използвани за разрешаване на ненамерените класове в текущия плъгин. Това ви позволява да препращате към класове от други добавки.
Компоненти на плъгина
Компонентите са основната концепция за интегриране на плъгини. Има три вида компоненти:
- ниво на приложение;
- ниво на проекта;
- модулно ниво.
Компонентите на ниво проект се създават за всяко копие на класа Project (те дори могат да бъдат създадени за неотворен проект). Те могат да бъдат получени от екземпляра на Project чрез извикване на метода getComponent(Class).
Компонентите на ниво модул се създават за всеки модул във всеки проект, зареден в IDEA. Те могат да бъдат получени по подобен начин от екземпляр на модул.
Всеки компонент трябва да реализира интерфейса, дефиниран в конфигурационния файл. Интерфейсът на класа ще се използва за получаване на bean-а от други bean-ове, изпълнението на класа ще се използва по време на инициализацията на bean-а. Важно е да се отбележи, че два компонента на едно и също ниво (модул, проект, приложение) не могат да имат един и същ интерфейс.
Всекикомпонентът трябва да има уникално име, което ще се използва при експортиране и други вътрешни нужди. Името на компонента се връща от метода getComponentName(). Препоръчително е да използвате следното име на компонент: .
Освен това, клас, който имплементира интерфейс на компонент на ниво приложение, може също да имплементира интерфейса на ApplicationComponent. Компонент на приложение, който няма никакви зависимости, трябва да предостави конструктор без параметри, който ще бъде извикан при създаване. Ако даден компонент зависи от други, той може да ги приеме като параметри на конструктора, IDEA гарантира, че тези компоненти са правилно инициализирани в правилния ред.
Класовете, които имат функционалността на компонент на ниво проект, реализират интерфейса ProjectComponent. Конструкторът на клас bean трябва да има параметър от тип Project, ако използва екземпляр на проект. Може също така да приеме други компоненти на ниво приложение или на ниво проект като параметри, ако има зависимост от тях.
Компонентите на ниво проект трябва да бъдат регистрирани в раздел
конфигурационен файл. Както при компонентите на приложението, можете да използвате помощта на IDE, като изберете подменюто „Нов компонент на проекта“.
Компонентите на ниво модул реализират интерфейса ModuleComponent. Зависимостите на компонентите могат да се предават като параметри на конструктора. Компонентите трябва да се регистрират ръчно или чрез изпълнение на елемента от контекстното меню "Нов модулен компонент".
Запазване на състоянието на компонента
Жизнен цикъл на компонента
Компонентите се зареждат в следния ред:
- създаване - изпълнение на конструктора;
- инициализация - извикване на метода initComponent (ако интерфейсът ApplicationComponent е имплементиран);
- конфигурация -извикване на readExternal (ако е имплементиран JDOMExternalizable) или loadState (ако е имплементиран PersistentStateComponent и компонентът е в състояние различно от подразбиране);
- за компоненти на ниво модул, извикайте moduleAdded (ако е внедрен ModuleComponent);
- за компоненти на ниво проект, projectOpened (ако интерфейсът ProjectComponent е внедрен).
- запазване на конфигурацията - извикване на writeExternal (ако е имплементиран интерфейсът JDOMExternalizable) или getState (ако е имплементиран PersistentStateComponent);
- освобождаване на ресурси - извикване на метода disposeComponent.
Разширения на приставки и точки за разширение
Intellij IDEA предоставя концепцията заразширенияиточки за разширение, които ви позволяват да взаимодействате с други добавки и ядрото на IDEA. Ако искате плъгин да ви позволи да разширите неговата функционалност, трябва да дефинирате една или повече точки за разширение. Всяка такава точка дефинира клас или интерфейс, който дефинира протокола за достъп до нея. Същото важи и за разширенията на плъгини.
Можете да дефинирате разширения и точки за разширение в конфигурационния файл в секциите Атрибутът "интерфейс" задава интерфейса, който трябва да бъде внедрен, за да се разшири функционалността. Атрибутът "beanClass" дефинира клас, съдържащ едно или повече свойства, анотирани с анотацията @Attribute. Плъгинът, предоставящ точката на разширение, ще прочете тези свойства от файлаplugin.xml Разгледайте пример с MyBeanClass1:
За да декларирате разширение с достъп до точката на разширение MyExtPoint, конфигурационният файл трябва да съдържа таг с атрибутите "key" и "implementationClass" със съответните стойности.
За да регистрирате разширение, са необходими следните стъпки:
- на елемента задайте стойността на атрибута "xmlns" (отхвърлено) или "defaultExtensionNs" на едно от следните:
- "com.intellij", ако плъгинът разширява функционалността на IDEA ядрото;
- ако плъгинът разширява функционалността на друг плъгин. добавете нов дъщерен елемент към секцията, името на етикета трябва да съвпада с идентификатора на точката на разширение; дефинирайте типа точка на разширение, като изберете от следното:
- ако точка на разширение е декларирана с атрибута "interface", тогава атрибутът "implementation" трябва да бъде указан в дъщерния елемент, чиято стойност е класът, който имплементира този интерфейс;
- ако точка на разширение е декларирана с атрибута "beanClass", тогава дъщерният елемент трябва да съдържа всички атрибути, които са били анотирани в този клас с анотацията @Attribute.
Действия
Intellij IDEA също предоставя концепцията за действия. Action е клас, който наследява от AnAction, чийто метод actionPerformed() се извиква, когато е избран елемент от менюто или бутон от лентата с инструменти.
Действията се комбинират в групи, които могат да съдържат и вложени групи. Групите за действие могат да се показват като менюта или ленти с инструменти. Подгрупите се показват като подменюта. Действията ще бъдат разгледани по-подробно по-късно.
Услугата е компонент, който се зарежда при поискване, когато плъгинът извиква метода getService() на класа ServiceManager. Intellij IDEA гарантира, че ще бъде създаден само един екземпляруслуга, без значение колко пъти е бил извикан методът.
Услугите трябва да имат интерфейс, дефиниран в plugin.xml. Класът с имплементацията ще се използва за създаване на услугата.
Услугите са на нива като компоненти, т.е. към услуги на ниво приложение, ниво проект и ниво модул, които съответстват съответно на точките за разширение на applicationService, projectService и moduleService.
За да декларирате услуга е необходимо:
- добавете съответния дъщерен елемент ( , , ) към секцията; Задайте следните атрибути за добавения елемент:
- "serviceInterface" – сервизен интерфейс;
- "serviceImplementaion" – изпълнение на услугата.
Интерфейсът и класовете за изпълнение могат да бъдат еднакви. Пример от файл plugin.xml:
В следващата част: конфигурационен файл, действия, проекти и т.н.