Как создать плагин для IntelliJ IDEA на примере генератора директорий для проекта

от автора

Меня зовут Александр Мамонов, и в KODE я занимаюсь разработкой на Flutter. Я столкнулся с бойлерплейтом композиции фич в наших проектах, поэтому решил написать универсальный плагин для создания файловой структуры фич в проекте.

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

Подготовка

В начале нужно установить плагин «Plugin Dev Kit» из магазина плагинов https://plugins.jetbrains.com/plugin/22851-plugin-devkit.

Шаг 1. Создание проекта

Выбираем «Создать новый проект». Затем тип проекта — IDE Plugin, и указываем его название.

Должен получиться такой шаблон:

Шаг 2. Конфигурация проекта

Открываем gradle.properties и вставляем параметры. Ниже в комментариях в коде указаны ссылки на ресурсы, где можно подробнее ознакомиться с параметрами.

# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html   pluginGroup = com.your_feature_name pluginName = your_feature_name pluginRepositoryUrl = https://github.com/Name/your_feature_name # SemVer format -> https://semver.org pluginVersion = 1.0.0   # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 232 #pluginUntilBuild = 251.*   # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType = IC platformVersion = 2023.2.6   # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 platformPlugins =   # Gradle Releases -> https://github.com/gradle/gradle/releases gradleVersion = 8.7   # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib kotlin.stdlib.default.dependency = false   # Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html org.gradle.configuration-cache = true   # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html org.gradle.caching = true

Затем открываем plugin.xml

и заменяем содержимое на:

<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html --> <idea-plugin>    <!-- Unique identifier of the plugin. It should be FQN. It cannot be changed between the plugin versions. -->    <id>com.name.your_feature_name</id>      <!-- Public plugin name should be written in Title Case.         Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-name -->    <name>Your_feature_name</name>      <!-- A displayed Vendor name or Organization ID displayed on the Plugins Page. -->    <vendor email="support@yourcompany.com" url="https://www.yourcompany.com">YourCompany</vendor>      <!-- Description of the plugin displayed on the Plugin Page and IDE Plugin Manager.         Simple HTML elements (text formatting, paragraphs, and lists) can be added inside of <![CDATA[ ]]> tag.         Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-description -->    <description><![CDATA[    Enter short description for your plugin here.<br>    <em>most HTML tags may be used</em>  ]]></description>      <!-- Product and plugin compatibility requirements.         Read more: https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->    <depends>com.intellij.modules.platform</depends>    <depends>org.jetbrains.kotlin</depends>      <!-- Extension points defined by the plugin.         Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->    <extensions defaultExtensionNs="com.intellij">      </extensions>      <!-- тут описываются команды или слушатели ide на которые должен реалигровать плагин    В нашем примере мы создаим одно действие для генерации шаблона -->    <actions>        <action id="GenerateCleanCode.NewAction"                icon="/META-INF/pluginIcon.svg"                class="com.your_feature_name.GenerateFolderStructureAction"                text="Create New Feature">            <add-to-group group-id="NewGroup" anchor="last"/>        </action>    </actions>    </idea-plugin>   

group-id=»NewGroup» добавляет наше действие в группу “new” при взаимодействии с директориями, а anchor=»last» добавляет наше действие последним в списке.

В параметр icon можно добавить свою svg-иконку, которая будет использоваться как в магазине приложений, так и в самой IDE при выборе действия.

В данный момент IDE будет ругаться на параметр class — мы его создадим в следующем шаге.

Шаг 3. Код плагина

Создадим класс  InputDialog

и наполним его:

import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.ui.Messages import java.awt.* import javax.swing.JComponent import javax.swing.JLabel import javax.swing.JPanel import javax.swing.JTextField   class InputDialog : DialogWrapper(null) {    private val textField = JTextField(20)    var featureName = ""      init {        init()        title = "Enter Feature Name"    }      override fun createCenterPanel(): JComponent {        val panel = JPanel(BorderLayout())        panel.add(JLabel("Feature Name:"), BorderLayout.WEST)        panel.add(textField, BorderLayout.CENTER)        return panel    }      override fun getPreferredSize(): Dimension {        return Dimension(300, 100)    }      override fun doOKAction() {        featureName = textField.text.trim()        if (featureName.isEmpty()) {            Messages.showErrorDialog("Feature name cannot be empty.", "Error")            return        }        super.doOKAction()    } } 

