diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt index bcabbf930..1c70d2326 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt @@ -40,16 +40,24 @@ import com.demonwav.mcdev.platform.mixin.expression.gen.psi.METype import com.demonwav.mcdev.platform.mixin.expression.psi.METypeUtil import com.demonwav.mcdev.platform.mixin.util.MixinConstants import com.demonwav.mcdev.util.findMultiInjectionHost +import com.intellij.codeInsight.AutoPopupController import com.intellij.codeInspection.InspectionManager +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.RemoveAnnotationQuickFix +import com.intellij.lang.annotation.AnnotationBuilder import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.project.Project import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.util.TypeConversionUtil import com.intellij.psi.util.parentOfType @@ -275,6 +283,7 @@ class MEExpressionAnnotator : Annotator { ) .range(type) .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + .withDefinitionFix(type) .create() } else { holder.newSilentAnnotation(HighlightSeverity.TEXT_ATTRIBUTES) @@ -306,6 +315,7 @@ class MEExpressionAnnotator : Annotator { ) .range(variable) .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + .withDefinitionFix(variable) .create() } else { holder.newSilentAnnotation(HighlightSeverity.TEXT_ATTRIBUTES) @@ -314,4 +324,43 @@ class MEExpressionAnnotator : Annotator { .create() } } + + private fun AnnotationBuilder.withDefinitionFix(name: MEName) = + withFix(AddDefinitionInspection(name)) + + private class AddDefinitionInspection(name: MEName) : LocalQuickFixAndIntentionActionOnPsiElement(name) { + private val id = name.text + + override fun getFamilyName(): String = "Add @Definition" + + override fun getText(): String = "$familyName(id = \"$id\")" + + override fun invoke( + project: Project, + file: PsiFile, + editor: Editor?, + startElement: PsiElement, + endElement: PsiElement + ) { + if (editor == null) { + MEExpressionCompletionUtil.addDefinition( + startElement, + id, + "" + ) + return + } + val annotation = MEExpressionCompletionUtil.addDefinition( + startElement, + id, + "dummy" + ) ?: return + val dummy = annotation.findAttribute("dummy") as? PsiElement ?: return + val hostEditor = InjectedLanguageEditorUtil.getTopLevelEditor(editor) + hostEditor.caretModel.moveToOffset(dummy.textOffset) + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(hostEditor.document) + hostEditor.document.replaceString(dummy.textRange.startOffset, dummy.textRange.endOffset, "") + AutoPopupController.getInstance(project).autoPopupMemberLookup(hostEditor, null) + } + } } diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt index 1c2617d10..3801ad83f 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt @@ -1178,6 +1178,11 @@ object MEExpressionCompletionUtil { private fun addDefinition(context: InsertionContext, id: String, definitionValue: String): PsiAnnotation? { val contextElement = context.file.findElementAt(context.startOffset) ?: return null + return addDefinition(contextElement, id, definitionValue) + } + + fun addDefinition(contextElement: PsiElement, id: String, definitionValue: String): PsiAnnotation? { + val project = contextElement.project val injectionHost = contextElement.findMultiInjectionHost() ?: return null val expressionAnnotation = injectionHost.parentOfType() ?: return null if (!expressionAnnotation.hasQualifiedName(MixinConstants.MixinExtras.EXPRESSION)) { @@ -1195,14 +1200,14 @@ object MEExpressionCompletionUtil { } // create and add the new @Definition annotation - var newAnnotation = JavaPsiFacade.getElementFactory(context.project).createAnnotationFromText( + var newAnnotation = JavaPsiFacade.getElementFactory(project).createAnnotationFromText( "@${MixinConstants.MixinExtras.DEFINITION}(id = \"$id\", $definitionValue)", modifierList, ) var anchor = modifierList.annotations.lastOrNull { it.hasQualifiedName(MixinConstants.MixinExtras.DEFINITION) } if (anchor == null) { val definitionPosRelativeToExpression = - MinecraftProjectSettings.getInstance(context.project).definitionPosRelativeToExpression + MinecraftProjectSettings.getInstance(project).definitionPosRelativeToExpression if (definitionPosRelativeToExpression == BeforeOrAfter.AFTER) { anchor = expressionAnnotation } @@ -1211,11 +1216,11 @@ object MEExpressionCompletionUtil { // add imports and reformat newAnnotation = - JavaCodeStyleManager.getInstance(context.project).shortenClassReferences(newAnnotation) as PsiAnnotation - JavaCodeStyleManager.getInstance(context.project).optimizeImports(modifierList.containingFile) + JavaCodeStyleManager.getInstance(project).shortenClassReferences(newAnnotation) as PsiAnnotation + JavaCodeStyleManager.getInstance(project).optimizeImports(modifierList.containingFile) val annotationIndex = modifierList.annotations.indexOf(newAnnotation) val formattedModifierList = - CodeStyleManager.getInstance(context.project).reformat(modifierList) as PsiModifierList + CodeStyleManager.getInstance(project).reformat(modifierList) as PsiModifierList return formattedModifierList.annotations.getOrNull(annotationIndex) }