diff --git a/build.gradle.kts b/build.gradle.kts index 358906c65..9686388bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -307,12 +307,13 @@ tasks.clean { delete(generate) } tasks.withType { pluginJar.set(tasks.jar.get().archiveFile) + val pluginDirName = intellijPlatform.projectName.get() from(externalAnnotationsJar) { - into("MinecraftDev/lib/resources") + into("$pluginDirName/lib/resources") } from("templates") { exclude(".git") - into("MinecraftDev/lib/resources/builtin-templates") + into("$pluginDirName/lib/resources/builtin-templates") } } @@ -323,6 +324,12 @@ tasks.runIde { systemProperty("idea.ProcessCanceledException", "disabled") systemProperty("idea.debug.mode", "true") } + + // Kotlin K2 is enabled by default, uncomment to switch to K1 + // jvmArgumentProviders += CommandLineArgumentProvider { + // listOf("-Didea.kotlin.plugin.use.k2=false") + // } + // Set these properties to test different languages // systemProperty("user.language", "fr") // systemProperty("user.country", "FR") diff --git a/changelog.md b/changelog.md index 074e38d07..9e603ff54 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,11 @@ - `mods.toml` and `neoforge.mods.toml` documentation for lookup elements - Support for split strings within inspections and method target references in Mixins ([#2358](https://github.com/minecraft-dev/MinecraftDev/pull/2358)) - Mouse ungrab on breakpoint hit while running a Gradle task +- JSON5 support to mixin config jsons ([#2375](https://github.com/minecraft-dev/MinecraftDev/pull/2375)) +- Value types in mods.toml key completion +- Mixin injection signature fix preview +- Loom 1.8 support +- K2 mode compatibility ### Changed @@ -20,6 +25,9 @@ - Ignored annotations registrations - NeoGradle and NeoModDev Minecraft version import - [#2360](https://github.com/minecraft-dev/MinecraftDev/issues/2360) `Class initialization must not depend on services` error +- [#2376](https://github.com/minecraft-dev/MinecraftDev/issues/2376) Error when generating event listeners in read only file +- [#2308](https://github.com/minecraft-dev/MinecraftDev/issues/2308) Mixin Inject signature fix adds last parameter as first local +- [#1813](https://github.com/minecraft-dev/MinecraftDev/issues/1813) Single character Accessor targets aren't inferred correctly ## [1.8.1] - 2024-08-10 diff --git a/src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelBuilderImpl.groovy b/src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelBuilderImpl.groovy index c751e8998..f911e8be8 100644 --- a/src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelBuilderImpl.groovy +++ b/src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelBuilderImpl.groovy @@ -20,13 +20,14 @@ package com.demonwav.mcdev.platform.mcp.gradle.tooling.fabricloom - import org.gradle.api.Project import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.gradle.tooling.AbstractModelBuilderService import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder -import org.jetbrains.plugins.gradle.tooling.ModelBuilderService +import org.jetbrains.plugins.gradle.tooling.Message +import org.jetbrains.plugins.gradle.tooling.ModelBuilderContext -class FabricLoomModelBuilderImpl implements ModelBuilderService { +class FabricLoomModelBuilderImpl extends AbstractModelBuilderService { @Override boolean canBuild(String modelName) { @@ -34,7 +35,7 @@ class FabricLoomModelBuilderImpl implements ModelBuilderService { } @Override - Object buildAll(String modelName, Project project) { + Object buildAll(@NotNull String modelName, @NotNull Project project, @NotNull ModelBuilderContext context) { if (!project.plugins.hasPlugin('fabric-loom')) { return null } @@ -43,7 +44,16 @@ class FabricLoomModelBuilderImpl implements ModelBuilderService { try { return build(project, loomExtension) - } catch (GroovyRuntimeException ignored) { + } catch (GroovyRuntimeException ex) { + context.messageReporter.createMessage() + .withTitle("Minecraft Dev - Loom importing error") + .withText("An error occurred while importing Loom data, falling back to legacy import") + .withGroup("com.demonwav.mcdev") + .withKind(Message.Kind.WARNING) + .withStackTrace() + .withException(ex) + .reportMessage(project) + // Must be using an older loom version, fallback. return buildLegacy(project, loomExtension) } @@ -77,7 +87,13 @@ class FabricLoomModelBuilderImpl implements ModelBuilderService { List getDecompilers(Object loomExtension, boolean client) { loomExtension.decompilerOptions.collect { def task = loomExtension.getDecompileTask(it, client) - def sourcesPath = task.outputJar.get().getAsFile().getAbsolutePath() + def sourcesPath + if (task.hasProperty("outputJar")) { + // Pre 1.8 + sourcesPath = task.outputJar.get().getAsFile().getAbsolutePath() + } else { + sourcesPath = task.sourcesOutputJar.get().getAsFile().getAbsolutePath() + } new FabricLoomModelImpl.DecompilerModelImpl(name: it.name, taskName: task.name, sourcesPath: sourcesPath) } } diff --git a/src/main/kotlin/creator/custom/EvaluateTemplateExpressionAction.kt b/src/main/kotlin/creator/custom/EvaluateTemplateExpressionAction.kt deleted file mode 100644 index d2fc2c771..000000000 --- a/src/main/kotlin/creator/custom/EvaluateTemplateExpressionAction.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Minecraft Development for IntelliJ - * - * https://mcdev.io/ - * - * Copyright (C) 2024 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.creator.custom - -import com.demonwav.mcdev.creator.custom.model.ClassFqn -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.editor.EditorFactory -import com.intellij.openapi.editor.ex.EditorEx -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.util.Disposer -import com.intellij.ui.components.JBTextField -import com.intellij.ui.dsl.builder.Align -import com.intellij.ui.dsl.builder.panel -import javax.swing.JComponent - -class EvaluateTemplateExpressionAction : AnAction() { - override fun actionPerformed(e: AnActionEvent) { - - val dialog = EvaluateDialog() - dialog.isModal = false - dialog.show() - } - - private class EvaluateDialog : DialogWrapper(null, false, IdeModalityType.IDE) { - val document = EditorFactory.getInstance().createDocument("") - val editor = EditorFactory.getInstance().createEditor(document) as EditorEx - - lateinit var field: JBTextField - - init { - title = "Evaluate Template Expression" - isOKActionEnabled = true - setValidationDelay(0) - - Disposer.register(disposable) { - EditorFactory.getInstance().releaseEditor(editor) - } - - init() - } - - override fun createCenterPanel(): JComponent = panel { - row { - cell(editor.component).align(Align.FILL) - } - - row("Result:") { - field = textField().align(Align.FILL).component - field.isEditable = false - } - } - - override fun doOKAction() { - val props = mapOf( - "BUILD_SYSTEM" to "gradle", - "USE_PAPER_MANIFEST" to false, - "MAIN_CLASS" to ClassFqn("io.github.rednesto.test.Test") - ) - field.text = TemplateEvaluator.evaluate(props, document.text).toString() - } - } -} diff --git a/src/main/kotlin/insight/generation/EventGenHelper.kt b/src/main/kotlin/insight/generation/EventGenHelper.kt index 5ee687e8b..2b7226229 100644 --- a/src/main/kotlin/insight/generation/EventGenHelper.kt +++ b/src/main/kotlin/insight/generation/EventGenHelper.kt @@ -33,6 +33,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.util.parentOfType +import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferences +import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferencesInRange +import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode +import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile @@ -108,7 +112,11 @@ class KotlinEventGenHelper : EventGenHelper { val factory = KtPsiFactory.contextual(context) val entry = factory.createSuperTypeEntry(fqn) val insertedEntry = ktClass.addSuperTypeListEntry(entry) - ShortenReferences.DEFAULT.process(insertedEntry) + when (KotlinPluginModeProvider.currentPluginMode) { + KotlinPluginMode.K1 -> ShortenReferences.DEFAULT.process(insertedEntry) + // TODO find a non-internal alternative to this... + KotlinPluginMode.K2 -> shortenReferences(insertedEntry) + } } override fun reformatAndShortenRefs(file: PsiFile, startOffset: Int, endOffset: Int) { @@ -116,7 +124,10 @@ class KotlinEventGenHelper : EventGenHelper { val project = file.project val marker = JvmEventGenHelper.doReformat(project, file, startOffset, endOffset) ?: return - - ShortenReferences.DEFAULT.process(file, marker.startOffset, marker.endOffset) + when (KotlinPluginModeProvider.currentPluginMode) { + KotlinPluginMode.K1 -> ShortenReferences.DEFAULT.process(file, marker.startOffset, marker.endOffset) + // TODO find a non-internal alternative to this... + KotlinPluginMode.K2 -> shortenReferencesInRange(file, marker.textRange) + } } } diff --git a/src/main/kotlin/platform/mixin/MixinModule.kt b/src/main/kotlin/platform/mixin/MixinModule.kt index 1ac235176..28f35c033 100644 --- a/src/main/kotlin/platform/mixin/MixinModule.kt +++ b/src/main/kotlin/platform/mixin/MixinModule.kt @@ -25,12 +25,12 @@ import com.demonwav.mcdev.facet.MinecraftFacetDetector import com.demonwav.mcdev.platform.AbstractModule import com.demonwav.mcdev.platform.PlatformType import com.demonwav.mcdev.platform.mixin.config.MixinConfig +import com.demonwav.mcdev.platform.mixin.config.MixinConfigFileType import com.demonwav.mcdev.platform.mixin.framework.MIXIN_LIBRARY_KIND import com.demonwav.mcdev.util.SemanticVersion import com.demonwav.mcdev.util.nullable import com.intellij.json.psi.JsonFile import com.intellij.json.psi.JsonObject -import com.intellij.openapi.fileTypes.FileTypeManager import com.intellij.openapi.project.Project import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass @@ -53,12 +53,7 @@ class MixinModule(facet: MinecraftFacet) : AbstractModule(facet) { override val icon: Icon? = null companion object { - private val mixinFileTypes by lazy { - listOfNotNull( - FileTypeManager.getInstance().findFileTypeByName("Mixin Json Configuration"), - FileTypeManager.getInstance().findFileTypeByName("Mixin Json5 Configuration") - ) - } + private val mixinFileTypes = listOf(MixinConfigFileType.Json, MixinConfigFileType.Json5) fun getMixinConfigs( project: Project, diff --git a/src/main/kotlin/platform/mixin/config/MixinConfigFileType.kt b/src/main/kotlin/platform/mixin/config/MixinConfigFileType.kt index a6cfb647c..15f927a6c 100644 --- a/src/main/kotlin/platform/mixin/config/MixinConfigFileType.kt +++ b/src/main/kotlin/platform/mixin/config/MixinConfigFileType.kt @@ -28,7 +28,7 @@ import com.intellij.openapi.fileTypes.ex.FileTypeIdentifiableByVirtualFile import com.intellij.openapi.vfs.VirtualFile interface MixinConfigFileType : FileTypeIdentifiableByVirtualFile { - fun getFilenameRegex() : Regex + fun getFilenameRegex(): Regex // Dynamic file type detection is sadly needed as we're overriding the built-in json file type. // Simply using an extension pattern is not sufficient as there is no way to bump the version to tell @@ -36,21 +36,22 @@ interface MixinConfigFileType : FileTypeIdentifiableByVirtualFile { // See https://www.plugin-dev.com/intellij/custom-language/file-type-detection/#guidelines override fun isMyFileType(file: VirtualFile) = file.name.contains(getFilenameRegex()) - override fun getDescription() = "Mixin configuration" override fun getDefaultExtension() = "" override fun getIcon() = PlatformAssets.MIXIN_ICON object Json : LanguageFileType(JsonLanguage.INSTANCE), MixinConfigFileType { private val filenameRegex = "(^|\\.)mixins?(\\.[^.]+)*\\.json\$".toRegex() - override fun getFilenameRegex() : Regex = filenameRegex + override fun getFilenameRegex(): Regex = filenameRegex override fun getName() = "Mixin Json Configuration" + override fun getDescription() = "Mixin Json configuration" } object Json5 : LanguageFileType(Json5Language.INSTANCE), MixinConfigFileType { private var filenameRegex = "(^|\\.)mixins?(\\.[^.]+)*\\.json5\$".toRegex() - override fun getFilenameRegex() : Regex = filenameRegex + override fun getFilenameRegex(): Regex = filenameRegex override fun getName() = "Mixin Json5 Configuration" + override fun getDescription() = "Mixin Json5 configuration" } -} \ No newline at end of file +} diff --git a/src/main/kotlin/platform/mixin/handlers/AccessorHandler.kt b/src/main/kotlin/platform/mixin/handlers/AccessorHandler.kt index 112045c97..b67f9dd55 100644 --- a/src/main/kotlin/platform/mixin/handlers/AccessorHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/AccessorHandler.kt @@ -84,7 +84,7 @@ class AccessorHandler : MixinMemberAnnotationHandler { val result = PATTERN.matchEntire(memberName) ?: return null val prefix = result.groupValues[1] var name = result.groupValues[2] - if (name.uppercase(Locale.ENGLISH) != name) { + if (name.uppercase(Locale.ENGLISH) != name || name.length == 1) { name = name.decapitalize() } val type = if (prefix == "set") { diff --git a/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt b/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt index 0e73bb6b6..d16cf18b7 100644 --- a/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt +++ b/src/main/kotlin/platform/mixin/handlers/InjectAnnotationHandler.kt @@ -87,11 +87,11 @@ class InjectAnnotationHandler : InjectorAnnotationHandler() { val resolvedInsns = resolveInstructions(annotation, targetClass, targetMethod).ifEmpty { return@let } for (insn in resolvedInsns) { val locals = LocalVariables.getLocals(module, targetClass, targetMethod, insn.insn) + ?.filterNotNull() ?.drop( Type.getArgumentTypes(targetMethod.desc).size + if (targetMethod.hasAccess(Opcodes.ACC_STATIC)) 0 else 1, ) - ?.filterNotNull() ?.filter { it.desc != null } ?: continue if (commonLocalsPrefix == null) { diff --git a/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt b/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt index ca1f57c25..393066daa 100644 --- a/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt +++ b/src/main/kotlin/platform/mixin/inspection/injector/InvalidInjectorMethodSignatureInspection.kt @@ -39,6 +39,7 @@ import com.demonwav.mcdev.util.synchronize import com.intellij.codeInsight.FileModificationService import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview import com.intellij.codeInsight.intention.QuickFixFactory +import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.template.Expression @@ -71,6 +72,7 @@ import com.intellij.psi.PsiPrimitiveType import com.intellij.psi.PsiType import com.intellij.psi.codeStyle.JavaCodeStyleManager import com.intellij.psi.codeStyle.VariableKind +import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.TypeConversionUtil import com.intellij.psi.util.parentOfType @@ -327,12 +329,21 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() { return } val method = startElement as PsiMethod - fixParameters(project, method.parameterList) + fixParameters(project, method.parameterList, false) fixReturnType(method) fixIntLikeTypes(method, editor ?: return) } - private fun fixParameters(project: Project, parameters: PsiParameterList) { + override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo { + val method = PsiTreeUtil.findSameElementInCopy(startElement, file) as? PsiMethod + ?: return IntentionPreviewInfo.EMPTY + fixParameters(project, method.parameterList, true) + fixReturnType(method) + fixIntLikeTypes(method, editor) + return IntentionPreviewInfo.DIFF + } + + private fun fixParameters(project: Project, parameters: PsiParameterList, preview: Boolean) { if (expectedParams == null) { return } @@ -366,8 +377,12 @@ class InvalidInjectorMethodSignatureInspection : MixinInspection() { // Restore the captured locals and sugars before applying the fix newParams.addAll(locals) newParams.addAll(sugars) - runWriteAction { + if (preview) { parameters.synchronize(newParams) + } else { + runWriteAction { + parameters.synchronize(newParams) + } } } diff --git a/src/main/kotlin/util/SemanticVersion.kt b/src/main/kotlin/util/SemanticVersion.kt index 39f74e6cc..eeb91c254 100644 --- a/src/main/kotlin/util/SemanticVersion.kt +++ b/src/main/kotlin/util/SemanticVersion.kt @@ -151,6 +151,24 @@ class SemanticVersion( } } + // Regular Minecraft snapshot versions e.g. 24w39a + fun parseMinecraftSnapshot(value: String): SemanticVersion? { + if (value.length != 6 || value[2] != 'w' || !value[5].isLetter()) { + return null + } + + val shortYear = value.substring(0, 2).toIntOrNull() ?: return null + val week = value.substring(3, 5).toIntOrNull() ?: return null + + val subParts = listOf(ReleasePart(week, week.toString()), TextPart(value[5].toString())) + val mainPart = PreReleasePart(shortYear, 'w', subParts, value) + return SemanticVersion( + listOf(mainPart), + ) + } + + parseMinecraftSnapshot(value)?.let { return it } + val decodedValue = value.split('+').joinToString("+") { URLDecoder.decode(it, Charsets.UTF_8) } val mainPartAndMetadata = decodedValue.split("+", limit = 2) val mainPart = mainPartAndMetadata[0] diff --git a/src/main/resources/META-INF/mcdev-kotlin.xml b/src/main/resources/META-INF/mcdev-kotlin.xml index 2ff77caa7..99f14fdf0 100644 --- a/src/main/resources/META-INF/mcdev-kotlin.xml +++ b/src/main/resources/META-INF/mcdev-kotlin.xml @@ -24,4 +24,8 @@ + + + + diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index eb20382a4..beb17ebb1 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1578,8 +1578,5 @@ description="Copy the reference to clipboard in Access Widener format"> - diff --git a/templates b/templates index 088b45d5f..0460c78e9 160000 --- a/templates +++ b/templates @@ -1 +1 @@ -Subproject commit 088b45d5ffa33c91a528e5ae3bb6773b6871ef44 +Subproject commit 0460c78e914e4a15d5375a980d73b07ec52f15d5