Этот диалог будет вызываться при нажатии нашего действия и будет выглядеть вот так:

Следом создаем GenerateFolderStructureAction

и наполняем его:

package com.your_feature_name     import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.ui.Messages import com.intellij.openapi.vfs.VirtualFile import java.util.*     class GenerateFolderStructureAction : AnAction() {    override fun actionPerformed(event: AnActionEvent) { //      тут мы используем созданный нами ранее диалог        val dialog = InputDialog() //      показываем его        dialog.show()        ApplicationManager.getApplication().runWriteAction {            if (dialog.isOK) { //              достаем введенное пользователем название                val featureName = dialog.featureName //              получаем системный путь где начать создание шаблона                val libDir = event.getData(PlatformDataKeys.VIRTUAL_FILE)                generateFolderStructure(libDir, featureName)            }        }      }      private fun generateFolderStructure(libDir: VirtualFile?, featureName: String) {        if (libDir != null) { //          создаем подпапку с введеным пользователем названием            val featureDir = libDir.createChildDirectory(null, featureName)   //          data              val dataDir = featureDir.createChildDirectory(null, "data") //          в созданной директории создаем файл "${featureName}_data_source.dart" - расширение файла и его содержимое могут быть любыми //          .createChildData создает файл с указаным именем и расширениием //          .setBinaryContent записывает нужный нам текст внутрь созданного файла            dataDir.createChildDirectory(null, "data_source").createChildData(null, "${featureName}_data_source.dart")                .setBinaryContent(getDataSourceContent(featureName).toByteArray())            //          ... тут можно дальше создавать новые директории и файлы            //          показываем диалог с успешным завершением генерации шаблона            showToastMessage("Generated Successfully!")          }    }      private fun String.toCamelCase(): String {        return this.split("_")            .joinToString("") { it.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } }    }      private fun showToastMessage(message: String) {        ApplicationManager.getApplication().invokeLater {            Messages.showMessageDialog(message, "Success", Messages.getInformationIcon())        }    }      private fun getDataSourceContent(featureName: String): String { //      при записи в файл | - указывает начало строки, чтобы у содержимого сохранилось форматирование        return """            |final class ${featureName.toCamelCase()}DataSource {            |  const ${featureName.toCamelCase()}DataSource({required NetworkService service}) : _service = service;            |            | final NetworkService _service;            |            | }            |        """.trimMargin()    }   } 

Шаг 4. Запуск и сборка

Для того, чтобы проверить плагин, в верхнем правом углу будет команда run plugin.

Она запустит новое окно IDE с включенным в него вашим плагином. Если плагин отработал корректно, пришло время сборки и публикации.

Создаем новое действие Gradle, а в команде выбираем runPluginVerifier:

Запускаем новый скрипт:

И исправляем ошибки — в том случае, если они будут.

Если скрипт прошел успешно, то в папке build/distributions будет лежать .zip архив с вашим плагином.

Если вы хотите поделиться плагином локально, данный архив можно установить без публикации, через команду install Plugin from Disk в самой студии.

Шаг 5. Публикация

Создаем аккаунт в https://plugins.jetbrains.com/ и выбираем upload plugin:

Заполняем поля, делаем скриншоты работы нашего плагина и следуем дальнейшим подсказкам от jetbrains.

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


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

Ознакомиться с реализацией можно на GitHub: https://github.com/Skleprozzz/intellij_flutter_clean_feature

Магазин плагинов JetBrains: https://plugins.jetbrains.com/plugin/24862-flutter-clean-feature

Надеюсь, дальнейшее развитие вашего плагина пойдет проще!


ссылка на оригинал статьи https://habr.com/ru/articles/880028/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *