背景介绍
痛点:在idea开发过程中,希望按需驼峰选中文本。现在默认是一整个单词选中,只有在设置–>智能按键 中开启了
使用"CamelHumps单词"
时能够驼峰选中。但是这种情况比较粗暴,直接全局开启了。但是在日常开发中,其实选中大部分是整个单词一起选中。只有少部分情况是按照驼峰选中。
所以就需要一块插件,能够快捷开关驼峰选中的能力,仅在需要的时候开启。
安装Plugin DevKit插件
Idea 2023.3 以下版本可以不用安装当前插件。idea自带。2023.3版本及之后的版本没有当前查询,需要自己安装。
插件商店搜索
Plugin DevKit
用于安装插件,安装完成之后建议先重启一下,不然可能开发工具可能出不来。
开启IDEA内部模式(使用UI检查器定位代码)
主菜单栏–>帮助(Help)–>编辑自定义属性
输入
idea.is.internal=true
开启内部模式,重启后生效。参考链接 https://plugins.jetbrains.com/docs/intellij/enabling-internal.html后面介绍如何使用UI检查器来定位代码位置
新建插件项目
新建项目选择Idea插件(如果没有
Plugin DevKit
插件,这里就没有当前选项)。
同时注意jdk版本需要和idea对应。参考:https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html#creating-a-plugin-with-new-project-wizard
修改Gradle相关配置
取消gradle构建
先取消默认的gradle构建。先修改一些配置在重新构建。
修改依赖远程仓库地址
修改
build.gradle.kts
中的repositories,注释中央仓库(mavenCentral)。配置阿里云地址。
repositories { // mavenCentral() maven { url = uri("https://maven.aliyun.com/repository/public") }}
如果文件名不是kts结尾,而是gradle结尾,配置可能有些区别。
修改使用本地Idea调试
注释intellij中的version和type(如果指定,需要下载),使用本地安装的idea进行调试。使用
localPath
设置本地idea的安装路径。参考:https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension
intellij { localPath.set("D:\\Program Files\\JetBrains\\IntelliJ IDEA 2024.1.2") // version.set("2023.2.6") // type.set("IC") // Target IDE Platform plugins.set(listOf(/* Plugin Dependencies */))}
重新加载Gradle变更
点击Gradle图标重新加载变更。
等待构建完成,初次可能比较慢,需要下载依赖等。构建完成之后,文件也就有高亮显示了。
其他build.gradle相关配置说明
https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#ide-configuration
plugin.xml解读
参考:https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html#configuration-structure-overviewplugin.xml文件可以理解是当前插件的相关配置。是插件开发中非常重要的一个文件。
构建完成之后,它会报错,是因为不能使用默认的模版字符。我们改掉就可以了。
防止报错
kotlin
目录名修改为
java
。选中kotlin目录,按shift+f6修改目录名为java。不修改后面可能会报错。
创建Action
idea中的action概念可以理解为idea中的任意一个动作,点击了某个按钮,就会执行它绑定的Action类的代码。使用Plugin DevKit 创建一个Action。
填写actionId,类名,功能名称,功能描述,添加到目标位置。
创建成功之后就会生成一个Action类和在plugin中注册一个action,表说明他的位置。
运行插件
点击gradle运行idea插件,它会重新启动一个idea环境,来运行idea插件。
第一次运行可能较慢,需要等待一会儿。运行成功之后,在工具栏中显示了我们的插件Action。
点击插件Action,后台也打印了相应的结果。
找不到你的插件注册的Action,并且控制台报错ClassNotFoundException?
需要将上面说的kotlin目录修改为java。
控制台中文乱码,报错?
修改
build.gradle.kts
,解决编译中文报错和控制台中文乱码问题。
tasks { // Set the JVM compatibility versions 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") } ...}
定位Action插入位置
我是需要将Action插入到主菜单栏中的Tools菜单,要如何定位呢。这就只要使用我们之前说的内部工具,ui检查器了。开启内部模式之后,按
ctrl+alt+鼠标左键
点击ui,就能显示当前ui的详细信息。找到他的
Group Id
然后创建action时搜索选择就好了。
定位Idea相关代码
在前面提到,idea设置中的智能按键有提供全局的驼峰选中能力,开启之后的就能够实现驼峰选中了。我们插件的逻辑也很简单,就是在编辑器中能够快捷开启这个开关。那我们要如何实现快捷开关呢,其实也很简单,我们只需要去看idea是怎么实现的就好了。
使用ui检查器定位智能按键逻辑
在设置中使用ui检查器定位智能按键的配置类。
打开idea源代码,搜索类
EditorSmartKeysConfigurable
然后搜索关键字camel,定位到配置,可以看到当前配置项有一个获取配置的方法,和更新配置的方法。然后查看这个
editorSettings
的来源。可以看到
editorSettings
的数据源是
EditorSettingsExternalizable.getInstance()
那这样就可以在我的项目中使用当前类的方法去设置快捷开关了。
编写插件逻辑(驼峰选中快捷开关)
在我们的Action中获取到刚刚的编辑器设置,然后对配置项
CamelWords
的状态取反就可以了。
public class SelectCamelWordsAction extends AnAction { @Override public void actionPerformed(AnActionEvent e) { // 获取到编辑器设置 EditorSettingsExternalizable editorSettingsExternalizable = EditorSettingsExternalizable.getInstance(); // 对之前的状态取反 editorSettingsExternalizable.setCamelWords(!editorSettingsExternalizable.isCamelWords()); }}
运行插件,通过ToolMenu中的
SelectCamelWords
就能够快捷开启关闭驼峰选中的功能。但是这还是很麻烦啊,不能够快捷启动。接下来就要使用监听器来监听按键实现对应的快捷启动。
使用监听器监听键盘按键
参考文档:https://plugins.jetbrains.com/docs/intellij/plugin-listeners.html#defining-application-level-listeners在plugin.xml中注册应用激活时监听,并绑定到我们的监听器中。
<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下
本地安装验证
打开插件仓库,选择本地安装,找到打包之后的jar
安装成功,确认,然后测试插件
发布插件
进入jetbrains插件开发平台:https://plugins.jetbrains.com/developers/intellij-platform点击登录,或者注册账号
点击Upload Plugin上传插件,上传插件jar包,填写相关信息,点击upload Plugin.
上传成功,等待审核。
兼容不同的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.*"/>
要做到多版本兼容,就是要将最低版本设置的尽可能的小,但是同时需要你设置的版本有你插件当前使用的api。例如
applicationListeners
就在193.0之后发布,我的最低版本就只能设置193.0。最大版本不设置。
发布前jetbrains会校验当前插件的兼容性,我这边就是校验通过,显示可以使用的版本。
参考文档
Jetbrains Idea插件开发文档代码地址:https://github.com/yangfeng20/selected-camel-words整体流程文档:2024idea插件开发指南