PSI 系统

PSI

PSI(Program Structure Interface)是一个接口,项目中的一切都可以表示为 PSI 对象,例如文件可以表示为 PsiFile,类可以表示为 PsiClass 等

PSI Element

PSI Element 是 PSI 系统下的基类,PsiFile、PsiClass 等等都是一个个具体的 PsiElement 实现,插件开发的主要工作就是针对不同的 PsiElement 进行分析和处理

常用对象

PsiFile

应用中的各种文件,例如 .java、.xml 文件等

VirtualFile 与 PsiFile 的区别:

PsiDirectory

应用中的目录

PsiJavaFile

Java源文件,如 Test.java

PsiClass

某个类,包括文件里的内部类

PsiMethod

类中的某个方法

PsiField

类中的某个属性

PsiParameterList

方法中的参数

PsiAnnotation

各种地方的注解

Document

以纯文本格式访问或者修改文件内容

常用方法

创建 ElementFactory

PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);

编辑 PsiClass

Intellij Platform 不允许在主线程中进行实时的文件写入,而需要通过一个异步任务来进行

WriteCommandAction.runWriteCommandAction(project, () -> {
  	//do sth.
});

格式化代码

CodeStyleManager.getInstance(project).reformat(element);

导入类

JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project);
manager.optimizeImports(file);
manager.shortenClassReferences(targetClass);

Find Usages

Query<PsiReference> query = ReferencesSearch.search(element);

搜索一个类的子类

Query<PsiClass> search = ClassInheritorsSearch.search(psiClass);

查询类所在的包

PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(classQualifiedName);

重命名

RefactoringFactory.getInstance(Project).createRename(element, "NewName");

查找被重写的方法

Query<PsiMethod> query = OverridingMethodsSearch.search(psiMethod);

获取 Editor

DataContext context = event.getDataContext();
Editor editor = CommonDataKeys.EDITOR.getData(context);

获取 Editor 选中的文本

SelectionModel selectionModel = editor.getSelectionModel();
int start = selectionModel.getSelectionStart();
int end = selectionModel.getSelectionEnd();
TextRange range = new TextRange(start, end);
String selectTxt = document.getText(range);

Editor打开指定名称的文件

new OpenFileDescriptor(project, psiFile.getVirtualFile()).navigate(true);
// 光标移动到指定位置
int offset = psiFile.getText().indexOf("setContentView");
new OpenFileDescriptor(project, psiFile.getVirtualFile(), offset).navigate(true);

根据类全名查询 PsiClass

PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(classQualifiedName, GlobalSearchScope.projectScope(project));

根据类 SiampleName 查询 PsiClass

PsiClass[] psiClasses = PsiShortNamesCache.getInstance(project).getClassesByName(classSimpleName, GlobalSearchScope.projectScope(project));

获取鼠标选中的目录

IdeView view = anActionEvent.getRequiredData(LangDataKeys.IDE_VIEW);
PsiDirectory directory = view.getOrChooseDirectory();

插件配置参数持久化

当插件有一些用户定制的配置参数信息时,需要插件具备记忆功能,在IDEA重启后,仍然能够生效,这就需要用到插件配置信息实现接口 PersistentStateComponent

状态栏进度条

如果有耗时任务,需要增加进度条,实现 Task.Backgroundable 抽象类,重写 run 方法

使用模板

插件开发中也可以使用文件模板,将公共部分代码进行抽离,减少创建PSI对象的复杂程度

鸣谢: