修改PSI

走着路睡觉大约 3 分钟

修改PSI

PSI 把源码封装成了一个元素树,可以通过 增加、替换、删除元素来修改源码。

在同一个操作中,PSI元素 可以通过 PsiElementopen in new window 接口中的 add()delete()replace() 等方法进行修改,也可以在指定位置增加新的 PSI元素。

Document 一样,为了保证线程安全。修改PSI操作必须在主线程中,在write action中执行,如下:

WriteCommandAction.writeCommandAction(project).run(() -> {修改操作})

创建PSI

提示

创建PSI文件,查看文档:PSI文件#如何创建PSI文件

通过PsiFileFactoryopen in new windowcreateFileFromText() 方法可以创建PSI文件,遍历创建的PSI文件中的PSI元素,可以定位到目标位置(找到某一个PSI元素)进行替换,添加等

大部分编程语言提供了简单的创建PSI元素的方法,例如 PsiJavaParserFacade.createMethodFromText() 方法可以创建java 方法。用字符串创建PSI元素的时候,需要保证字符串的语法是正确的,否则会抛出异常。

修改大的代码片段,为了防止异常,最好使用以下步骤:

  1. 预创建代码片段,在片段中预留占位符

  2. 把占位符替换为用户输入代码

  3. 在源文件中替换老代码

上面的步骤可以保证代码格式,不会引入不必要的空格等。示例如下:

// 需要把 binaryExpression中的 "x == y" 替换为 "x.equals(y)"
PsiBinaryExpression binaryExpression = (PsiBinaryExpression) descriptor.getPsiElement();
IElementType opSign = binaryExpression.getOperationTokenType();
PsiExpression lExpr = binaryExpression.getLOperand();
PsiExpression rExpr = binaryExpression.getROperand();

// 第一步:预创建代码片段,在片段中预留占位符 : 使用a和b当占位符 
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
PsiMethodCallExpression equalsCall =
    (PsiMethodCallExpression) factory.createExpressionFromText("a.equals(b)", null);

// 第二步: 把占位符a和b替换为原文件的x,y 
equalsCall.getMethodExpression().getQualifierExpression().replace(lExpr);
equalsCall.getArgumentList().getExpressions()[0].replace(rExpr);

// 第三步: 把原来的 PSI元素 "x == y" 替换为 新建的 PSI元素 
PsiExpression result = (PsiExpression) binaryExpression.replace(equalsCall);

提示

IntelliJ Platform 中,所有使用字符串参数来创建PSI元素的方法中,所有字符串中的换行符必须使用 "\n",例如 createFileFromText() 或其它的 createFromText() 方法中传入的字符串

保证代码结构的一致性

修改的时候需要保证代码结构的一致性,例如:for循环必须放在一个方法里(PsiMethod),可以使用 PsiTestUtil.checkFileStructure() 来校验代码结构是否正确。

空格和引入(import)

修改的时候,不需要创建单独的空格和换行符节点。IntelliJ Platform 会在每一条修改命令执行以后,根据用户选择的代码格式自动格式化代码。也可以使用 CodeStyleManager.reformat(PsiElement) 方法来手动格式化。

另外,在 JAVA(或有类似import机制的语言,例如:Groovy 或 Python )开发时,不需要手动创建 import ,只需要在你的代码使用类的全限定命名 ,然后调用JavaCodeStyleManager.shortenClassReferences()open in new window 方法(编程语言对应的方法),会自动在正确的地方自动插入 import

合并PSI和Document修改

In some cases, you need to perform a PSI modification and then to perform an operation on the document you've just modified through the PSI (for example, start a live templateopen in new window ). To complete the PSI-based post-processing (such as formatting) and commit the changes to the document, call doPostponedOperationsAndUnblockDocument() on PsiDocumentManageropen in new window instance.

上次编辑于:
贡献者: zhaojingbo
Loading...