Перейти к основному содержимому

Написание подключаемых модулей IntelliJ IDEA с использованием Gradle

· 6 мин. чтения

1. Введение

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

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

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

2. Основные типы плагинов

Наиболее распространенные типы плагинов включают в себя функции для:

  • Поддержка пользовательских языков: возможность писать, интерпретировать и компилировать код, написанный на разных языках .
  • Интеграция с фреймворком: поддержка сторонних фреймворков, таких как Spring .
  • Интеграция инструментов: интеграция с внешними инструментами, такими как Gradle
  • Дополнения пользовательского интерфейса: новые пункты меню, окна инструментов, индикаторы выполнения и многое другое .

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

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

Существует два поддерживаемых способа создания плагинов. Мы будем использовать рекомендуемый способ для новых проектов с Gradle вместо использования их Plugin Devkit .

Создание плагина на основе Gradle выполняется с помощью меню « Создать» > «Проект» .

./fb1763084dcb22a6ce5fb974f81de474.png

Обратите внимание, что мы должны включить Java и подключаемый модуль платформы IntelliJ , чтобы обеспечить доступность необходимых классов подключаемых модулей в пути к классам.

На момент написания этой статьи мы можем использовать JDK 8 только для написания плагинов IntelliJ .

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

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

  • пункт меню «Инструменты», чтобы перейти на страницу «Задать вопрос».
  • пункт всплывающего меню как в текстовом редакторе, так и в выводе консоли для поиска выделенного текста в переполнении стека

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

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

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

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

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

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

Для выполнения поиска в StackOverflow нам нужны два параметра: тег языка и текст для поиска.

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

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

Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
String languageTag = psiFile.map(PsiFile::getLanguage)
.map(Language::getDisplayName)
.map(String::toLowerCase)
.map(lang -> "[" + lang + "]")
.orElse("");

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

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

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

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

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
String languageTag = psiFile.map(PsiFile::getLanguage)
.map(Language::getDisplayName)
.map(String::toLowerCase)
.map(lang -> "[" + lang + "]")
.orElse("");

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

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

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

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.foreach.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.foreach.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.foreach.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 требует тестирования. Для небольшого плагина, такого как тот, который мы написали, достаточно убедиться, что плагин компилируется и что созданные нами действия работают должным образом, когда мы нажимаем на них.

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

./0302da8e19de0bc8cefa43154873b303.png

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

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

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

Плагин Gradle предоставляет простой способ упаковки плагинов, чтобы мы могли их устанавливать и распространять. Просто откройте окно инструмента Gradle и выполните задачу buildPlugin . Это создаст ZIP-файл внутри каталога build/distributions .

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

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

./ab53c02ec88f99a0f5358135d8b88478.png

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

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

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

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