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

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

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

1. Введение

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

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

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

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

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

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

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

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

Самый простой способ начать работу с плагинами IntelliJ — использовать их Plugin DevKit . Доступ к этому можно получить из меню « Создать » > «Проект» :

./97e2bfa1a30e9a8e85dfab1796ff7f4e.jpg

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

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

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

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

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

Чтобы получить языковой тег, мы будем использовать интерфейс структуры программы . Этот 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.

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

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

./69b545d0212d2233b3b54f1ebb0c2430.jpg

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

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

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

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

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

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

./772cea1ae4d85102f0f1a60da2a37831.jpg

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

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

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

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