怎样让百度搜不到自己的网站/品牌广告
系列文章
- IntelliJ IDE 插件开发 |(一)快速入门
- IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化
- IntelliJ IDE 插件开发 |(三)消息通知与事件监听
- IntelliJ IDE 插件开发 |(四)来查收你的 IDEA 使用报告吧
- IntelliJ IDE 插件开发 |(五)VFS 与编辑器
- IntelliJ IDE 插件开发 |(六)内部模式的使用
- IntelliJ IDE 插件开发 |(七)PSI 入门及实战(实现 MyBatis 插件的跳转功能)
前言
所谓 PSI(Program Structure Interface),直译过来是程序结构接口,其实就是 IntelliJ 平台给我们提供用来解析代码文件,简化对各类编程语言(Java、Kotlin、XML)操作的接口。大部分针对编程语言或者框架的便利插件其实就与此相关,本文则会先介绍关于 PSI 的一些基础知识,然后再以一些 Mybatis 插件提供的 Java 方法 和 Mapper XML 文件互相跳转的例子来说明 PSI 的实际应用,最终实现效果如下图,本文涉及的到的完整代码文件也已上传到GitHub。
PSI file(PSI 文件)
在本系列的第五篇文章中介绍了Virtual Files 和 Documents 用于处理文件的 API,而 PSI file 也是用于处理文件的 API,不过也有一些不同,具体如下:
类别 | 层面 | 范围 |
---|---|---|
VF、Document | 文本文件 | 应用级 |
PSI | 编程语言语法树 | 项目级 |
获取文件的 PSI file 对象的方式主要有以下几种(来自官网):
Context | API |
---|---|
Action | AnActionEvent.getData(CommonDataKeys.PSI_FILE) |
Document | PsiDocumentManager.getPsiFile() |
PSI Element | PsiElement.getContainingFile() |
Virtual File | PsiManager.findFile() , PsiUtilCore.toPsiFiles() |
File Name | FilenameIndex.getVirtualFilesByName() |
最后一种方式
FilenameIndex.getVirtualFilesByName()
得到的结果是Virtual File 对象,需要再通过倒数第二行的方式再获取到对应的 PIS file 对象。
不过通过以上方式获取到的 PsiFile 只是顶层的接口,针对不同的编程语言,我们会使用相应的实现类。例如 Java 是 PsiJavaFile,XML 是 XMLFile。
下面通过实际使用来进行介绍,首先是 PsiJavaFile,当然在使用之前需要确保build.gradle
文件中将 Java 添加到插件配置中(XML 内置无需添加):
intellij {// 用到的插件plugins.set(listOf("com.intellij.java"))
}
然后在plugin.xml
中加入以下配置:
<depends>com.intellij.modules.java</depends>
如果是 XML 则需要添加如下配置:
<depends>com.intellij.modules.xml</depends>
经过以上配置后,我们就可以使用 PsiJavaFile 和 XMLFile 的相关 API 了。
例如以下代码可以得到 java 文件的所属表名和类中 所有的方法名,然后展示出来:
class PsiJavaAction: AnAction() {override fun actionPerformed(e: AnActionEvent) {// 获取 PsiFile 对象val psiFile = e.getData(CommonDataKeys.PSI_FILE)// 转换为 PsiJavaFileval psiJavaFile = psiFile as PsiJavaFile// 获取类所属包Utils.info("当前类所属包:${psiJavaFile.packageName}")// 遍历获取所有的方法名psiJavaFile.accept(object: JavaRecursiveElementVisitor() {override fun visitMethod(method: PsiMethod) {Utils.info("查找到方法:${method.name}")}})}}
在以上代码中需要注意psiJavaFile.accept()
方法,其中 accept 方法是 PsiFile 所提供的方法,方法签名为void accept(@NotNull PsiElementVisitor visitor)
,用于遍历 PSI 文件中的各类元素,可以看到上面我们在传参时传递的是JavaRecursiveElementVisitor
,这是用于遍历 Java 中各类元素(字段、方法、注解等)的一个实现类,只需要重写对应的方法即可,在上面我们重写了visitMethod
方法,其实内部提供了很多方法,大家可以自行尝试,通过方法名也可以看到这里还支持遍历 break 语句,断言语句等等:
下面再说明如何遍历 XML 文件中的元素:
class PsiXMLAction: AnAction() {override fun actionPerformed(e: AnActionEvent) {// 获取 PsiFile 对象val psiFile = e.getData(CommonDataKeys.PSI_FILE)// 转换为 XmlFileval xmlFile = psiFile as XmlFile// 获取根标签名称Utils.info("根标签名称:${xmlFile.rootTag?.name}")// 遍历获取所有的元素信息xmlFile.accept(object: XmlRecursiveElementVisitor() {override fun visitXmlAttribute(attribute: XmlAttribute) {Utils.info("属性名称:${attribute.name}, 属性值:${attribute.value}")}})}}
可以看到这里遍历使用的是XmlRecursiveElementVisitor
,是 XML 对于PsiElementVisitor
的一个实现类,用于遍历 XML 文件中的各种元素:
PSI Element(PSI 元素)
在上面介绍 PSI 文件的时候多次提到元素的概念,PSI 文件则正是由一系列的 PSI Element 所组成。和 PSI file 类似,PSI Element 也属于一个顶层接口,针对不同的编程语言,会有多种 PSI 元素。以 Java 为例,有 PsiClass、PSIMethod、PsiField 等对应 Java 语法的各类元素。而 XML 中也有 XmlTag、XmlAttribute 等概念。那我们如何快速知道一个文件中有哪些 PSI 元素?如何快速知道一个我们不熟悉的编程语言中的 PSI 元素?别慌,IntelliJ平台给我提供了工具:
通过 IntelliJ 平台的工具,我们可以很方便地查看当前或者任意一种文件的 PSI 结构,下面分别以 Java 和 XML 文件为例,首先是 Java 文件:
同时点击左下的元素节点,上方还会自动对应到元素位置:
然后是 XML 文件:
当然,除了 Java 和 XML,IntelliJ 支持的编程语言远不止这些,这里展示一部分,剩下的大家可以自行探索:
上面介绍了如何快速查看 PSI 文件中的元素,下面再介绍如何去获取 PSI 元素,以下来自官网:
Context | API |
---|---|
Action | AnActionEvent.getData(CommonDataKeys.PSI_ELEMENT) Note: If an editor is currently open and the element under caret is a reference, this will return the result of resolving the reference. |
PSI File | PsiFile.findElementAt(offset) |
Reference | PsiReference.resolve() |
可以看到总共有三种方式:第一种是直接获取当前光标位置的 PSI 元素;第二种是可以自己指定偏移量(如果不熟悉偏移量的概念,可以看本系列第五篇文章中讲解 CaretModel 的部分),获取指定文件指定位置的 PSI 元素;最后一种引用则使用的较少,这里不再展开介绍,大家可以查看官方文档进行了解。
除了获取某个位置的 PSI 元素,我们还可以获取其所属父元素或者子元素,下面以 Java 文件为例讲解如何使用:
class PsiJavaAction: AnAction() {override fun actionPerformed(e: AnActionEvent) {val psiFile = e.getData(CommonDataKeys.PSI_FILE)// 获取光标处 PSI 元素,假定该元素在方法内部val psiElement = e.getData(PlatformDataKeys.EDITOR)?.caretModel?.let { psiFile?.findElementAt(it.offset) }// 获取该元素所属的方法名val psiMethod = PsiTreeUtil.getParentOfType(psiElement, PsiMethod::class.java)// 获取该元素所属的类名val psiClass = PsiTreeUtil.getParentOfType(psiElement, PsiClass::class.java)Utils.info("所属方法名:${psiMethod?.name}")Utils.info("所属类名:${psiClass?.name}")}}
可以看到上面我们使用PsiTreeUtil::getParentOfType
可以获取到一个元素的父元素,同时支持跨层级获取,既可以获取元素所属的方法,也可以获取元素所属的类。
效果如下:
相应地我们也可以通过PsiTreeUtil::getChildrenOfTypeAsList
去获取某个元素的所有子元素:
class PsiJavaAction: AnAction() {override fun actionPerformed(e: AnActionEvent) {val psiFile = e.getData(CommonDataKeys.PSI_FILE)// 先获取光标所在处元素所属的类val psiElement = e.getData(PlatformDataKeys.EDITOR)?.caretModel?.let { psiFile?.findElementAt(it.offset) }val psiClass = PsiTreeUtil.getParentOfType(psiElement, PsiClass::class.java)// 获取类中所有的方法val psiMethods = PsiTreeUtil.getChildrenOfTypeAsList(psiClass, PsiMethod::class.java)Utils.info("包含的方法:${psiMethods.joinToString(",") { it.name }}")}}
实战
在正式实现前,先介绍一下整体的实现思路,这里只说明如何从 Java 方法跳转到 Mapper XML 文件中的节点,反向参考代码也很好理解,思路如下:
- 左侧图标行标记符通过实现
RelatedItemLineMarkerProvider
并重写collectNavigationMarkers
方法设置。 - 判断代码行的元素类型为 PsiMethod 才进行设置,同时文件类名以 Mapper 结尾。
- 根据类名在项目查找同名的 Mapper XML 文件。
- 通过 accept 方法遍历 XML 文件所有的属性,将 id 值为对应方法名的标签所对应的元素保存到可跳转的目标。
设置行标记符号,平台给我们提供了 RelatedItemLineMarkerProvider 类进行设置,只需要自定义了自己的行标记类,然后在 plugin.xml 中添加 如下配置即可:
<codeInsight.lineMarkerProvider language="JAVA"implementationClass="cn.butterfly.psi.provider.JavaMapperLineMarkerProvider"/>
代码实现如下:
class JavaMapperLineMarkerProvider: RelatedItemLineMarkerProvider() {override fun collectNavigationMarkers(element: PsiElement,result: MutableCollection<in RelatedItemLineMarkerInfo<*>>) {// 查找类名后缀为 Mapper 内的所有方法if (element !is PsiMethod) {return}val psiClass = PsiTreeUtil.getParentOfType(element, PsiClass::class.java) ?: returnval className = psiClass.name ?: returnif (!className.endsWith("Mapper")) {return}// 查找同名 XML 文件对应的 PSI 文件对象val virtualFile = FileTypeIndex.getFiles(XmlFileType.INSTANCE, GlobalSearchScope.allScope(element.project)).first { it.name.startsWith(className) }val psiFile = PsiManager.getInstance(element.project).findFile(virtualFile)// 遍历 XML 文件中标签 id 节点值等于 Java 方法名的元素, 然后添加可跳转的行标记符psiFile?.accept(object : XmlRecursiveElementVisitor() {override fun visitXmlAttribute(attribute: XmlAttribute) {if (attribute.name == "id" && attribute.value == element.name) {// NavigationGutterIconBuilder 用于创建标识符result.add(NavigationGutterIconBuilder.create(PluginIcons.MAPPER_ICON).setTargets(setOf(attribute.navigationElement)).setTooltipText("Navigation to target in mapper xml").createLineMarkerInfo(element))}}})}}
总结
本文简单介绍了关于 PSI 文件和元素的基础知识,最后以一个 Mybatis 文件跳转的例子去演示了如何去实际运用 PSI,在下一篇文章则会介绍关于 PSI 的进阶知识,敬请期待~~
相关文章:

IntelliJ IDE 插件开发 | (七)PSI 入门及实战(实现 MyBatis 插件的跳转功能)
系列文章 IntelliJ IDE 插件开发 |(一)快速入门IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化IntelliJ IDE 插件开发 |(三)消息通知与事件监听IntelliJ IDE 插件开发 |(四)来查收…...

【教程】iOS如何抓取HTTP和HTTPS数据包经验分享
📱 在日常的App开发和研发调研中,对各类App进行深入的研究分析时,我们需要借助专业的抓包应用来协助工作。本文将介绍如何使用iOS手机抓包工具来获取HTTP和HTTPS数据包,并推荐一款实用的抓包应用——克魔助手,希望能够…...

基于javaweb(springboot)汽车配件管理系统设计和实现以及文档报告
基于javaweb(springboot)汽车配件管理系统设计和实现以及文档报告 博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐…...

Spring Cloud Gateway Server MVC
之前你如果要用spring cloud gateway ,就必须是webflux 的,也就是必须是异步响应式编程。不能和spring mvc 一起使用。现在spring cloud 新出了一个可以不用webflux的gateway。 具体使用mvc的gateway步骤如下 普通的Eureka Client的项目 如果你只是想测…...

建立动态MGRE隧道的配置方法
目录 一、实验拓扑 1.1通用配置 1.1.1地址配置 1.1.2静态缺省指向R5,实现公网互通 1.1.3MGRE协议配置 1.1.4配置静态 二、Shortcut方式 三、Normal方式(非shortcut) 四、总结 一、实验拓扑 下面两种配置方法皆使用静态方式 1.1通用配…...

【MySQL】9. 内置函数
函数 1. 日期函数 获得年月日: mysql> select current_date(); ---------------- | current_date() | ---------------- | 2024-03-23 | ---------------- 1 row in set (0.00 sec)获得时分秒: mysql> select current_time(); ------------…...

芯片工程系列(5)2.5D 3D封装
0 英语缩写 硅通孔(Through Silicon Via,TSV)硅中介层(Silicon Interposer)物理气象沉淀法(Physical Vapor Deposition,PVD)DRIE、CVD、PVD、CMP等设备CoWoS(Chip on Wa…...

KubeSphere简单介绍及安装使用
KubeSphere 概述 官网地址:https://kubesphere.io/zh/ 什么是 kubesphere KubeSphere 是一个开源的多云容器管理平台,旨在简化企业级 k8s 集群的部署、管理和运维。它提供了一个可视化的管理界面,帮助用户更轻松地管理和监控 k8s 集群&…...

Java零基础-集合:Java 8新增的集合操作
哈喽,各位小伙伴们,你们好呀,我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。 我是一名后…...

C++经典面试题目(七)
1、什么是引用?请解释引用的概念和用法。 当谈论引用时,指的是在 C 中的一种类型。引用提供了对变量的别名,它允许通过不同的名称访问同一个变量。引用在 C 中常用于函数参数传递、返回值传递和操作符重载等场景。 引用的概念和用法&#x…...

让手机平板成为AI开发利器:AidLux
想ssh登录自己的手机吗? 想在手机上自由的安装lynx、python、vscode、jupyter甚至飞桨PaddlePaddle、Tensorflow、Pytorch和昇思Mindspore吗? 那么看这里....装上AidLux,以上全都有! AidLux是一个综合的AI开发平台,…...

Python物理学有限差分微分求解器和动画波形传播
🎯要点 Python数值和符号计算: 振动常微分方程:🎯中心差分求解器,绘制移动窗口研究长时间序列。🎯符号计算离散方程量化误差。🎯Python数值对比正向欧拉方法,反向欧拉方法…...

游戏本续航@控制中心的省电模式效果如何
文章目录 节能模式长续航模式👺相关工具 节能模式长续航模式👺 蓝天模具Control Center中的模式 根据我的试验,以及软件的提示,可以发现 Power Saving是最省电的,儿Quiet模式并不省电,它会启用独立显卡,只不过风扇的转速不像娱乐模式和性能模式那么积极而…...

centOS 安装MySQL8.0
1.配置yum仓库 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 2.安装MySQL8.x版本 yum库 rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch.rpm 或者 wget https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch…...

力扣 1.两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回…...

Occupancy field----其他应用
文章目录 3D表示技术的概述:Signed Distance Function (SDF)Occupancy Field (占用场)神经辐射场(NeRF) Occupancy Networks 是一种基于Occupancy表示的可微分模型,它在与其他3D表示技术(例如点云、体素和三角面片&…...

Spring_MVC
web.xml配置文件 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://xmlns.jcp.org/xml…...

【动手学深度学习】深入浅出深度学习之线性神经网络
目录 🌞一、实验目的 🌞二、实验准备 🌞三、实验内容 🌼1. 线性回归 🌻1.1 矢量化加速 🌻1.2 正态分布与平方损失 🌼2. 线性回归的从零开始实现 🌻2.1. 生成数据集 &#x…...

2024/3/26 C++作业
定义一个矩形类(Rectangle),包含私有成员:长(length)、宽(width), 定义成员函数: 设置长度:void set_l(int l) 设置宽度:void set_w(int w) 获取长度:int…...

LinkedList讲解指南
咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好…...

IP如何异地共享文件?
【天联】 组网由于操作简单、跨平台应用、无网络要求、独创的安全加速方案等原因,被几十万用户广泛应用,解决了各行业客户的远程连接需求。采用穿透技术,简单易用,不需要在硬件设备中端口映射即可实现远程访问。 异地共享文件 在…...

HCIA-Datacom H12-811 题库补充(3/28)
完整题库及答案解析,请直接扫描上方二维码,持续更新中 OSPFv3使用哪个区域号标识骨干区域? A:0 B:3 C:1 D:2 答案:A 解析:AREA 号0就是骨干区域。 STP下游设备通知上游…...

轻量级富文本编辑 Trumbowyg —— 基于 jQuery 插件配置
使用方法👇 首先,添加jQuery到页面<body>位置: <script src"http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script> <script>window.jQuery || document.write(<script src"js/vendor/jquery-1.10.2.min.js&qu…...

那些王道书里的题目-----计算机网络篇
注:仅记录个人认为有启发的题目 p155 34.下列四个地址块中,与地址块 172.16.166.192/26 不重叠,且与172.16.166.192/26聚合后的地址块不会引入多余地址的是() A.172.16.166.192/27 B.172.16.166.128/26 …...

【前端学习——js篇】 10.this指向
具体见:https://github.com/febobo/web-interview 10.this指向 根据不同的使用场合,this有不同的值,主要分为下面几种情况: 默认绑定隐式绑定new绑定显示绑定 ①默认绑定 全局环境中定义person函数,内部使用this关…...

项目搭建之统一返回值
自定义枚举类 Getter public enum ReturnCodeEnum {/*** 操作失败**/RC999("999","操作XXX失败"),/*** 操作成功**/RC200("200","success"),/*** 服务降级**/RC201("201","服务开启降级保护,请稍后再试!"),/*** …...

嵌入式和 Java 走哪条路?
最近看到一个物联网大三学生的疑问,原话如下: 本人普通本科物联网工程专业,开学大三,现在就很迷茫,不打算考研了,准备直接就业,平时一直在实验室参加飞思卡尔智能车比赛,本来是想走嵌…...

C++ 控制语句(一)
一 顺序结构 程序的基本结构有三种: 顺序结构、分支结构、循环结构 大量的实际问题需要通过各种控制流程来解决。 1.1 顺序结构 1.2 简单语句和复合语句 二 循环 2.1 for循环 语句流程图 注意:使用for语句的灵活性 三 while语句 四 do while语句...

mysql 用户管理-权限表
学习了《mysql5.7安装》,就先再了解下用户管理,先了解下权限表。 MySQL是一个多用户数据库,具有功能强大的访问控制系统,可以为不同用户指定允许 的权限。MySQL用户可以分为普通用户和root用户。root 用户是超级管理员,拥有所有权…...

【Postman如何进行接口测试简单详细操作实例】
1、下载Postman postman下载地址:Download Postman | Get Started for Free 2、安装Postman (1)双击下载好的postman-setup.exe文件,进行安装postman工具 (2)安装完成后,在桌面找到并打开postman软件,输入邮箱和密码进行登录&a…...