Создание плагина для Intellij Platform (IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm and AppCode)

в 13:01, , рубрики: IDE, intellij idea, java, jetbrains, plugins, pycharm, python, Песочница, метки: , , , , , ,

Привет!
В данном топике я расскажу как создать простой плагин для IntelliJ IDEA и PyCharm. Так как все IDE содержат одинаковый интерфейс для работы с плагинами, то модификация его для других систем не требует значительных усилий (подробнее), в отличии от процесса непосредственной разработки.

Предупреждию, что если вы решите создать свой плагин, то ожидаемый результат может сильно не соответствовать задуманному или потребует значительного времени. Если бы я знал, что получится и сколько я затратил времени, то врятли взялся бы.

Плагины пишутся на Java, UI создается на SWING. Документация для разработки плагинов состоит всего лишь из нескольких страниц и горстки примеров. На просторах интернета данная тематика не отражена совсем. Единственное, что слегка помогает это наличие исходных кодов у некоторых уже созданных плагинов.

Изначально я хотел создать окно в котором можно быстро и удобно выбрать описание стандартной библиотеки питона, но получилось плохо. Добавить ещё можно многое, хотя бы поиск и подсветку документации питона. Доделывать желания нет, пока проще по старинке использовать браузер.

image

Тогда начнем:

1) Подготовка среды

Плагины для IDE пишутся в IDE. Их придется установить и настроить.

Установка инструментов:

Нам потребуются:
— Java ( разработчики рекомендуют 1.6);
— IntelliJ IDEA Community Edition или Ultimate.(Я использовал первую, так как она бесплатная. Скачать можно здесь)

Настройка инструментов:

Необходимо настроить Java SDK и IntelliJ IDEA Plugin SDK:
— запускаем IntelliJ IDEA
— открываем пункт меню File | Project Structure
— выбираем вкладку SDKs, жмем на плюсик и выбираем путь к Java
— выбираем вкладку Project
— нажимаем на new, далее IntelliJ IDEA Plugin SDK и в открывшемся меню — выбираем путь к IntelliJ IDEA

image

Теперь можно создавать проекты плагинов.

2) Создание плагина

Плагин является обычной java программой, которая использует специальный открытый интерфейс для взаимодействия с IDE (это он только называется открытым, лучше бы closeapi назвали). Существует несколько основных видов плагинов: действие пользователя(AnAction), сервис(Service), расширения для других плагинов(Extension). Подробнее в документации. И хотя я не расширил ни одного плагина, в файле конфигурации я регистрировал именно его.

Создадим проект плагина

File | new project: Вводим имя, выбираем тип Plugin Module, выбираем SDK настроенный в шаге 1, создаем проект.

image

Далее в зависимости от разрабатываемого плагина действия будут индивидуальными. Я буду описывать как создавал свой плагин. За основу я взял пример плагина из документации — Tool Window. Чтобы получить его исходный код и код других примеров, необходимо скачать исходный код IDE.

Редактируем plugin.xml

После создания проекта появилась структура плагина и основной файл конфигурации — plugin.xml.

image

В нем мы будем регистрировать наши классы и производить их настройку. Подробнее об этом файле можно прочитать в документации.
Код файла:

<idea-plugin version="2">
  <name>DocPy</name>
  <description>Python standard documentation</description>
  <version>1.0</version>
  <vendor>YourCompany</vendor>
  <!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
  <idea-version since-build="107.105"/>
  <application-components>
    <!-- Add your application components here -->
  </application-components>
  <project-components>
    <!-- Add your project components here -->
  </project-components>
  <actions>
    <!-- Add your actions here -->
  </actions>
  <extensions defaultExtensionNs="com.intellij">
    <!-- Add your extensions here -->
  </extensions>
</idea-plugin>

Для своего плагина я добавил две строчки:

в секции idea-plugin:
<depends>com.intellij.modules.lang</depends> — для того чтобы данный плагин работал в PyCharme, если не указывать ни одной зависимости плагин будет работать только в IntelliJ IDEA. В этой секции также можно указывать необходимые зависимости для работы плагина.

