Написание плагинов IntelliJ IDEA

1. Вступление

За последние несколько лет IntelliJ от JetBrains быстро стал лучшей IDE для разработчиков Java. В нашем последнем отчете State of Java IntelliJ был IDE для 55% респондентов по сравнению с 48% годом ранее.

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

И обратите внимание, что хотя эта статья посвящена плагинам IntelliJ, все интегрированные среды разработки JetBrains имеют общий код. Поэтому многие из методов, использованных здесь, могут быть применены к другим IDE JetBrain , таким как PyCharm, RubyMine и другие.

2. Функциональность плагина

Функциональность плагина для IntelliJ обычно подпадает под одну из 4 категорий:

  • Пользовательские языки : способность писать, интерпретировать и компилировать код

написано на разных языках Frameworks ** : поддержка сторонних фреймворков, таких как Spring

  • Инструменты : интеграция с внешними инструментами, такими как Gradle

  • Дополнения пользовательского интерфейса : новые пункты меню, окна инструментов и кнопки,

и больше

  • Плагины часто попадают в несколько категорий ** . Например, плагин Git , который поставляется с IntelliJ, взаимодействует с исполняемым файлом git, установленным в системе. Плагин предоставляет окно инструментов и элементы всплывающего меню, а также интегрируется в рабочий процесс создания проекта, окно настроек и многое другое.

3. Создание плагина

Самый простой способ начать работу с плагинами IntelliJ - использовать их http://www.jetbrains.org/intellij/sdk/docs/basics/getting started/using dev kit.html[Plugin DevKit]. Это может быть доступно из меню New > Project__:

ссылка:/uploads/intellij-plugin-100x66.jpg%20100w[]

  • Обратите внимание, что мы должны использовать JetBrains JDK ** , чтобы обеспечить наличие необходимых классов плагинов на пути к классам. IntelliJ должен поставляться с подходящим JDK по умолчанию, но если нет, мы можем скачать его с here .

На момент написания этой статьи мы можем использовать только Java 8 для написания плагинов IntelliJ . Это потому, что JetBrains в настоящее время не предоставляет официальный JDK для Java 9 или выше.

4. Пример плагина

Чтобы продемонстрировать написание плагина IntelliJ, мы создадим плагин, обеспечивающий быстрый доступ к популярному веб-сайту Stack Overflow из нескольких областей в среде IDE. Мы добавим:

  • Пункт меню Инструменты, чтобы посетить страницу Задать вопрос

  • Элемент всплывающего меню как в текстовом редакторе, так и в консоли для поиска

Переполнение стека для выделенного текста.

4.1. Создание действий

  • Действия являются основным компонентом, используемым для написания плагинов IntelliJ ** .

Действия инициируются событиями в IDE, такими как нажатие элемента меню или кнопки панели инструментов.

Первым шагом в создании действия является создание класса Java, который расширяет AnAction . Для нашего плагина Stack Overflow мы создадим 2 действия.

Первое действие открывает страницу «Задать вопрос» в новом окне браузера:

public class AskQuestionAction extends AnAction {
   @Override
   public void actionPerformed(AnActionEvent e) {
       BrowserUtil.browse("https://stackoverflow.com/questions/ask");
   }
}

Мы используем встроенный класс BrowserUtil , поскольку он обрабатывает все нюансы открытия веб-страницы в разных операционных системах и браузерах.

Второе действие открывает страницу поиска переполнения стека и передает текст поиска в виде строки запроса. На этот раз мы реализуем два метода.

Первый метод, который мы реализуем, похож на наше первое действие и обрабатывает открытие веб-браузера.

Однако сначала нам нужно собрать два значения для StackOverflow. Одним из них является языковой тег, а другим - текст для поиска.

Чтобы получить языковой тег, мы будем использовать Program Structure Interface . Этот API анализирует все файлы в проекте и предоставляет программный способ их проверки.

В этом случае мы используем PSI для определения языка программирования файла:

PsiFile file = e.getData(CommonDataKeys.PSI__FILE);
Language lang = e.getData(CommonDataKeys.PSI__FILE).getLanguage();
String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

Обратите внимание, что PSI также предоставляет информацию о файле для конкретного языка.

Например, мы могли бы использовать PSI для поиска всех открытых методов в классе Java.

