IntelliJ IDE 插件开发 | (六)内部模式的使用

系列文章

  • IntelliJ IDE 插件开发 |(一)快速入门
  • IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化
  • IntelliJ IDE 插件开发 |(三)消息通知与事件监听
  • IntelliJ IDE 插件开发 |(四)来查收你的 IDEA 使用报告吧
  • IntelliJ IDE 插件开发 |(五)VFS 与编辑器
  • IntelliJ IDE 插件开发 |(六)内部模式的使用

前言

前几篇文章主要介绍了 IntelliJ IDE 插件开发的基础知识和实战内容,作为后续内容的过渡,本文会讲解前几篇文章中提到过的内部模式的使用。内部模式通过菜单形式提供了一系列实用工具,能够帮助初学 IntelliJ IDE 插件的同学极大提升开发效率,由于内部模式提供的工具过多,本文则会挑选几个比较实用的工具进行介绍。

启用内部模式

首先在帮助菜单中找到Edit Custom Properties...

image-20240205104923509

然后加入如下配置:

idea.is.internal=true

保存后重启 IDEA,就可以在 Tools 菜单中发现多了一个 Internal Actions:

image-20240205105443548

下面介绍的工具都是基于 Internal Actions 下的,按照实用性,顺序会有所差异。

UI Debugger

在 Internal Actions 下找到 UI Debugger 菜单,点击后会出现以下弹框:

image-20240205134500788

可以发现这里有 Playback 和 Actions 两个标签页,其中 Playback 用于执行给定的脚本,例如以下脚本会自动执行 CTRL + F 显示搜索框,然后先开启大写,最后输入 HELLO:

%[control F]
%type 20:16;72:16;69:16;76:16;76:16;79:16

第一行用于执行 CTRL + F,第二行中的所有的数字都对应键盘编码(不是ASCII码),例如 20代表开启大写,72代表字符 h,所有的输入用 ; 进行分割,: 前表示字符编码,: 后表示控制字符的编码。所有支持的命令和语法规则可以参考源码,由于这个功能在插件开发中用处不大,这里就不展开介绍了。

效果如下:

动画

上面关于 Playback 的使用了解即可,这里主要讲解一下 Actions 的使用,通过前面的文章我们可以知道,在 IntelliJ IDE 中各种操作(不管是点击菜单项还是通过快捷键)都有相对应的 Action,而 Actions 这个菜单就是用于帮助我们查看每个操作所对应的 Action 类名和 id(如果存在),而知道了 Action 的 id,我们就可以调用相应的操作,这样就实现了对 IDEA 自带功能的使用(也可以直接根据 Action 的类名去找相应的文件去看实现方式),下面以一个具体的例子去介绍使用方式:

例如我们想实现一个根据 Kotlin 类定位到对应的 class 文件并打开的功能,我们首先通过 UI Debugger 去查看 IDEA 定位文件并打开对应的 Action:

动画

这里可以看到该操作对应的 ActionId 为 SelectInProjectView,然后我们只需要实现根据 Kotlin 文件名找到同名的 class 文件的逻辑即可,最终实现方式如下:

class FindClassAction: AnAction() {
    
    override fun actionPerformed(e: AnActionEvent) {
        val project = e.project ?: return
        val file = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)?.get(0) ?: return
        val kotlinSuffix = ".kt"
        val classSuffix = ".class"
        
        if (!file.name.endsWith(kotlinSuffix)) {
            Utils.info("请选择 Kotlin 文件")
            return
        }
        // 查找 class 文件路径
        val className = file.name.replace(kotlinSuffix, classSuffix)
        val fileList = findFiles(project.basePath.toString(), className, setOf(".idea"))
        if (fileList.isEmpty()) {
            Utils.info("未找到对应类文件")
            return
        }
        val classFile = fileList[0]
        LocalFileSystem.getInstance().findFileByIoFile(classFile)
            ?.let {
                // 打开文件
                FileEditorManager.getInstance(project).openFile(it, true)
                // 定位文件
                ActionManager.getInstance().getAction("SelectInProjectView").actionPerformed(e)
            }
    }
    
    // 在指定路径递归查询某个文件, 同时排除指定的路径
    private fun findFiles(rootDir: String, targetFileName: String, excludedDirs: Set<String> = emptySet()): List<File> { 
        val result = mutableListOf<File>()
        fun searchFiles(directory: File) {
            val files = directory.listFiles() ?: return
            for (file in files) {
                if (file.isDirectory) {
                    if (file.name !in excludedDirs) {
                        searchFiles(file)
                    }
                } else {
                    if (file.name == targetFileName && file.path.contains("classes")) {
                        result.add(file)
                    }
                }
            }
        }
        searchFiles(File(rootDir))
        return result
    }
}

假如我们想知道格式化代码的实现方式,也是先去获取对应的 action:

动画

这里可以看到对应的 Action 类路径是 com.intellij.codeInsight.actions.ReformatCodeAction,这样我们就可以去找对应的源代码,查看其实现方式:

image-20240205150729549

