User: joe Date: 02 Apr 26 20:18 Revision: c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f Summary: Implement CT v2 (enum extensions) TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=10468&personal=false Index: src/main/grammars/CtLexer.flex =================================================================== --- src/main/grammars/CtLexer.flex (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/grammars/CtLexer.flex (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -46,6 +46,8 @@ %s AW_TYPES %s ITF_ENTRY_KEY %s ITF_ENTRY_VALUE +%s ENUM_NAME +%s ENUM_VALUE %s SIGNATURE %unicode @@ -59,6 +61,7 @@ TYPE_VARIABLE=T[^;\n]+; ACCESS_ELEMENT=accessible|transitive-accessible|extendable|transitive-extendable|mutable|transitive-mutable INJECT_INTERFACE_ELEMENT=inject-interface|transitive-inject-interface +EXTEND_ENUM_ELEMENT=extend-enum|transitive-extend-enum CLASS_ELEMENT=class METHOD_ELEMENT=method FIELD_ELEMENT=field @@ -74,6 +77,7 @@ {HEADER_NAME} { yybegin(HEADER); return HEADER_NAME; } {ACCESS_ELEMENT} { yybegin(AW_ENTRY); return ACCESS_ELEMENT; } {INJECT_INTERFACE_ELEMENT} { yybegin(ITF_ENTRY_KEY); return INJECT_INTERFACE_ELEMENT; } + {EXTEND_ENUM_ELEMENT} { yybegin(ENUM_NAME); return EXTEND_ENUM_ELEMENT; } }
{ @@ -111,6 +115,14 @@ {CLASS_NAME_ELEMENT} { yybegin(SIGNATURE); return CLASS_NAME_ELEMENT; } } + { + {CLASS_NAME_ELEMENT} { yybegin(ENUM_VALUE); return CLASS_NAME_ELEMENT; } +} + + { + {NAME_ELEMENT} { return NAME_ELEMENT; } +} + { "<" { return LESS_THAN; } ">" { return GREATER_THAN; } Index: src/main/grammars/CtParser.bnf =================================================================== --- src/main/grammars/CtParser.bnf (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/grammars/CtParser.bnf (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -49,7 +49,7 @@ pin = 1 } -private entry ::= aw_entry | itf_entry { +private entry ::= aw_entry | itf_entry | extend_enum_entry { mixin="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.impl.CtEntryImplMixin" implements="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.impl.CtEntryMixin" recoverWhile = line_recover @@ -84,6 +84,12 @@ pin = 1 } +extend_enum_entry ::= EXTEND_ENUM_ELEMENT class_name member_name { + mixin="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.impl.CtExtendEnumEntryImplMixin" + implements="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.CtExtendEnumEntryMixin" + pin = 1 +} + private line_recover ::= !(end_line | COMMENT) access ::= ACCESS_ELEMENT { Index: src/main/kotlin/platform/mcp/ct/CtAnnotator.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/CtAnnotator.kt (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/kotlin/platform/mcp/ct/CtAnnotator.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -22,8 +22,10 @@ import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtAccess import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtClassLiteral +import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtExtendEnumEntry import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtFieldLiteral import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtHeader +import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtItfEntry import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtMethodLiteral import com.demonwav.mcdev.util.childOfType import com.google.common.collect.HashMultimap @@ -38,26 +40,43 @@ class CtAnnotator : Annotator { override fun annotate(element: PsiElement, holder: AnnotationHolder) { - if (element is CtAccess) { + val effectiveVersion by lazy { element.containingFile?.childOfType()?.effectiveVersion ?: 1 } + + when (element) { + is CtAccess -> { - val access = element.text - val target = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java)?.text - if (!TokenSets.compatibleByAccessMap.get(access).contains(target)) { - holder.newAnnotation(HighlightSeverity.ERROR, "Access '$access' cannot be used on '$target'").create() - } + val access = element.text + val target = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java)?.text + if (!TokenSets.compatibleByAccessMap.get(access).contains(target)) { + holder.newAnnotation(HighlightSeverity.ERROR, "Access '$access' cannot be used on '$target'").create() + } - if (element.accessElement.text.startsWith("transitive-") && - element.containingFile?.childOfType()?.effectiveVersion == 1 - ) { + if (element.accessElement.text.startsWith("transitive-") && effectiveVersion < 2) { - holder.newAnnotation(HighlightSeverity.ERROR, "Transitive accesses were introduced in v2").create() - } + holder.newAnnotation(HighlightSeverity.ERROR, "Transitive accesses were introduced in v2").create() + } - } else if (element is CtFieldLiteral || element is CtMethodLiteral || element is CtClassLiteral) { + } + is CtItfEntry -> { + if (effectiveVersion < 3) { + holder.newAnnotation(HighlightSeverity.ERROR, "Interface injection was introduced in ClassTweaker v1") + .range(element.firstChild) + .create() + } + } + is CtExtendEnumEntry -> { + if (effectiveVersion < 4) { + holder.newAnnotation(HighlightSeverity.ERROR, "Enum extension was introduced in ClassTweaker v2") + .range(element.firstChild) + .create() + } + } + is CtFieldLiteral, is CtMethodLiteral, is CtClassLiteral -> { - val target = element.text - val access = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace::class.java)?.text - if (!TokenSets.compatibleByTargetMap.get(target).contains(access)) { - holder.newAnnotation(HighlightSeverity.ERROR, "'$target' cannot be used with '$access'").create() - } - } - } + val target = element.text + val access = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace::class.java)?.text + if (!TokenSets.compatibleByTargetMap.get(target).contains(access)) { + holder.newAnnotation(HighlightSeverity.ERROR, "'$target' cannot be used with '$access'").create() + } + } + } + } object TokenSets { val compatibleByAccessMap = HashMultimap.create() Index: src/main/kotlin/platform/mcp/ct/CtColorSettingsPage.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/CtColorSettingsPage.kt (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/kotlin/platform/mcp/ct/CtColorSettingsPage.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -32,9 +32,9 @@ override fun getHighlighter() = CtSyntaxHighlighter() override fun getDemoText() = $$""" - classTweaker v1 named + classTweaker v2 named - # https://www.fabricmc.net/wiki/tutorial:accesswideners + # https://docs.fabricmc.net/develop/class-tweakers/ extendable class net/minecraft/world/item/crafting/Ingredient transitive-extendable class net/minecraft/world/item/crafting/Ingredient @@ -45,6 +45,8 @@ accessible field net/minecraft/world/item/crafting/Ingredient values [Lnet/minecraft/world/item/crafting/Ingredient$Value; inject-interface net/minecraft/world/level/block/Block com/example/MyBlockInterface transitive-inject-interface net/minecraft/world/level/block/Block com/example/MyTransitiveBlockInterface + extend-enum net/minecraft/client/gui/Gui$HeartType MYMOD_HEART_TYPE + transitive-extend-enum net/minecraft/client/gui/Gui$HeartType MYMOD_TRANSITIVE_HEART_TYPE """.trimIndent() override fun getAdditionalHighlightingTagToDescriptorMap(): Map? = null @@ -58,6 +60,7 @@ AttributesDescriptor("Header namespace", CtSyntaxHighlighter.HEADER_NAMESPACE), AttributesDescriptor("Access", CtSyntaxHighlighter.ACCESS), AttributesDescriptor("Inject interface", CtSyntaxHighlighter.INJECT_INTERFACE), + AttributesDescriptor("Extend enum", CtSyntaxHighlighter.EXTEND_ENUM), AttributesDescriptor("Class element", CtSyntaxHighlighter.CLASS_ELEMENT), AttributesDescriptor("Method element", CtSyntaxHighlighter.METHOD_ELEMENT), AttributesDescriptor("Field element", CtSyntaxHighlighter.FIELD_ELEMENT), Index: src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -111,7 +111,9 @@ "mutable", "transitive-mutable", "inject-interface", - "transitive-inject-interface" + "transitive-inject-interface", + "extend-enum", + "transitive-extend-enum", ).map { LookupElementBuilder.create(it).withInsertHandler { ctx, _ -> insertWhitespace(ctx) } } result.addAllElements(elements) } Index: src/main/kotlin/platform/mcp/ct/CtSyntaxHighlighter.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/CtSyntaxHighlighter.kt (revision 8124072a68b95d51e5e6373840b43fc753c40707) +++ src/main/kotlin/platform/mcp/ct/CtSyntaxHighlighter.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -38,6 +38,7 @@ CtTypes.HEADER_NAMESPACE_ELEMENT -> HEADER_NAMESPACE_KEYS CtTypes.ACCESS_ELEMENT -> ACCESS_KEYS CtTypes.INJECT_INTERFACE_ELEMENT -> INJECT_INTERFACE_KEYS + CtTypes.EXTEND_ENUM_ELEMENT -> EXTEND_ENUM_KEYS CtTypes.CLASS_ELEMENT -> CLASS_ELEMENT_KEYS CtTypes.METHOD_ELEMENT -> METHOD_ELEMENT_KEYS CtTypes.FIELD_ELEMENT -> FIELD_ELEMENT_KEYS @@ -60,6 +61,8 @@ TextAttributesKey.createTextAttributesKey("CT_ACCESS", DefaultLanguageHighlighterColors.KEYWORD) val INJECT_INTERFACE = TextAttributesKey.createTextAttributesKey("CT_INJECT_INTERFACE", DefaultLanguageHighlighterColors.KEYWORD) + val EXTEND_ENUM = + TextAttributesKey.createTextAttributesKey("CT_EXTEND_ENUM", DefaultLanguageHighlighterColors.KEYWORD) val CLASS_ELEMENT = TextAttributesKey.createTextAttributesKey("CT_CLASS_ELEMENT", DefaultLanguageHighlighterColors.KEYWORD) val METHOD_ELEMENT = @@ -85,6 +88,7 @@ private val HEADER_NAMESPACE_KEYS = arrayOf(HEADER_NAMESPACE) private val ACCESS_KEYS = arrayOf(ACCESS) private val INJECT_INTERFACE_KEYS = arrayOf(INJECT_INTERFACE) + private val EXTEND_ENUM_KEYS = arrayOf(EXTEND_ENUM) private val CLASS_ELEMENT_KEYS = arrayOf(CLASS_ELEMENT) private val METHOD_ELEMENT_KEYS = arrayOf(METHOD_ELEMENT) private val FIELD_ELEMENT_KEYS = arrayOf(FIELD_ELEMENT) Index: src/main/kotlin/platform/mcp/ct/psi/mixins/CtExtendEnumEntryMixin.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/psi/mixins/CtExtendEnumEntryMixin.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) +++ src/main/kotlin/platform/mcp/ct/psi/mixins/CtExtendEnumEntryMixin.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -0,0 +1,23 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mcp.ct.psi.mixins + +interface CtExtendEnumEntryMixin : CtEntryMixin Index: src/main/kotlin/platform/mcp/ct/psi/mixins/impl/CtExtendEnumEntryImplMixin.kt =================================================================== --- src/main/kotlin/platform/mcp/ct/psi/mixins/impl/CtExtendEnumEntryImplMixin.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) +++ src/main/kotlin/platform/mcp/ct/psi/mixins/impl/CtExtendEnumEntryImplMixin.kt (revision c6f35ea0dc5c00454bc5895623a1ccb161b7ab0f) @@ -0,0 +1,26 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2025 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mcp.ct.psi.mixins.impl + +import com.demonwav.mcdev.platform.mcp.ct.psi.mixins.CtExtendEnumEntryMixin +import com.intellij.lang.ASTNode + +abstract class CtExtendEnumEntryImplMixin(node: ASTNode): CtEntryImplMixin(node), CtExtendEnumEntryMixin