Чтобы получить текст для поиска, мы будем использовать __Editor __API для получения выделенного текста на экране:

final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
String selectedText = caretModel.getCurrentCaret().getSelectedText();

Хотя это действие одинаково для окон редактора и консоли, доступ к выделенному тексту работает одинаково.

Теперь мы можем собрать все это вместе в объявлении actionPerformed :

@Override
public void actionPerformed(AnActionEvent e) {

    PsiFile file = e.getData(CommonDataKeys.PSI__FILE);
    Language lang = e.getData(CommonDataKeys.PSI__FILE).getLanguage();
    String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

    Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
    CaretModel caretModel = editor.getCaretModel();
    String selectedText = caretModel.getCurrentCaret().getSelectedText()

    String query = selectedText.replace(' ', '+') + languageTag;
    BrowserUtil.browse("https://stackoverflow.com/search?q=" + query);
}

Это действие также отменяет второй метод с именем update . Это позволяет нам включать или отключать действие в различных условиях.

В этом случае мы отключаем действие поиска, когда нет выделенного текста:

@Override
public void update(AnActionEvent e) {
     Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
     CaretModel caretModel = editor.getCaretModel();
     e.getPresentation().setEnabledAndVisible(caretModel.getCurrentCaret().hasSelection());
}

4.2. Регистрация действий

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

Первый способ - использовать файл plugin.xml , который создается для нас, когда мы начинаем новый проект.

По умолчанию в файле будет пустой элемент <actions> , куда мы добавим наши действия:

<actions>
    <action
      id="StackOverflow.AskQuestion.ToolsMenu"
      class="com.baeldung.intellij.stackoverflowplugin.AskQuestionAction"
      text="Ask Question on Stack Overflow"
      description="Ask a Question on Stack Overflow">
        <add-to-group group-id="ToolsMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Editor"
      class="com.baeldung.intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="EditorPopupMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Console"
      class="com.baeldung.intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="ConsoleEditorPopupMenu" anchor="last"/>
    </action>
</actions>

Использование файла XML для регистрации действий обеспечит их регистрацию во время запуска IDE, что обычно является предпочтительным.

Второй способ зарегистрировать действия - это программно использовать класс ActionManager :

ActionManager.getInstance().registerAction("StackOverflow.SearchAction", new SearchAction());

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

Недостатком этого подхода является то, что действия не регистрируются при запуске. Мы должны создать экземпляр ApplicationComponent для управления действиями, что требует больше кодирования и настройки XML.

5. Тестирование плагина

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

Мы можем вручную протестировать (и отладить) наш плагин, используя конфигурацию запуска плагина:

ссылка:/uploads/intellij-plugin-run-configuration-100x71.jpg%20100w[]

Это запустит новый экземпляр IntelliJ с активированным нашим плагином.

Это позволяет нам щелкать по различным пунктам меню, которые мы создали, и открывать соответствующие страницы переполнения стека.

Если вы хотите выполнить более традиционное модульное тестирование, IntelliJ предоставляет headlessless environment для запуска модульных тестов. Мы можем писать тесты, используя любую среду тестирования, какую захотим, и тесты выполняются с использованием реальных немодированных компонентов из IDE.

6. Развертывание плагина

Плагин DevKit предоставляет простой способ упаковки плагинов, чтобы мы могли их устанавливать и распространять. Просто щелкните правой кнопкой мыши по проекту плагина и выберите «Подготовить модуль плагина к развертыванию». Это сгенерирует файл JAR внутри директории проекта.

Сгенерированный файл JAR содержит код и файлы конфигурации, необходимые для загрузки в IntelliJ. Вы можете установить его локально или опубликовать в plugin хранилище для использования другими.

На снимке экрана ниже показан один из новых пунктов меню Stack Overflow в действии:

ссылка:/uploads/intellij-stackoverflow-pluginjpg-100x41.jpg%20100w[]

7. Заключение

В этой статье мы разработали простой плагин, который подчеркивает лишь некоторые из способов улучшения IntelliJ IDE.

Хотя мы в основном работали с действиями, плагин IntelliJ SDK предлагает несколько способов добавления новых функций в IDE. Для дальнейшего чтения, ознакомьтесь с official руководством по началу работы .

Как всегда, полный код нашего примера плагина можно найти в нашем GitHub репозитории .