PSI(Program Structure Interface) 文件是表示一个文件的内容作为在一个特定的编程语言元素的层次结构的结构的根。
PsiFile 类是所有PSI文件共同的基类, 在特定语言中的文件通常使用它的子类表示。比如,PsiJavaFile 类表示一个java文件, XmlFile 类表示xml文件。
和 VirtualFile
以及 Document
的应用作用域不同(即使打开多个projects,仍然只有一个对应的实例),PSI的作用域是项目级(多个projects中同时打开同一个文件,会有多个实例)。
如何获取PSI文件?
- 从action获取:
e.getData(LangDataKeys.PSI_FILE)
. - 从虚拟文件获取:
PsiManager.getInstance(project).findFile()
- 从文档获取:
PsiDocumentManager.getInstance(project).getPsiFile()
- 从文件内的一个元素获取:
psiElement.getContainingFile()
- 在project中的任意位置通过指定的名字寻找文件,使用
FilenameIndex.getFilesByName(project, name, scope)
PSI文件可以做什么?
大多数修改操作作用在独立的PSI元素上,而不是整个文件。
遍历一个文件中的所有元素,使用 psiFile.accept(new PsiRecursiveElementWalkingVisitor()...);
PSI 文件从何而来?
PSI是语言独立的,PSI文件通过 Language 对象创建, 使用LanguageParserDefinitions.INSTANCE.forLanguage(language).createFile(fileViewProvider)
方法.
和文档一样,一旦PSI被作为文件访问,一个PSI文件即被立即创建了。
PSI文件生命周期?
和文档相同,PSI文件被VirtualFile
实例弱引用,因此当不再被其它任何对象引用时将被GC回收。
如何创建PSI文件?
PsiFileFactory
.getInstance(project).createFileFromText()
方法为指定的内容在内存中创建一个PSI文件。
把PSI文件保存到硬盘中,使用 PsiDirectory
.add()
方法.
如何获取PSI文件修改通知?
PsiManager.getInstance(project).addPsiTreeChangeListener()
允许你获取一个project中所有PSI树的修改。
我如何扩展PSI?
PSI可通过自定义语言插件扩展用来支持其它语言。更多信息参考 Custom Language Support .
PSI工作规则?
PSI文件内容的任何改变反映在文档上,所以文档的任何规则都是有效的(读、写动作,命令,只读状态处理)。