编辑

18. Quick Fix

快速修复允许通过显示意图操作(Alt + Enter)对代码应用自动更改。

让我们添加一个快速修复,它有助于根据其用法定义未解析的属性。

18.1。

更新元素工厂

package com.simpleplugin.psi; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.simpleplugin.SimpleFileType; public class SimpleElementFactory { public static SimpleProperty createProperty(Project project, String name, String value) { final SimpleFile file = createFile(project, name + " = " + value); return (SimpleProperty) file.getFirstChild(); } public static SimpleProperty createProperty(Project project, String name) { final SimpleFile file = createFile(project, name); return (SimpleProperty) file.getFirstChild(); } public static PsiElement createCRLF(Project project) { final SimpleFile file = createFile(project, "\n"); return file.getFirstChild(); } public static SimpleFile createFile(Project project, String text) { String name = "dummy.simple"; return (SimpleFile) PsiFileFactory.getInstance(project). createFileFromText(name, SimpleFileType.INSTANCE, text); } }

18.2。

定义意图行动

快速修复将在用户选择的文件中创建属性,并在创建后导航到此属性。

package com.simpleplugin; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.IncorrectOperationException; import com.intellij.util.indexing.FileBasedIndex; import com.simpleplugin.psi.SimpleElementFactory; import com.simpleplugin.psi.SimpleFile; import com.simpleplugin.psi.SimpleProperty; import org.jetbrains.annotations.NotNull; import java.util.Collection; class CreatePropertyQuickFix extends BaseIntentionAction { private String key; CreatePropertyQuickFix(String key) { this.key = key; } @NotNull @Override public String getText() { return "Create property"; } @NotNull @Override public String getFamilyName() { return "Simple properties"; } @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { return true; } @Override public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { Collection<VirtualFile> virtualFiles = FileTypeIndex.getFiles(SimpleFileType.INSTANCE, GlobalSearchScope.allScope(project) ); if (virtualFiles.size() == 1) { createProperty(project, virtualFiles.iterator().next()); } else { final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor(SimpleFileType.INSTANCE); descriptor.setRoots(ProjectUtil.guessProjectDir(project)); final VirtualFile file = FileChooser.chooseFile(descriptor, project, null); if (file != null) { createProperty(project, file); } } } }); } private void createProperty(final Project project, final VirtualFile file) { WriteCommandAction.writeCommandAction(project).run(() -> { SimpleFile simpleFile = (SimpleFile) PsiManager.getInstance(project).findFile(file); ASTNode lastChildNode = simpleFile.getNode().getLastChildNode(); // TODO: Add another check for CRLF if (lastChildNode != null/* && !lastChildNode.getElementType().equals(SimpleTypes.CRLF)*/) { simpleFile.getNode().addChild(SimpleElementFactory.createCRLF(project).getNode()); } // IMPORTANT: change spaces to escaped spaces or the new node will only have the first word for the key SimpleProperty property = SimpleElementFactory.createProperty(project, key.replaceAll(" ", "\\\\ "), ""); simpleFile.getNode().addChild(property.getNode()); ((Navigatable) property.getLastChild().getNavigationElement()).navigate(true); FileEditorManager.getInstance(project).getSelectedTextEditor().getCaretModel().moveCaretRelatively(2, 0, false, false, false); }); } }

18.3。

更新注释器

注意对registerFix的调用。

package com.simpleplugin; import com.intellij.lang.annotation.*; import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.simpleplugin.psi.SimpleProperty; import org.jetbrains.annotations.NotNull; import java.util.List; public class SimpleAnnotator implements Annotator { @Override public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { if (element instanceof PsiLiteralExpression) { PsiLiteralExpression literalExpression = (PsiLiteralExpression) element; String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null; if (value != null && value.startsWith("simple" + ":")) { Project project = element.getProject(); String key = value.substring(7); List<SimpleProperty> properties = SimpleUtil.findProperties(project, key); if (properties.size() == 1) { TextRange range = new TextRange(element.getTextRange().getStartOffset() + 7, element.getTextRange().getStartOffset() + 7); Annotation annotation = holder.createInfoAnnotation(range, null); annotation.setTextAttributes(DefaultLanguageHighlighterColors.LINE_COMMENT); } else if (properties.size() == 0) { TextRange range = new TextRange(element.getTextRange().getStartOffset() + 8, element.getTextRange().getEndOffset()); holder.createErrorAnnotation(range, "Unresolved property"). registerFix(new CreatePropertyQuickFix(key)); } } } } }

18.4。

运行该项目

现在让我们尝试使用尚未定义的属性。

快速修复

Last modified: 11 May 2019