IDEA插件开发实践
第一步、环境准备
1、IDEA安装Plugin DevKit插件

2、开启IDEA内部模式(使用UI检查器定位代码)

输入idea.is.internal=true开启内部模式,重启后生效。
3、gradle安装配置
gradle下载地址:https://gradle.org/releases/
注意:gradle版本需兼容IDEA的版本,否则构建会报错
版本对应查询:https://www.jetbrains.com/legal/third-party-software/?product=IIU&version=2023.1


解压gradle压缩包到指定路径,然后配置环境变量


idea中配置本地gradle

第二步、项目实战
1、背景
日常开发过程中,我们鼠标双击会选中整个单词,现在想实现按照驼峰选中,效果如图

当然,idea中有开关可以控制,但每次都进行设置不太方便,现在开发一个简单插件,实现当同时按下ctrl+alt+win键时,双击鼠标则是驼峰选中,释放时是单词选中

2、原理
开启IDEA内部模式(使用UI检查器定位代码)后,我们可以通过 ctrl+alt+鼠标左键点击对应菜单,可以获取到点击信息,然后根据关键类信息,到idea源码中查找到对应的代码,在插件开发中通过调用对应的api就可以修改配置信息。

3、新建插件项目

4、编辑build.gradle.kts配置文件内容
plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.7.20"
id("org.jetbrains.intellij") version "1.13.1"
}
group = "com.fufeng"
version = "1.0-SNAPSHOT"
repositories {
// 这里修改为阿里云的仓库地址
// mavenCentral()
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
}
// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
// version.set("2022.2.4")
// type.set("IC") // Target IDE Platform
// 使用localPath设置本地idea的安装路径,这样在运行时会新打开一个程序用于测试插件
localPath.set("D:\\develop Tools\\JetBrains\\IntelliJ IDEA 2023.1")
plugins.set(listOf(/* Plugin Dependencies */))
}
tasks {
// Set the JVM compatibility versions
withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
// 解决编译时中文报错
options.encoding = "UTF-8"
}
// 添加以下内容,解决运行时控制台中文乱码
withType<JavaExec> {
jvmArgs = listOf("-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8")
}
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
patchPluginXml {
sinceBuild.set("222")
untilBuild.set("232.*")
}
signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}
publishPlugin {
token.set(System.getenv("PUBLISH_TOKEN"))
}
}
重新构建配置文件

若出现这个报错,解决方式把项目修改为离线状态即可

打开 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 -->
<id>com.fufeng.SelectByCamel</id>
<!-- Public plugin name should be written in Title Case.
Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-name -->
<!-- 插件名称,大驼峰格式,不能有plugin字符串 -->
<name>SelectByCamel</name>
<!-- A displayed Vendor name or Organization ID displayed on the Plugins Page. -->
<!-- 插件下载页面,作者相关信息 -->
<vendor email="123@qq.com" url="https://www.yourcompany.com">YourCompany1</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[插件功能描述,需要大于40个字符,支持html。。。。。。。。。。。。。。。。。。。。。。。。。。。。]]></description>
<!-- Product and plugin compatibility requirements.
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->
<depends>com.intellij.modules.platform</depends>
<!-- Extension points defined by the plugin.
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
<extensions defaultExtensionNs="com.intellij">
</extensions>
</idea-plugin>
kotlin目录名修改为java。选中kotlin目录,按shift+f6修改目录名为java。不修改后面可能会报错。

5、实现开关切换的两种方式
5.1、创建动作Action
- idea中的action概念可以理解为idea中的任意一个动作,点击了某个按钮,就会执行它绑定的Action类的代码。
- 使用Plugin DevKit 创建一个Action。创建成功之后就会生成一个Action类并在plugin中注册一个action
查询Tools菜单详情:

插件Action