通过这种方式,我们就可以在对 IDEA 自带功能有某些定制化需求的时候,通过继承原有类,然后重写某些逻辑去实现我们的需求。

UI Inspector

通过 UI -> UI Inspector 可以找到该菜单,不过我们在实际使用的时候并不需要从菜单里点击,只需要选择 IDEA 界面中某个 UI 组件,然后使用 CTRL + ALT + 点击鼠标左键即可显示该组件的 UI 信息,如下所示:

动画

这里查看的是 debug 按钮所对应的布局信息,具体如下:

image-20240205152021642

可以发现这里也有 Action ID 和 Action Class 属性,因此上面想查找定位按钮的 Action ID 也可以通过这种方式进行查看:

image-20240205152549992

可以看到这里的 id 和我们通过 UI Debugger 获取的内容一样,当然除了 Action 相关的信息,根据查看的组件类型不同,所对应的属性也会有区别(例如设置页面和这里的按钮属性就有些不同),具体的不同可以查看官网。

LaF Defaults

通过 UI -> LaF Defaults 可以找到该菜单,点击后会出现以下弹框:

image-20240205154635942

这里展示了 IDEA 中所有的颜色和外观设置(例如各种间距),我们可以点击对应的 Value 值进行修改,同时修改的设置会立即生效,因此如果有开发主题类插件需求的时候,我们就可以很方便地先通过该工具获取实时的预览效果,例如我们去修改按钮的圆角大小为 0:

image-20240205155316347

修改完就可以发现按钮的圆角消失了:

image-20240205155349887

或者是修改按钮的背景色:

image-20240205155719598

点击 OK 后会出现以下效果:

image-20240205155754512

Kotlin UI DSL

image-20240205155852946

在前几篇文章中我们有简单地使用 Kotlin UI DSL 去实现一些 UI 界面,如果是初学者对相关的使用方式不熟悉,就可以通过该菜单去查看一些组件地使用用例,点击View source就可以查看相应的源码:

image-20240205160104843

总结

本文主要讲解了内部模式中几个比较实用的工具,希望能给大家提供一些帮助,如果你发现了一些插件开发中的小技巧,也欢迎一起交流讨论~~~

题外话

从下篇文章开始会逐步介绍 PSI、自定义语言以及一些常用插件的开发思路和实现方式,敬请期待,同时也祝各位新年快乐,在新的一年里,事业有成,身体健康,家庭幸福,万事如意!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/373398.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024.1.26力扣每日一题——边权重均等查询

2024.1.26 题目来源我的题解方法一 使用dfs对每一组查询都求最近公共祖先&#xff08;会超时&#xff0c;通不过&#xff09;方法二 不需要构建图&#xff0c;直接在原始数组上进行求最大公共祖先的操作。 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2846 我的题解 …

【数据分享】1929-2023年全球站点的逐年平均能见度(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 之前我们分享过1929-2023年全球气象站点的逐年平均气温数据、逐年最高气温数据…

关于旋转编码器(EC11)的使用(判断旋转方向,按键处理)

关于旋转编码器(EC11)的使用&#xff08;判断旋转方向&#xff0c;按键处理&#xff09; 文章目录 关于旋转编码器(EC11)的使用&#xff08;判断旋转方向&#xff0c;按键处理&#xff09;零. 前言一. 注意事项二. 本文所述旋转编码器的旋转控制逻辑三. 旋转编码器判断代码&…

什么是S参数

S参数是网络参数&#xff0c;定义了反射波和入射波之间的关系&#xff0c;给定频率的S参数矩阵指定端口反射波b的矢量相对于端口入射波a的矢量&#xff0c;如下所示&#xff1a; bS∙a 在此基础上&#xff0c;如下图所示&#xff0c;为一个常见的双端口网络拓扑图&#xff1a;…

sqli.labs靶场(54-65关)

54、第五十四关 提示尝试是十次后数据库就重置&#xff0c;那我们尝试union 原来是单引号闭合 id-1 union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schemadatabase()) -- 数据库&#xff1a;challenges&#xff0c…

visio对任意形状进行任意角度旋转调整

在使用VISIO进行绘图时&#xff0c;可能需要对任意的形状进行旋转&#xff0c;让其达到一致。如下图所示&#xff0c;灰色矩形与直线要保持一致&#xff0c;而实际在绘制矩形时&#xff0c;成水平朝向。需要对矩形进行调整&#xff0c;将其与直线倾斜保持一致。具体步骤如下&am…

(已解决)vueQQ邮箱注册发送验证码前端设计,如何发送验证码设计倒计时

我们之前已经通过前端测试成功完成qq邮箱动态验证码发送&#xff08;未使用redis&#xff0c;我准备自己了解完后&#xff0c;后期有时间补上&#xff09; 衔接文章&#xff1a; 1&#xff1a; spingboot 后端发送QQ邮箱验证码 2&#xff1a; 这段代码建设图形化界面 <di…

双向链表的插入、删除、按位置增删改查、栈和队列区别、什么是内存泄漏

2024年2月4日 1.请编程实现双向链表的头插&#xff0c;头删、尾插、尾删 头文件&#xff1a; #ifndef __HEAD_H__ #define __HEAD_H__ #include<stdio.h> #include<stdlib.h> #include<string.h> typedef int datatype; enum{FALSE-1,SUCCSE}; typedef str…

RabbitMQ-2.SpringAMQP

SpringAMQP 2.SpringAMQP2.1.创建Demo工程2.2.快速入门2.1.1.消息发送2.1.2.消息接收2.1.3.测试 2.3.WorkQueues模型2.2.1.消息发送2.2.2.消息接收2.2.3.测试2.2.4.能者多劳2.2.5.总结 2.4.交换机类型2.5.Fanout交换机2.5.1.声明队列和交换机2.5.2.消息发送2.5.3.消息接收2.5.4…

文件夹正在使用无法删除(重命名)解决办法

1、问题描述 相信都遇到文件夹无法删除&#xff0c;或者无法重命名的情况。如果将文件夹正在使用的文件都已经关闭后&#xff0c;文件夹仍旧无法删除或重命名。 这个时候大概率是有隐藏的进程没有关闭&#xff0c;可以重启电脑&#xff0c;或者采用下面的方式关闭对应文件夹的…

小白水平理解面试经典题目LeetCode 20. Valid Parentheses【栈】

20.有效括号 小白渣翻译 给定一个仅包含字符 ‘(’ 、 ‘)’ 、 ‘{’ 、 ‘}’ 、 ‘[’ 和 ‘]’ &#xff0c;判断输入字符串是否有效。 输入字符串在以下情况下有效&#xff1a; 左括号必须由相同类型的括号封闭。 左括号必须按正确的顺序关闭。 每个右括号都有一个对…

vscode 突然连接不上服务器了(2024年版本 自动更新从1.85-1.86)

vscode日志 ll192.168.103.5s password:]0;C:\WINDOWS\System32\cmd.exe [17:09:16.886] Got some output, clearing connection timeout [17:09:16.887] Showing password prompt [17:09:19.688] Got password response [17:09:19.688] "install" wrote data to te…

