背景介绍
- 痛点:在idea开发过程中,希望按需驼峰选中文本。
- 现在默认是一整个单词选中,只有在设置–>智能按键 中开启了
使用"CamelHumps单词"
时能够驼峰选中。但是这种情况比较粗暴,直接全局开启了。但是在日常开发中,其实选中大部分是整个单词一起选中。只有少部分情况是按照驼峰选中。
![image.png](https://img-blog.csdnimg.cn/img_convert/75ca49abad613e669e557f05a30f9b39.png)
- 所以就需要一块插件,能够快捷开关驼峰选中的能力,仅在需要的时候开启。
安装Plugin DevKit插件
- Idea 2023.3 以下版本可以不用安装当前插件。idea自带。2023.3版本及之后的版本没有当前查询,需要自己安装。
![image.png](https://img-blog.csdnimg.cn/img_convert/df67b4035b4b6ece5cda394cbb0cae05.png)
- 插件商店搜索
Plugin DevKit
用于安装插件,安装完成之后建议先重启一下,不然可能开发工具可能出不来。
![image.png](https://img-blog.csdnimg.cn/img_convert/3a862b2a251faabdb767e1182c581211.png)
开启IDEA内部模式(使用UI检查器定位代码)
![image.png](https://img-blog.csdnimg.cn/img_convert/499afa4818a9cfa7b370eaff18052192.png)
新建插件项目
- 新建项目选择Idea插件(如果没有
Plugin DevKit
插件,这里就没有当前选项)。
![image.png](https://img-blog.csdnimg.cn/img_convert/61948269990eccc74910496cdbaa0adc.png)
![image.png](https://img-blog.csdnimg.cn/img_convert/a4136b6153e62856eb3a9e7082da4392.png)
修改Gradle相关配置
取消gradle构建
- 先取消默认的gradle构建。先修改一些配置在重新构建。
修改依赖远程仓库地址
- 修改
build.gradle.kts
中的repositories,注释中央仓库(mavenCentral)。配置阿里云地址。
repositories {
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
}
- 如果文件名不是kts结尾,而是gradle结尾,配置可能有些区别。
修改使用本地Idea调试
intellij {
localPath.set("D:\\Program Files\\JetBrains\\IntelliJ IDEA 2024.1.2")
plugins.set(listOf())
}
![image.png](https://img-blog.csdnimg.cn/img_convert/2a783bf27f1a66fbfeb98d23a24fd656.png)
重新加载Gradle变更
![image.png](https://img-blog.csdnimg.cn/img_convert/bb90de129f82e57625b4e735eac1280c.png)
- 等待构建完成,初次可能比较慢,需要下载依赖等。构建完成之后,文件也就有高亮显示了。
![image.png](https://img-blog.csdnimg.cn/img_convert/5a016b425fe9e41a7cb5c4c8ac704e02.png)
其他build.gradle相关配置说明
plugin.xml解读
![image.png](https://img-blog.csdnimg.cn/img_convert/30260bc98b6b9eabdef1666f4e5d1ffb.png)
- 构建完成之后,它会报错,是因为不能使用默认的模版字符。我们改掉就可以了。
![image.png](https://img-blog.csdnimg.cn/img_convert/a104ec6eb20beee299adb322c6dbee2d.png)
防止报错
kotlin
目录名修改为java
。选中kotlin目录,按shift+f6修改目录名为java。不修改后面可能会报错。
![image.png](https://img-blog.csdnimg.cn/img_convert/ebdf80d5a54acea4c4431127f87c9331.png)
创建Action
- idea中的action概念可以理解为idea中的任意一个动作,点击了某个按钮,就会执行它绑定的Action类的代码。
- 使用Plugin DevKit 创建一个Action。
![image.png](https://img-blog.csdnimg.cn/img_convert/061bb780cbb4793f48ff58197a65158c.png)
- 填写actionId,类名,功能名称,功能描述,添加到目标位置。
![image.png](https://img-blog.csdnimg.cn/img_convert/9d6835453086def73047941379a86f16.png)
- 创建成功之后就会生成一个Action类和在plugin中注册一个action,表说明他的位置。
![image.png](https://img-blog.csdnimg.cn/img_convert/e68302e39dc7579d6f24908026de1f0d.png)
运行插件
- 点击gradle运行idea插件,它会重新启动一个idea环境,来运行idea插件。
![image.png](https://img-blog.csdnimg.cn/img_convert/665d4be98958f3658599c8e0e89e20ef.png)
- 第一次运行可能较慢,需要等待一会儿。运行成功之后,在工具栏中显示了我们的插件Action。
![image.png](https://img-blog.csdnimg.cn/img_convert/b0328e1c848bd5a9f0933ba49447074a.png)
![image.png](https://img-blog.csdnimg.cn/img_convert/3f3ed4625b924ad4b621757e22e95c20.png)
找不到你的插件注册的Action,并且控制台报错ClassNotFoundException?
控制台中文乱码,报错?
- 修改
build.gradle.kts
,解决编译中文报错和控制台中文乱码问题。
tasks {
withType<JavaCompile> {
sourceCompatibility = "17"
targetCompatibility = "17"
options.encoding = "UTF-8"
}
withType<JavaExec> {
jvmArgs = listOf("-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8")
}
...
}
![image.png](https://img-blog.csdnimg.cn/img_convert/b7118ee9eaee12ffa554990f0a6faabc.png)
定位Action插入位置
- 我是需要将Action插入到主菜单栏中的Tools菜单,要如何定位呢。这就只要使用我们之前说的内部工具,ui检查器了。
- 开启内部模式之后,按
ctrl+alt+鼠标左键
点击ui,就能显示当前ui的详细信息。找到他的Group Id
然后创建action时搜索选择就好了。
![image.png](https://img-blog.csdnimg.cn/img_convert/43b3b54a23ad0024c4eac63fbe609eff.png)
定位Idea相关代码
- 在前面提到,idea设置中的智能按键有提供全局的驼峰选中能力,开启之后的就能够实现驼峰选中了。
- 我们插件的逻辑也很简单,就是在编辑器中能够快捷开启这个开关。
- 那我们要如何实现快捷开关呢,其实也很简单,我们只需要去看idea是怎么实现的就好了。
使用ui检查器定位智能按键逻辑
![image.png](https://img-blog.csdnimg.cn/img_convert/01407ab7189b4cf18773e293aa58aa0e.png)
- 打开idea源代码,搜索类
EditorSmartKeysConfigurable
![image.png](https://img-blog.csdnimg.cn/img_convert/01fb6d443f099c3fe727e7076c307044.png)
- 然后搜索关键字camel,定位到配置,可以看到当前配置项有一个获取配置的方法,和更新配置的方法。然后查看这个
editorSettings
的来源。可以看到editorSettings
的数据源是EditorSettingsExternalizable.getInstance()
![image.png](https://img-blog.csdnimg.cn/img_convert/0d5181461f7dafd56454000b8f215fd5.png)
- 那这样就可以在我的项目中使用当前类的方法去设置快捷开关了。
编写插件逻辑(驼峰选中快捷开关)
- 在我们的Action中获取到刚刚的编辑器设置,然后对配置项
CamelWords
的状态取反就可以了。
public class SelectCamelWordsAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
EditorSettingsExternalizable editorSettingsExternalizable = EditorSettingsExternalizable.getInstance();
editorSettingsExternalizable.setCamelWords(!editorSettingsExternalizable.isCamelWords());
}
}
- 运行插件,通过ToolMenu中的
SelectCamelWords
就能够快捷开启关闭驼峰选中的功能。 - 但是这还是很麻烦啊,不能够快捷启动。接下来就要使用监听器来监听按键实现对应的快捷启动。
使用监听器监听键盘按键
<applicationListeners>
<listener class="com.maple.plugindemo.MyKeyListener" topic="com.intellij.openapi.application.ApplicationActivationListener"/>
</applicationListeners>
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 {
}
}
- 在自定义的事件分发器中监听shift+ctrl+win按下,开启驼峰选中。win键抬起,关闭驼峰选中。
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;
}
}
- 至此,插件逻辑就已经大功告成了。由于我没有mac,不清楚mac的快捷键,就没有适配mac快捷键。大家也可以去我的仓库提交pr。
打包插件
- 通过gradle的task打包插件。构建jar包,最终会输出到build–>libs下
![image.png](https://img-blog.csdnimg.cn/img_convert/25cd77f72aeeb51cf5b0ff3c2202a5d5.png)
本地安装验证
![image.png](https://img-blog.csdnimg.cn/img_convert/4c5d89285b0f2191eb38bb3a8d61c74a.png)
![image.png](https://img-blog.csdnimg.cn/img_convert/0ce92bd111cb7a690b1bc82a1de35c55.png)
发布插件
![image.png](https://img-blog.csdnimg.cn/img_convert/4bfd9bd0f163a71a2b116ee88df81b7f.png)
- 点击Upload Plugin上传插件,上传插件jar包,填写相关信息,点击upload Plugin.
![image.png](https://img-blog.csdnimg.cn/img_convert/a26317ee5247f8eb784c8dedaac33d71.png)
![image.png](https://img-blog.csdnimg.cn/img_convert/8c10a2aedc7605a2b32c7929e8e0899c.png)
兼容不同的idea版本
patchPluginXml {
sinceBuild.set("232")
untilBuild.set("242.*")
}
<idea-version since-build="232" until-build="242.*"/>
- 要做到多版本兼容,就是要将最低版本设置的尽可能的小,但是同时需要你设置的版本有你插件当前使用的api。例如
applicationListeners
就在193.0之后发布,我的最低版本就只能设置193.0。最大版本不设置。
![image.png](https://img-blog.csdnimg.cn/img_convert/336291312a6eb2b29f81eddd315b4b1a.png)
- 发布前jetbrains会校验当前插件的兼容性,我这边就是校验通过,显示可以使用的版本。
![image.png](https://img-blog.csdnimg.cn/img_convert/29c91fe444edd0149b2424ece0b58ce2.png)
参考文档