в секции extensions:
<toolWindow id="PythonDoc" secondary="true" anchor="right" factoryClass="MainPanel" ></toolWindow> — для запуска класса при старте IDE и его начальное расположение: anchor — положение окна, factoryClass — наш класс

В итоге:

<idea-plugin version="2">
  <name>DocPy</name>
  <description>Python standard documentation</description>
  <version>1.0</version>
  <vendor>YourCompany</vendor>
  <idea-version since-build="107.105"/>
  <depends>com.intellij.modules.lang</depends>
  <application-components>
  </application-components>
  <project-components>
  </project-components>
  <actions>
  </actions>
  <extensions defaultExtensionNs="com.intellij">
      <toolWindow id="PythonDoc"   secondary="true" anchor="right" factoryClass="MainPanel"   >
  </extensions>
</idea-plugin>

Cоздаем класс и графический интерфейс

Так как у меня простое графическое окно, то я создаю класс из шаблона Gui Form, что позволит мне воспользоваться удобным графическим редактором для создания интерфейса. Создаю необходимые элементы:
image

Получился вот такой класс:

public class MainPanel {
    private JPanel panel1;
    private JTabbedPane tabbedPane1;
    private JTextArea MainText;
    private JList FileList;
    private JPanel FilesTab;
    private JPanel TextTab;
    private JScrollPane TextPane;
}

Тут у нас панель с двумя вкладками, на первой список файлов, на второй текст из этого файла.
Расширяем данный класс интерфейсом ToolWindowFactory.

Как я узнал о данном интерфейсе? — спросите вы.
Скопировал из примера, какие ещё бывают неизвестно и нигде не написано, один из путей — искать в исходниках других плагинов.

Реализуем требуемый метод данного интерфейса — createToolWindowContent, который вызывается при создании нашего окна. Интересные в нем только последние три строчки.

@Override
    public void createToolWindowContent(Project project, ToolWindow toolWindow) {
        final String[] FilesMas = getFileList("python-3.2.3-docs-textlibrary");
        FileList.setListData(FilesMas);
        //Обработчик события выбора элемента
        FileList.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                MainText.setText(readFileToStr("python-3.2.3-docs-textlibrary" +
                FilesMas[FileList.getSelectedIndex()]));
                //Устанавливаем курсор в верхнюю позицию
                MainText.setSelectionStart(0);
                MainText.setSelectionEnd(0);
                //Прокручиваем в начало текста
                TextPane.getVerticalScrollBar().setValue(0);
                //Переключамся на вторую вкладку
                tabbedPane1.setSelectedIndex(1);
 
            }
        });
        MainText.setText(readFileToStr("A:downloadspython-3.2.3-docs-textlibrarysqlite3.txt"));
        //Создаем фабрику контента
        ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
        //Создаем контент(окно) с нашим GUI
        Content content = contentFactory.createContent(panel1, "", false);
        //Добовляем в IDE
        toolWindow.getContentManager().addContent(content);
    }

После добавления ещё двух функций( получение списка файлов и чтение из файла) плагин готов для следующего этапа.

3) Компилируем плагин

Для использования плагина необходимо его определенным образом собрать:
Build | Prepare Plugin Module PyDoc for Deployment

Получаем в директории проекта jar файл с именем нашего проекта.

4) Устанавливаем плагин в IDE

Через настройки->Плагины->Загрузить с диска(выбираем jar полученный на предыдущем шаге) или jar файл копируем в папку plugins.

Выводы

К сожалению, разработчики и сообщество популярной линейки IDE, мало пишут о процессе создания плагинов, что не содействует к их появлению и развитию. В итоге это похоже на поиск выхода из комнаты без единого источника света. Надеюсь мой пост даст некоторый толчок в данном направлении.

Так как почти все приходилось делать вслепую, возможно я где-то допустил ошибки. Буду благодарен если поправите в комментах или через личку.

Исходный код моего проекта.

Автор: overmes

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js