uniapp踩坑之项目:简易版不同角色显示不一样的tabbar和页面

1. pages下创建三个不同用户身份的“我的”页面。 显示第几个tabbar&#xff0c;0是管理员 1是财务 2是司机 2. 在uni_modules文件夹创建底部导航cc-myTabbar文件夹&#xff0c;在cc-myTabbar文件夹创建components文件夹&#xff0c;在components文件夹创建cc-myTabbar.vue组件…

【机器学习】机器学习简单入门

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;matplotlib &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

【高质量精品】2024美赛C题高质量成品论文分享获取入口(后续会更新)

一定要点击文末的卡片&#xff0c;进入后&#xff0c;即可获取完整论文&#xff01;&#xff01; 首先&#xff0c;我们需要对缺失的 speed_mph 进行插补。缺失值处理是数据预处理的 重要环节之一。可以采用均值、中位数或者根据其他相关特征进行预测的方法来 填补缺失值。在这…

Packet Tracer - Configure IOS Intrusion Prevention System (IPS) Using the CLI

Packet Tracer - 使用CLI配置IOS入侵防御系统&#xff08;IPS&#xff09; 地址表 目标 启用IOS入侵防御系统&#xff08;IPS&#xff09;。 配置日志记录功能。 修改IPS签名规则。 验证IPS配置。 背景/场景 您的任务是在R1上启用IPS&#xff0c;扫描进入192.168.1.0网络…

Unity3d Cinemachine篇(完)— TargetGroup

文章目录 前言使用TargetGroup追随多个模型1. 创建二个游戏物体2. 创建TargetGroup相机3. 设置相机4. 完成 前言 上一期我们简单的使用了ClearShot相机&#xff0c;这次我们来使用一下TargetGroup 使用TargetGroup追随多个模型 1. 创建二个游戏物体 2. 创建TargetGroup相机 3…

刚刚晋升为管理者,还不会如何管理团队?你要重点关注这9个策略

管理团队需要明确团队目标、提前要求承诺、明确组织架构、团队高效协作、洞察员工、引入敏捷、执行可视化、及时反馈和复盘优化。 这样管理团队可以极大提高团队组织能力。团队组织能力强大的话&#xff0c;团队成员是可以实现自我管理的&#xff0c;会自我驱动去完成目标和执…

2024.2.5 vscode连不上虚拟机,始终waiting for server log

昨天还好好的&#xff0c;吃着火锅&#xff0c;做着毕设&#xff0c;突然就被vscode给劫了。 起初&#xff0c;哥们跟着网上教程有模有样地删除了安装包缓存&#xff0c;还删除了.vscode-server&#xff0c;发现没卵用&#xff0c;之前都是搜那个弹窗报错。 后来发现原来是vsco…

SpringBoot 全局异常处理

介绍 如果代码没有做异常处理&#xff0c;就会报框架错误&#xff0c;而这种格式不符合REST风格&#xff0c;也可以在每一个接口添加 try{ } catch { } 捕获异常&#xff0c;但是会非常的繁琐&#xff0c;这时候可以使用全局异常处理。 统一响应类 Data NoArgsConstructor …