Разработка на плъгини 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 към него.
intellij

След това можете да започнете да разработвате плъгина като обикновен Java проект, но с допълнителната възможност да видите изходния код на вътрешния API и да проследите изпълнението му в дебъгера.

Изградете числа

Това са ограничения за диапазона от поддържани версии, използвани от рамката, за да се определи дали определен плъгин може да работи правилно. Началният и крайният номер на компилациите са посочени във файла plugin.xml, както и в друга мета-информация. Започвайки с IntelliJ IDEA 9, се използва съставно номериране на компилации: например IU-90.94. Този номер се състои от следноточасти:

  • ID на продукта (IC за IDEA Community, IU за IDEA Ultimate, RM за RubyMine и PY за PyCharm);
  • номер на клон;
  • номер на компилация в тази тема.
Всеки път, когато се създава клон на версия на един от продуктите, базиран на платформата IntelliJ, номерът на клон се увеличава с 1, а номерът на ствола с 2, така че нестабилните компилации имат четен номер, а стабилните компилации имат нечетен номер.

Комбинираните номера на компилации могат да се използват в таговете 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.
PhpStorm няма конкретен модул, но включва PHP плъгин, който също може да се използва като зависимост:com.jetbrains.php. Възможно е също да използвате незадължителни зависимости. Ако приставката работи с всички продукти, но предоставя някои специфични за Java функционалности, тогава може да се използва следният таг:

Преди да направите плъгин съвместим с други продукти, струва си да се уверите, че не се използват функции, специфични за 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, в раздела за зависимости, можете да дефинирате зависимости от други добавки. В такъв случай програмите за зареждане на класове на тези добавки ще бъдат използвани за разрешаване на ненамерените класове в текущия плъгин. Това ви позволява да препращате към класове от други добавки.

Компоненти на плъгина

Компонентите са основната концепция за интегриране на плъгини. Има три вида компоненти:

  1. ниво на приложение;
  2. ниво на проекта;
  3. модулно ниво.
Компонентите на ниво приложение се създават и инициализират по време на стартиране на IntelliJ IDEA. Могат да бъдат получени от екземпляр на класа Application с помощта на метода getComponent(Class).

Компонентите на ниво проект се създават за всяко копие на класа 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.
Забранено е използването на метода getComponent() в конструктора на компонент за получаване на каквито и да било зависимости. Ако този компонент трябва да получи други компоненти по време на инициализацията, те трябва да бъдат предадени в параметрите на конструктора или да прехвърлите инициализацията към метода initComponent().

Разширения на приставки и точки за разширение

Intellij IDEA предоставя концепцията заразширенияиточки за разширение, които ви позволяват да взаимодействате с други добавки и ядрото на IDEA. Ако искате плъгин да ви позволи да разширите неговата функционалност, трябва да дефинирате една или повече точки за разширение. Всяка такава точка дефинира клас или интерфейс, който дефинира протокола за достъп до нея. Същото важи и за разширенията на плъгини.

Можете да дефинирате разширения и точки за разширение в конфигурационния файл в секциите Атрибутът "интерфейс" задава интерфейса, който трябва да бъде внедрен, за да се разшири функционалността. Атрибутът "beanClass" дефинира клас, съдържащ едно или повече свойства, анотирани с анотацията @Attribute. Плъгинът, предоставящ точката на разширение, ще прочете тези свойства от файлаplugin.xml Разгледайте пример с MyBeanClass1:

За да декларирате разширение с достъп до точката на разширение MyExtPoint, конфигурационният файл трябва да съдържа таг с атрибутите "key" и "implementationClass" със съответните стойности.

За да регистрирате разширение, са необходими следните стъпки:

  1. на елемента задайте стойността на атрибута "xmlns" (отхвърлено) или "defaultExtensionNs" на едно от следните:
  2. "com.intellij", ако плъгинът разширява функционалността на IDEA ядрото;
  3. ако плъгинът разширява функционалността на друг плъгин.
  4. добавете нов дъщерен елемент към секцията, името на етикета трябва да съвпада с идентификатора на точката на разширение; дефинирайте типа точка на разширение, като изберете от следното:
    • ако точка на разширение е декларирана с атрибута "interface", тогава атрибутът "implementation" трябва да бъде указан в дъщерния елемент, чиято стойност е класът, който имплементира този интерфейс;
    • ако точка на разширение е декларирана с атрибута "beanClass", тогава дъщерният елемент трябва да съдържа всички атрибути, които са били анотирани в този клас с анотацията @Attribute.

Действия

Intellij IDEA също предоставя концепцията за действия. Action е клас, който наследява от AnAction, чийто метод actionPerformed() се извиква, когато е избран елемент от менюто или бутон от лентата с инструменти.

Действията се комбинират в групи, които могат да съдържат и вложени групи. Групите за действие могат да се показват като менюта или ленти с инструменти. Подгрупите се показват като подменюта. Действията ще бъдат разгледани по-подробно по-късно.

Услугата е компонент, който се зарежда при поискване, когато плъгинът извиква метода getService() на класа ServiceManager. Intellij IDEA гарантира, че ще бъде създаден само един екземпляруслуга, без значение колко пъти е бил извикан методът.

Услугите трябва да имат интерфейс, дефиниран в plugin.xml. Класът с имплементацията ще се използва за създаване на услугата.

Услугите са на нива като компоненти, т.е. към услуги на ниво приложение, ниво проект и ниво модул, които съответстват съответно на точките за разширение на applicationService, projectService и moduleService.

За да декларирате услуга е необходимо:

  • добавете съответния дъщерен елемент ( , , ) към секцията; Задайте следните атрибути за добавения елемент:
  • "serviceInterface" – сервизен интерфейс;
  • "serviceImplementaion" – изпълнение на услугата.

Интерфейсът и класовете за изпълнение могат да бъдат еднакви. Пример от файл plugin.xml:

В следващата част: конфигурационен файл, действия, проекти и т.н.