IDEA插件开发日记(二)
2024.4.29
PSI
全称 程序结构接口(Program Structure Interface),是IDEA插件开发中比较难的部分。负责解析文件并创建语法和语义代码模型,为平台的众多功能提供支持。个人理解就是将代码的各个元素分解开来,形成一颗树,然后可以定位到我们想要的代码,可以对其进行修改、删除等操作。 PSI主要包含三方面内容:
- PSI File
- File View Provider
- PSI Element
1.PSI File
PSI(程序结构接口)文件是结构的根,将文件内容表示为特定编程语言中元素的层次结构。 PsiFile 类是所有 PSI 文件的公共基类,而特定语言的文件通常由其子类表示。
例如,PsiJavaFile 类表示一个 Java 文件,而 XmlFile 类表示一个 XML 文件。 与Virtual Files和Documents有应用范围(即使打开多个项目,每个文件都由同一个VirtualFile实例表示)不同,PSI有项目范围:
如果文件属于多个项目,则同一个文件由多个PsiFile实例表示 同时打开。
在 IntelliJ IDEA 插件开发中,可以使用 PSI 文件来完成许多任务,例如:
- 导航和查找:通过分析 PSI 文件,可以实现跳转到定义、查找引用等导航功能。插件可以定位代码中的特定元素,并在编辑器中进行高亮显示或进行其他操作。
- 代码分析:通过遍历 PSI 树,可以执行静态代码分析。插件可以检测代码中的错误、潜在问题或编码风格违规,并提供相应的警告或建议。
- 重构和代码生成:PSI 文件提供了修改代码结构的能力。插件可以使用 PSI 文件来执行重构操作,例如重命名变量、提取方法、内联方法等。此外,还可以基于代码模板生成新的代码。
- 代码生成和自动完成:插件可以利用 PSI 文件生成代码片段,并将其插入到编辑器中。这对于自动完成功能非常有用,可以根据上下文为用户提供代码补全建议。
2.File View Provider
现实情况是编程语言是可以混合多种语言混写的,这时就需要用到了文件视图提供程序 ( FileViewProvider) ,它可以对单个文件中多个 PSI 树的访问。例如,JSPX 页面中的 Java 代码有一个单独的 PSI 树 ( `PsiJavaFile`),XML 代码有一个单独的树 ( `XmlFile`),整个 JSP 有一个单独的树 ( `JspFile`)。
每种语言被包装成单独的PSI树,然后在源文件的入口处饮食了一个"outer language elements"的点位符。每个 PSI 树都覆盖了文件的全部内容,并在可以找到不同语言内容的地方包含特殊的“外部语言元素”。
总结一下:一个FileViewProviderinstance对应一个VirtualFile,一个single Document,包含一或多个PsiFileinstance。
3.PSI Element
上述提到了元素就是这里所说的PSI Element。
How do I get a PSI element?
| Context | API |
|---|---|
| Action | AnActionEvent.getData(CommonDataKeys.PSI_ELEMENT)注意:如果编辑器当前打开并且插入符号下的元素是引用,则这将返回解析引用的结果。 |
| PSI File | PsiFile.findElementAt(offset) - 这会返回指定偏移处的叶元素,通常是词法分析器标记。用于PsiTreeUtil.getParentOfType()查找确切类型的元素。PsiRecursiveElementWalkingVisitor |
| Reference | PsiReference.resolve() |