skip to content
usubeni fantasy logo Usubeni Fantasy

IntelliJ 插件开发

/ 6 min read

注意:这是一篇草稿,但是因为 IntelliJ 插件开发参考资料实在太少,就放出来吧,不知道以后还有没有机会完善,怀念写 kotlin 的一周(哈哈)。

难点与应对方法:

  • 语言基本陌生——问题不大
  • IDE 完全陌生——看文档
  • 插件运行原理一点都不知道——根据文档了解核心概念
  • sdk一点都不知道,这对工时评估影响很大——这个就真的最花时间的了

先决条件:

  • JVM 语言
  • Gradle
  • Swing
  • 熟悉 IDE

Gradle

构建脚本 build.gradle(Groovy/kotlin)

Gradle Wrapper 通过使用 gradle-wrapper.properties 配置文件来确保每个开发者和 CI 工具都使用相同的 Gradle 版本。

Swing

学 Swing 有感:终于知道后端学 CSS 有多难了。而且 Swing 不能实时调试,教程也不多。

IDE

窗口结构:https://www.jetbrains.com/help/idea/guided-tour-around-the-user-interface.html

IDE 开发体验确实好,自动改名,新建类,一键加参数

插件模板

https://github.com/JetBrains/intellij-platform-plugin-template

项目结构

.
├── .github/ GitHub Actions
├── .run/ Run/Debug 配置
├── build/ 构建目录
├── gradle
│ ├── wrapper/ Gradle Wrapper
│ └── libs.versions.toml Gradle version catalog
├── src Plugin 代码
│ ├── main
│ │ ├── kotlin/ Kotlin 代码
│ │ └── resources/ 资源文件夹 - plugin.xml <- 这是重点, icons, messages
│ └── test
│ ├── kotlin/ 测试代码
│ └── testData/ 测试数据
├── .gitignore
├── build.gradle.kts Gradle build 配置
├── CHANGELOG.md Full change history
├── gradle.properties Gradle 配置
├── gradlew *nix Gradle Wrapper script
├── gradlew.bat Windows Gradle Wrapper script
├── LICENSE
├── qodana.yml
├── README.md
└── settings.gradle.kts Gradle project settings

plugin.xml

<idea-plugin>
<id>org.jetbrains.plugins.template</id>
<name>Template</name>
<vendor>JetBrains</vendor>
<depends>com.intellij.modules.platform</depends>
<resource-bundle>messages.MyBundle</resource-bundle>
<extensions defaultExtensionNs="com.intellij">
<toolWindow factoryClass="..." id="..."/>
</extensions>
<applicationListeners>
<listener class="..." topic="..."/>
</applicationListeners>
</idea-plugin>

开发资料

文档写得一般,没有系统教程,只能看开源插件学习

开启内部模式

这里还有个也没多大用的 samples 仓库

重要概念

Action

在IntelliJ插件开发中,“Action” 是一个核心概念。一般来说,一个 “Action” 就是用户可以执行的一个操作或命令,它可以被关联到菜单项、工具栏按钮或者快捷键。 例如:打开一个新的文件、剪切和粘贴文本、用某种语言运行代码等都是 “Actions”。

你可以通过创建和注册自定义 “Action” 来扩展 IntelliJ 的功能。每个 “Action” 都需要提供一个 “actionPerformed” 方法,当用户触发该操作时,这个方法会被调用。

在 IntelliJ 的插件开发中,使用 XML 文件(通常是 plugin.xml)来注册你的 “Action”,并指定其所在的位置,如 “File” 菜单或者右键弹出菜单等。

你可以选 action 插入的位置、触发快捷键,这些都是以用户触发为基础的。所以如果你的插件或程序不需要用户触发,只需要在后台或者特定条件下自动执行某些操作,你只需要编写普通的处理类就行了。

Service

https://plugins.jetbrains.com/docs/intellij/plugin-services.html

服务是一个全局或项目级别的单例,用于保存数据和状态,或者提供复杂的操作。

Listener & Message

监听和响应 Topic

Extension Point

EP:https://plugins.jetbrains.com/docs/intellij/intellij-platform-extension-point-list.html

没太看懂,ai是这么跟我解释的:在IntelliJ中,extension point不是一个class,而是一个特殊的接口,它为你的插件提供了扩展应用程序的能力。使用extension point,你可以将自己的代码插入到IDE的生命周期中的特定点,让你的代码在某些特定事件发生时被执行。这是IntelliJ插件开发的重要组成部分,用于实现插件的具体功能。

例子:

<extensions defaultExtensionNs="com.intellij">
<lang.parserDefinition implementation="your.package.YourParserDefinition"/>
</extensions>
public class YourParserDefinition implements ParserDefinition {
public static final IFileElementType FILE = new IFileElementType(YourLanguage.INSTANCE);
@NotNull
@Override
public Lexer createLexer(Project project) {
return new YourLexerAdapter();
}
@Override
public PsiParser createParser(Project project) {
return new YourPsiParser();
}
@Override
public IFileElementType getFileNodeType() {
return FILE;
}
@NotNull
@Override
public TokenTypeRemapper getWhitespaceTokens() {
return YourLanguageTokens.WHITESPACES;
}
@NotNull
@Override
public TokenTypeRemapper getCommentTokens() {
return YourLanguageTokens.COMMENTS;
}
@NotNull
@Override
public TokenTypeRemapper getStringLiteralElements() {
return YourLanguageTokens.STRING_LITERALS;
}
@NotNull
@Override
public PsiElement createElement(ASTNode node) {
return YourLanguageTypes.Factory.createElement(node);
}
@Override
public PsiFile createFile(FileViewProvider viewProvider) {
return new YourFile(viewProvider);
}
@NotNull
@Override
public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) {
return SpaceRequirements.MAY;
}
}

Execution

https://plugins.jetbrains.com/docs/intellij/execution.html

可以直接执行普通命令、从右上角执行可以配置运行配置。实际要编程实现时要理解的概念比较多。

PSI

PSI (Program Structure Interface):PSI是IntelliJ用于在内存中表示源代码的接口。例如,一个Java文件将被解析为一个PSI文件,包含了多个PSI类,PSI方法等。通过PSI,你可以很容易地分析和修改代码。

可以通过 View PSI Structure 熟悉 PSI

AI 开发

  • 解释概念
  • 根据 API 给出例子
评论组件加载中……