手动切换驼峰选中开关:SelectByCamelAction:
package com.fufeng.selectcamel;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
public class SelectCamelWordsAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
System.out.println("hello plugin");
// TODO: insert action logic here
// 获取到编辑器设置
EditorSettingsExternalizable editorSettingsExternalizable = EditorSettingsExternalizable.getInstance();
// 对之前的状态取反
editorSettingsExternalizable.setCamelWords(!editorSettingsExternalizable.isCamelWords());
}
}
5.2、监听器实现
监听快捷键切换驼峰选中开关:MyKeyListener
在自定义的事件分发器中监听shift+ctrl+win按下,开启驼峰选中。win键抬起,关闭驼峰选中。
package com.fufeng.selectcamel;
import com.intellij.openapi.application.ApplicationActivationListener;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.wm.IdeFrame;
import java.awt.*;
import java.awt.event.KeyEvent;
/**
* @ClassName: MyKeyListener
* @Description:
* @Author: 扶风
* @Date: 2024/8/31 11:13
*/
public class MyKeyListener implements ApplicationActivationListener {
private final KeyEventDispatcher dispatcher = new MyKeyEventDispatcher();
@Override
public void applicationActivated(@NotNull IdeFrame ideFrame) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
}
@Override
public void applicationDeactivated(@NotNull IdeFrame ideFrame) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);
}
private static class MyKeyEventDispatcher implements KeyEventDispatcher {
// 分发器逻辑
private boolean shiftPressed = false;
private boolean ctrlPressed = false;
private boolean winPressed = false;
private final EditorSettingsExternalizable editorSettingsExternalizable = EditorSettingsExternalizable.getInstance();
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
int keyCode = e.getKeyCode();
int id = e.getID();
if (id == KeyEvent.KEY_PRESSED) {
switch (keyCode) {
case KeyEvent.VK_SHIFT:
shiftPressed = true;
break;
case KeyEvent.VK_CONTROL:
ctrlPressed = true;
break;
case KeyEvent.VK_WINDOWS:
winPressed = true;
break;
}
if (shiftPressed && ctrlPressed && winPressed) {
// 开启驼峰选中
System.out.println("Shift + Ctrl + Win 按下!");
editorSettingsExternalizable.setCamelWords(true);
}
} else if (id == KeyEvent.KEY_RELEASED) {
switch (keyCode) {
case KeyEvent.VK_WINDOWS:
if (shiftPressed && ctrlPressed) {
// 关闭驼峰选中
System.out.println("Win 键抬起!");
editorSettingsExternalizable.setCamelWords(false);
}
winPressed = false;
break;
case KeyEvent.VK_SHIFT:
shiftPressed = false;
break;
case KeyEvent.VK_CONTROL:
ctrlPressed = false;
break;
}
}
return false; // 继续分发事件
}
}
}
在plugin.xml中注册应用激活时监听,并绑定到我们的监听器中。
<applicationListeners>
<listener class="com.fufeng.selectcamel.MyKeyListener" topic="com.intellij.openapi.application.ApplicationActivationListener"/>
</applicationListeners>
至此开发完成!
第三步、打包导入

构建完成后会生成一个jar包,在插件管理里面从本地导入这个jar即可使用

idea版本兼容性问题
- idea-version参考: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html#idea-plugin__idea-version
- 内部版本号映射参考:https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html#earlier-versions
- 修改build.gradle.kts中的patchPluginXml,它用来不是兼容的idea版本。该值会覆盖plugin.xml中的idea-versin标签,所有可以直接把兼容版本写在这里。
patchPluginXml {
// 最低版本
sinceBuild.set("232")
// 最高版本
untilBuild.set("242.*")
}
<idea-version since-build="232" until-build="242.*"/>
jetbrains.com/docs/intellij/build-number-ranges.html#earlier-versions
- 修改build.gradle.kts中的patchPluginXml,它用来不是兼容的idea版本。该值会覆盖plugin.xml中的idea-versin标签,所有可以直接把兼容版本写在这里。
patchPluginXml {
// 最低版本
sinceBuild.set("232")
// 最高版本
untilBuild.set("242.*")
}
<idea-version since-build="232" until-build="242.*"/>
- 要做到多版本兼容,就是要将最低版本设置的尽可能的小,但是同时需要你设置的版本有你插件当前使用的api。例如
applicationListeners就在193.0之后发布,我的最低版本就只能设置193.0。最大版本不设置。
更多推荐



所有评论(0)