From 0f55d27acdf3b772c5a51ba8a9dc044a1d1ef2cc Mon Sep 17 00:00:00 2001 From: joe Date: Mon, 20 Oct 2025 16:19:09 +0100 Subject: [PATCH 1/5] 2025.3 --- build.gradle.kts | 6 ++++-- .../main/kotlin/mcdev-publishing.gradle.kts | 5 +++-- gradle.properties | 2 +- gradle/libs.versions.toml | 21 ++++++++++++------- obfuscation-explorer/build.gradle.kts | 4 +++- .../kotlin/insight/ColorLineMarkerProvider.kt | 2 +- .../VanillaGradleDecompileSourceProvider.kt | 2 +- .../InjectionPointTypedHandlerDelegate.kt | 2 +- .../mixin/expression/MEExpressionAnnotator.kt | 2 +- .../MEExpressionTypedHandlerDelegate.kt | 2 +- .../kotlin/platform/mixin/util/AsmUtil.kt | 6 +++--- 11 files changed, 33 insertions(+), 21 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1518788cf..da61158ca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -101,7 +101,9 @@ dependencies { } intellijPlatform { - intellijIdeaCommunity(libs.versions.intellij.ide, useInstaller = false) + intellijIdea(libs.versions.intellij.ide) { + useInstaller = false + } // Bundled plugin dependencies bundledPlugin("com.intellij.java") @@ -109,7 +111,7 @@ dependencies { bundledPlugin("com.intellij.gradle") bundledPlugin("org.intellij.groovy") bundledPlugin("ByteCodeViewer") - bundledPlugin("org.intellij.intelliLang") + bundledModule("intellij.platform.langInjection") bundledPlugin("com.intellij.properties") bundledPlugin("Git4Idea") bundledPlugin("com.intellij.modules.json") diff --git a/buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts b/buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts index 4b14b592b..8aef4a8dc 100644 --- a/buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts @@ -26,6 +26,7 @@ import java.net.http.HttpResponse import kotlin.io.path.absolute import org.jetbrains.intellij.platform.gradle.utils.IdeServicesPluginRepositoryService import org.jetbrains.intellij.pluginRepository.PluginRepositoryFactory +import org.jetbrains.intellij.pluginRepository.model.ProductFamily plugins { id("org.jetbrains.intellij.platform") @@ -62,9 +63,9 @@ tasks.publishPlugin { false -> PluginRepositoryFactory.create(host.get(), token.get()) } - @Suppress("DEPRECATION") - val uploadBean = repositoryClient.uploader.upload( + val uploadBean = repositoryClient.uploader.uploadUpdateByXmlIdAndFamily( id = pluginId, + family = ProductFamily.INTELLIJ, file = path.toFile(), channel = channel.takeIf { it != "default" }, notes = null, diff --git a/gradle.properties b/gradle.properties index df922c10b..aefa0d733 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,7 +21,7 @@ # suppress inspection "UnusedProperty" for whole file org.gradle.jvmargs=-Xmx1g -ideaVersionName = 2025.2 +ideaVersionName = 2025.3 coreVersion = 1.8.6 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d9069c851..539ed2e23 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,17 +1,24 @@ [versions] -kotlin = "2.1.21" +# https://github.com/JetBrains/intellij-community/blob//.idea/libraries/kotlin_stdlib.xml +kotlin = "2.2.20" +# https://github.com/JetBrains/intellij-community/blob//.idea/libraries/kotlinx_coroutines_core.xml coroutines = "1.10.2" junit = "5.10.2" junit-platform = "1.10.2" -asm = "9.6" +asm = "9.9" fuel = "2.3.1" licenser = "0.6.1" changelog = "2.2.0" -intellij-plugin = "2.6.0" -intellij-plugin-repository-rest-client = "2.0.46" -intellij-ide = "2025.2" -idea-ext = "1.1.10" -psiPlugin = "251.175" +# https://github.com/JetBrains/intellij-platform-gradle-plugin +intellij-plugin = "2.10.1" +# https://search.maven.org/artifact/org.jetbrains.intellij/plugin-repository-rest-client +intellij-plugin-repository-rest-client = "2.0.47" +# https://www.jetbrains.com/intellij-repository/snapshots or https://www.jetbrains.com/intellij-repository/releases/ +intellij-ide = "253.27642.30-EAP-SNAPSHOT" +# https://github.com/JetBrains/gradle-idea-ext-plugin +idea-ext = "1.3" +# https://plugins.jetbrains.com/plugin/227-psiviewer/versions +psiPlugin = "253.7181" [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/obfuscation-explorer/build.gradle.kts b/obfuscation-explorer/build.gradle.kts index 03da2b1e9..c6bf6b97f 100644 --- a/obfuscation-explorer/build.gradle.kts +++ b/obfuscation-explorer/build.gradle.kts @@ -38,7 +38,9 @@ intellijPlatform { dependencies { intellijPlatform { - intellijIdeaCommunity(libs.versions.intellij.ide, useInstaller = false) + intellijIdea(libs.versions.intellij.ide) { + useInstaller = false + } plugin(libs.versions.psiPlugin.map { "PsiViewer:$it" }) diff --git a/src/main/kotlin/insight/ColorLineMarkerProvider.kt b/src/main/kotlin/insight/ColorLineMarkerProvider.kt index 70c272350..2689eeef0 100644 --- a/src/main/kotlin/insight/ColorLineMarkerProvider.kt +++ b/src/main/kotlin/insight/ColorLineMarkerProvider.kt @@ -149,7 +149,7 @@ class ColorLineMarkerProvider : LineMarkerProvider { } val actionText = MCDevBundle("generate.color.choose_action") - val c = ColorChooserService.instance.showDialog(psiElement.project, editor.component, actionText, color) + val c = ColorChooserService.getInstance().showDialog(psiElement.project, editor.component, actionText, color) ?: return@handler when (workElement) { is ULiteralExpression -> { diff --git a/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt b/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt index a54f8b8b1..8ada5fd7f 100644 --- a/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt +++ b/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt @@ -68,7 +68,7 @@ class VanillaGradleDecompileSourceProvider : AttachSourcesProvider { val taskCallback = object : TaskCallback { override fun onSuccess() { val importSpec = ImportSpecBuilder(project, GradleConstants.SYSTEM_ID) - .callback( + .withCallback( object : ExternalProjectRefreshCallback { override fun onSuccess(externalProject: DataNode?) = callback.setDone() diff --git a/src/main/kotlin/platform/mixin/completion/InjectionPointTypedHandlerDelegate.kt b/src/main/kotlin/platform/mixin/completion/InjectionPointTypedHandlerDelegate.kt index 0a93cc2b5..4a122951a 100644 --- a/src/main/kotlin/platform/mixin/completion/InjectionPointTypedHandlerDelegate.kt +++ b/src/main/kotlin/platform/mixin/completion/InjectionPointTypedHandlerDelegate.kt @@ -34,7 +34,7 @@ class InjectionPointTypedHandlerDelegate : TypedHandlerDelegate() { if (charTyped != ':' || !file.language.isKindOf(JavaLanguage.INSTANCE)) { return Result.CONTINUE } - AutoPopupController.getInstance(project).autoPopupMemberLookup(editor) { + AutoPopupController.getInstance(project).scheduleAutoPopup(editor) { val offset = editor.caretModel.offset val element = it.findElementAt(offset)?.findContextElement() InjectionPointReference.ELEMENT_PATTERN.accepts(element) diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt index 547077983..bbb0e5667 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionAnnotator.kt @@ -362,7 +362,7 @@ class MEExpressionAnnotator : Annotator { 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) + AutoPopupController.getInstance(project).scheduleAutoPopup(hostEditor, null) } } } diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionTypedHandlerDelegate.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionTypedHandlerDelegate.kt index fd6052b98..254936bf2 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionTypedHandlerDelegate.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionTypedHandlerDelegate.kt @@ -31,7 +31,7 @@ import com.intellij.psi.util.elementType class MEExpressionTypedHandlerDelegate : TypedHandlerDelegate() { override fun checkAutoPopup(charTyped: Char, project: Project, editor: Editor, file: PsiFile): Result { if (charTyped == ':' && file.language == MEExpressionLanguage) { - AutoPopupController.getInstance(project).autoPopupMemberLookup(editor) { + AutoPopupController.getInstance(project).scheduleAutoPopup(editor) { val offset = editor.caretModel.offset it.findElementAt(offset - 1).elementType == MEExpressionTypes.TOKEN_METHOD_REF } diff --git a/src/main/kotlin/platform/mixin/util/AsmUtil.kt b/src/main/kotlin/platform/mixin/util/AsmUtil.kt index f25148e57..1ded3b18b 100644 --- a/src/main/kotlin/platform/mixin/util/AsmUtil.kt +++ b/src/main/kotlin/platform/mixin/util/AsmUtil.kt @@ -42,6 +42,7 @@ import com.demonwav.mcdev.util.toJavaIdentifier import com.intellij.byteCodeViewer.ByteCodeViewerManager import com.intellij.codeEditor.JavaEditorFileSwapper import com.intellij.ide.highlighter.JavaFileType +import com.intellij.java.syntax.parser.JavaKeywords import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.project.Project @@ -64,7 +65,6 @@ import com.intellij.psi.PsiEnumConstant import com.intellij.psi.PsiField import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiKeyword import com.intellij.psi.PsiLambdaExpression import com.intellij.psi.PsiManager import com.intellij.psi.PsiMethod @@ -224,7 +224,7 @@ private val NODE_BY_PSI_CLASS_KEY = Key.create>("mcdev.n fun findClassNodeByPsiClass(psiClass: PsiClass, module: Module? = psiClass.findModule()): ClassNode? { return psiClass.lockedCached(NODE_BY_PSI_CLASS_KEY) { try { - val bytes = ByteCodeViewerManager.loadClassFileBytes(psiClass) + val bytes = ByteCodeViewerManager.findClassFile(psiClass)?.contentsToByteArray(false) if (bytes == null) { // find compiler output if (module == null) return@lockedCached null @@ -1050,7 +1050,7 @@ fun MethodNode.findBodyElements(clazz: ClassNode, project: Project, scope: Globa if (body != null) { val children = body.children val superCtorIndex = children.indexOfFirst { - it is PsiMethodCallExpression && it.methodExpression.text == PsiKeyword.SUPER + it is PsiMethodCallExpression && it.methodExpression.text == JavaKeywords.SUPER } result += children.take(superCtorIndex + 1) sourceMethod.containingClass?.children?.forEach { element -> From f2be83710cc66905f49ab308edf69014769d3305 Mon Sep 17 00:00:00 2001 From: joe Date: Fri, 19 Dec 2025 23:27:51 +0000 Subject: [PATCH 2/5] Build against 2025.3 release --- gradle/libs.versions.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 21b037823..2a9978952 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,11 +10,11 @@ fuel = "2.3.1" licenser = "0.7.5" changelog = "2.2.0" # https://github.com/JetBrains/intellij-platform-gradle-plugin -intellij-plugin = "2.10.1" -# https://search.maven.org/artifact/org.jetbrains.intellij/plugin-repository-rest-client -intellij-plugin-repository-rest-client = "2.0.47" +intellij-plugin = "2.10.5" +# https://central.sonatype.com/artifact/org.jetbrains.intellij/plugin-repository-rest-client +intellij-plugin-repository-rest-client = "2.0.50" # https://www.jetbrains.com/intellij-repository/snapshots or https://www.jetbrains.com/intellij-repository/releases/ -intellij-ide = "253.27642.30-EAP-SNAPSHOT" +intellij-ide = "253.29346.138" # https://github.com/JetBrains/gradle-idea-ext-plugin idea-ext = "1.3" # https://plugins.jetbrains.com/plugin/227-psiviewer/versions @@ -51,7 +51,7 @@ jflex-skeleton = "org.jetbrains.idea:jflex:1.7.0-c1fdf11" grammarKit = "org.jetbrains.idea:grammar-kit:1.5.1" # Gradle Tooling -gradleToolingExtension = { module = "com.jetbrains.intellij.gradle:gradle-tooling-extension", version = "252.23892.409" } +gradleToolingExtension = { module = "com.jetbrains.intellij.gradle:gradle-tooling-extension", version = "253.29346.138" } annotations = "org.jetbrains:annotations:24.0.0" groovy = "org.codehaus.groovy:groovy:3.0.19" From 65ec4d862d6154f32bcd8ab7ef3339baf894a1c3 Mon Sep 17 00:00:00 2001 From: joe Date: Sat, 20 Dec 2025 00:00:16 +0000 Subject: [PATCH 3/5] Remove some unnecessary unstable API suppressions --- src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt | 2 -- src/main/kotlin/platform/mixin/expression/gui/FlowGraph.kt | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt b/src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt index 9f87abd76..9667f1caf 100644 --- a/src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt +++ b/src/main/kotlin/platform/mixin/expression/gui/FlowDiagram.kt @@ -253,7 +253,6 @@ private suspend fun addGraphContent( } for (group in flowGraph) { - @Suppress("UnstableApiUsage") checkCanceled() val cells = mutableListOf() addFlow(group.root, null, cells::add) @@ -274,7 +273,6 @@ private suspend fun layOutGraph( var maxY = 0.0 var lastLine: Int? = null for ((group, list) in groupedCells) { - @Suppress("UnstableApiUsage") checkCanceled() val (targetLeft, targetTop) = if (group.lineNumber == lastLine) { diff --git a/src/main/kotlin/platform/mixin/expression/gui/FlowGraph.kt b/src/main/kotlin/platform/mixin/expression/gui/FlowGraph.kt index e85651a1f..40e14251b 100644 --- a/src/main/kotlin/platform/mixin/expression/gui/FlowGraph.kt +++ b/src/main/kotlin/platform/mixin/expression/gui/FlowGraph.kt @@ -156,7 +156,6 @@ class FlowGraph(val groups: SortedSet, val flowMap: FlowMap, val allN if (!flow.isRoot) { continue } - @Suppress("UnstableApiUsage") checkCanceled() val node = FlowNode(flow, project, clazz, method, allNodes) From 90ec4b099575785984e30b731ff8b63b9aaf135e Mon Sep 17 00:00:00 2001 From: Kyle Wood Date: Sun, 29 Mar 2026 15:02:16 -0500 Subject: [PATCH 4/5] Updates for 2026.1 --- build.gradle.kts | 1 + gradle.properties | 4 +- gradle/libs.versions.toml | 4 +- .../kotlin/creator/buildsystem/maven-steps.kt | 4 +- .../GradlePluginSelectorCreatorProperty.kt | 4 +- .../creator/step/AbstractReformatFilesStep.kt | 4 +- src/main/kotlin/facet/MinecraftFacet.kt | 36 ++-------------- .../insight/generation/EventGenHelper.kt | 5 ++- .../fabric/reference/ResourceFileReference.kt | 6 +-- .../mcp/ct/CtCompletionContributor.kt | 4 +- .../VanillaGradleProjectResolverExtension.kt | 6 +-- .../platform/mixin/action/FindMixinsAction.kt | 8 ++-- .../mixin/debug/MixinPositionManager.kt | 9 ++-- .../MEExpressionCompletionContributor.kt | 4 +- .../expression/MEExpressionCompletionUtil.kt | 2 +- .../mixin/expression/gui/FlowStrings.kt | 4 +- .../MixinSoftImplementMethodSuperSearcher.kt | 6 +-- .../inspection/SpongeInjectionInspection.kt | 43 +++++++------------ ...ionExternalAnnotationsArtifactsResolver.kt | 6 +-- .../reference/TranslationReferenceSearch.kt | 6 +-- src/main/kotlin/util/utils.kt | 4 +- 21 files changed, 67 insertions(+), 103 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index eee767aa2..5fbc4478a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -116,6 +116,7 @@ dependencies { bundledPlugin("com.intellij.java") bundledPlugin("org.jetbrains.idea.maven") bundledPlugin("com.intellij.gradle") + bundledPlugin("org.jetbrains.idea.reposearch") bundledPlugin("org.intellij.groovy") bundledPlugin("ByteCodeViewer") bundledModule("intellij.platform.langInjection") diff --git a/gradle.properties b/gradle.properties index 53099b841..10bb9db8f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ # # https://mcdev.io/ # -# Copyright (C) 2025 minecraft-dev +# Copyright (C) 2026 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 @@ -21,7 +21,7 @@ # suppress inspection "UnusedProperty" for whole file org.gradle.jvmargs=-Xmx1g -ideaVersionName = 2025.3 +ideaVersionName = 2026.1 coreVersion = 1.8.12 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2308ef94a..3a9716b46 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # https://github.com/JetBrains/intellij-community/blob//.idea/libraries/kotlin_stdlib.xml -kotlin = "2.2.20" +kotlin = "2.3.20-RC2" # https://github.com/JetBrains/intellij-community/blob//.idea/libraries/kotlinx_coroutines_core.xml coroutines = "1.10.2" junit = "6.0.3" @@ -14,7 +14,7 @@ intellij-plugin = "2.13.1" intellij-plugin-repository-rest-client = "2.0.50" # https://www.jetbrains.com/intellij-repository/snapshots or https://www.jetbrains.com/intellij-repository/releases/ # Search for com.jetbrains.intellij.idea -intellij-ide = "253.29346.138" +intellij-ide = "261.22158.277" # https://github.com/JetBrains/gradle-idea-ext-plugin idea-ext = "1.4.1" diff --git a/src/main/kotlin/creator/buildsystem/maven-steps.kt b/src/main/kotlin/creator/buildsystem/maven-steps.kt index ec67c07aa..abc4598fe 100644 --- a/src/main/kotlin/creator/buildsystem/maven-steps.kt +++ b/src/main/kotlin/creator/buildsystem/maven-steps.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -195,7 +195,7 @@ class MavenImportStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(pa val templateConfig = mavenConfigFactory.createTemplateConfiguration(project) val runConfiguration = mavenConfigFactory.createConfiguration(runConfigName, templateConfig) as MavenRunConfiguration - runConfiguration.runnerParameters.goals.add(task) + runConfiguration.runnerParameters.goals = listOf(task) runConfiguration.runnerParameters.workingDirPath = context.projectDirectory.toString() runConfiguration.isAllowRunningInParallel = false diff --git a/src/main/kotlin/creator/custom/types/GradlePluginSelectorCreatorProperty.kt b/src/main/kotlin/creator/custom/types/GradlePluginSelectorCreatorProperty.kt index e0c81576c..6e84f395e 100644 --- a/src/main/kotlin/creator/custom/types/GradlePluginSelectorCreatorProperty.kt +++ b/src/main/kotlin/creator/custom/types/GradlePluginSelectorCreatorProperty.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -43,7 +43,7 @@ import com.intellij.ui.dsl.builder.bindItem import com.intellij.ui.dsl.builder.bindSelected import com.intellij.ui.dsl.builder.bindText import com.intellij.util.ui.AsyncProcessIcon -import fleet.multiplatform.shims.ConcurrentHashMap +import java.util.concurrent.ConcurrentHashMap import java.util.function.Function import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/src/main/kotlin/creator/step/AbstractReformatFilesStep.kt b/src/main/kotlin/creator/step/AbstractReformatFilesStep.kt index 276f43062..f983da0ce 100644 --- a/src/main/kotlin/creator/step/AbstractReformatFilesStep.kt +++ b/src/main/kotlin/creator/step/AbstractReformatFilesStep.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -50,7 +50,7 @@ abstract class AbstractReformatFilesStep(parent: NewProjectWizardStep) : Abstrac val rootDir = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) ?: return val psiManager = PsiManager.getInstance(project) - val files = ReadAction.compute, Throwable> { + val files = ReadAction.computeBlocking, Throwable> { filesToReformat.mapNotNull { path -> VfsUtil.findRelativeFile(rootDir, *path.split('/').toTypedArray())?.let(psiManager::findFile) }.toTypedArray() diff --git a/src/main/kotlin/facet/MinecraftFacet.kt b/src/main/kotlin/facet/MinecraftFacet.kt index 85e2ef560..f8898efd9 100644 --- a/src/main/kotlin/facet/MinecraftFacet.kt +++ b/src/main/kotlin/facet/MinecraftFacet.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -32,14 +32,12 @@ import com.demonwav.mcdev.util.runWriteActionAndWait import com.google.common.collect.HashMultimap import com.intellij.facet.Facet import com.intellij.facet.FacetManager +import com.intellij.facet.FacetType import com.intellij.facet.FacetTypeId import com.intellij.facet.FacetTypeRegistry import com.intellij.ide.projectView.ProjectView -import com.intellij.openapi.application.runReadAction import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleGrouper -import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiClass @@ -220,14 +218,14 @@ class MinecraftFacet( fun findFile(path: String, type: SourceType): VirtualFile? { try { return findFile0(path, type) - } catch (ignored: RefreshRootsException) { + } catch (_: RefreshRootsException) { } updateRoots() return try { findFile0(path, type) - } catch (ignored: RefreshRootsException) { + } catch (_: RefreshRootsException) { // Well we tried our best null } @@ -261,32 +259,6 @@ class MinecraftFacet( fun getInstance(module: Module) = FacetManager.getInstance(module).getFacetByType(ID) - fun getChildInstances(module: Module) = runReadAction run@{ - val instance = getInstance(module) - if (instance != null) { - return@run setOf(instance) - } - - val project = module.project - val manager = ModuleManager.getInstance(project) - val grouper = ModuleGrouper.instanceFor(project) - - val result = mutableSetOf() - - val modulePath = grouper.getModuleAsGroupPath(module) ?: return@run result - - for (m in manager.modules) { - val path = grouper.getGroupPath(m) - if (modulePath != path) { - continue - } - - val facet = getInstance(m) ?: continue - result.add(facet) - } - return@run result - } - fun getInstance(module: Module, type: AbstractModuleType) = getInstance(module)?.getModuleOfType(type) diff --git a/src/main/kotlin/insight/generation/EventGenHelper.kt b/src/main/kotlin/insight/generation/EventGenHelper.kt index 7a07f3d09..951bc143e 100644 --- a/src/main/kotlin/insight/generation/EventGenHelper.kt +++ b/src/main/kotlin/insight/generation/EventGenHelper.kt @@ -33,6 +33,7 @@ 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.K1Deprecation import org.jetbrains.kotlin.analysis.api.KaIdeApi import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferences import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferencesInRange @@ -114,7 +115,7 @@ class KotlinEventGenHelper : EventGenHelper { val entry = factory.createSuperTypeEntry(fqn) val insertedEntry = ktClass.addSuperTypeListEntry(entry) when (KotlinPluginModeProvider.currentPluginMode) { - KotlinPluginMode.K1 -> ShortenReferences.DEFAULT.process(insertedEntry) + KotlinPluginMode.K1 -> @OptIn(K1Deprecation::class) ShortenReferences.DEFAULT.process(insertedEntry) // TODO find a non-internal alternative to this... KotlinPluginMode.K2 -> @OptIn(KaIdeApi::class) shortenReferences(insertedEntry) } @@ -128,7 +129,7 @@ class KotlinEventGenHelper : EventGenHelper { val marker = JvmEventGenHelper.doReformat(project, file, startOffset, endOffset) ?: return when (KotlinPluginModeProvider.currentPluginMode) { - KotlinPluginMode.K1 -> ShortenReferences.DEFAULT.process(file, marker.startOffset, marker.endOffset) + KotlinPluginMode.K1 -> @OptIn(K1Deprecation::class) ShortenReferences.DEFAULT.process(file, marker.startOffset, marker.endOffset) // TODO find a non-internal alternative to this... KotlinPluginMode.K2 -> @OptIn(KaIdeApi::class) shortenReferencesInRange(file, marker.textRange) } diff --git a/src/main/kotlin/platform/fabric/reference/ResourceFileReference.kt b/src/main/kotlin/platform/fabric/reference/ResourceFileReference.kt index c6e243c53..0429b7c7e 100644 --- a/src/main/kotlin/platform/fabric/reference/ResourceFileReference.kt +++ b/src/main/kotlin/platform/fabric/reference/ResourceFileReference.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -27,7 +27,7 @@ import com.demonwav.mcdev.util.manipulator import com.demonwav.mcdev.util.mapFirstNotNull import com.demonwav.mcdev.util.reference.InspectionReference import com.intellij.json.psi.JsonStringLiteral -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.ModuleUtilCore @@ -98,7 +98,7 @@ class ResourceFileReference( } val variants = mutableListOf() - runReadAction { + runReadActionBlocking { val relevantModules = getRelevantModules() val relevantRootTypes = mutableSetOf(JavaResourceRootType.RESOURCE) diff --git a/src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt b/src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt index 6a4a2bdde..9d105e566 100644 --- a/src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt +++ b/src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt @@ -32,7 +32,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiDocumentManager import com.intellij.psi.TokenType @@ -61,7 +61,7 @@ private fun insertWhitespace(context: InsertionContext) { context.document.insertString(context.editor.caretModel.offset, " ") context.editor.caretModel.moveCaretRelatively(1, 0, false, false, false) context.setLaterRunnable { - runReadAction { + runReadActionBlocking { CodeCompletionHandlerBase.createHandler(CompletionType.BASIC) .invokeCompletion(context.project, context.editor) } diff --git a/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleProjectResolverExtension.kt b/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleProjectResolverExtension.kt index cd2d4c057..9f13bfbb5 100644 --- a/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleProjectResolverExtension.kt +++ b/src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleProjectResolverExtension.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -21,7 +21,7 @@ package com.demonwav.mcdev.platform.mcp.vanillagradle import com.demonwav.mcdev.platform.mcp.gradle.tooling.vanillagradle.VanillaGradleModel -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.openapi.externalSystem.model.DataNode import com.intellij.openapi.externalSystem.model.project.ModuleData import org.gradle.tooling.model.idea.IdeaModule @@ -35,7 +35,7 @@ class VanillaGradleProjectResolverExtension : AbstractProjectResolverExtension() override fun getToolingExtensionsClasses() = extraProjectModelClasses override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode) { - val vgData = runReadAction { + val vgData = runReadActionBlocking { resolverCtx.getExtraProject(gradleModule, VanillaGradleModel::class.java) } if (vgData != null && vgData.hasVanillaGradle()) { diff --git a/src/main/kotlin/platform/mixin/action/FindMixinsAction.kt b/src/main/kotlin/platform/mixin/action/FindMixinsAction.kt index 27ddfb92f..25183c92e 100644 --- a/src/main/kotlin/platform/mixin/action/FindMixinsAction.kt +++ b/src/main/kotlin/platform/mixin/action/FindMixinsAction.kt @@ -33,7 +33,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys.CARET import com.intellij.openapi.actionSystem.CommonDataKeys.PROJECT import com.intellij.openapi.actionSystem.CommonDataKeys.PSI_FILE import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.runBackgroundableTask import com.intellij.openapi.project.Project @@ -89,13 +89,13 @@ class FindMixinsAction : AnAction() { runBackgroundableTask("Searching for Mixins", project, true) run@{ indicator -> indicator.isIndeterminate = true - val classes = runReadAction { + val classes = runReadActionBlocking { if (!targetClass.isValid) { - return@runReadAction null + return@runReadActionBlocking null } val classes = findMixins(targetClass, project, indicator)?.filter(filter) - ?: return@runReadAction null + ?: return@runReadActionBlocking null when (classes.size) { 0 -> null diff --git a/src/main/kotlin/platform/mixin/debug/MixinPositionManager.kt b/src/main/kotlin/platform/mixin/debug/MixinPositionManager.kt index 20d14e910..e870e38e6 100644 --- a/src/main/kotlin/platform/mixin/debug/MixinPositionManager.kt +++ b/src/main/kotlin/platform/mixin/debug/MixinPositionManager.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -33,7 +33,7 @@ import com.intellij.debugger.engine.PositionManagerImpl.ClsSourcePosition import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.debugger.requests.ClassPrepareRequestor import com.intellij.ide.highlighter.JavaFileType -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFileManager @@ -47,6 +47,7 @@ import com.sun.jdi.request.ClassPrepareRequest class MixinPositionManager(private val debugProcess: DebugProcess) : MultiRequestPositionManager { + @Deprecated("Deprecated in Java") override fun getAcceptedFileTypes(): Set = setOf(JavaFileType.INSTANCE) @Throws(NoDataException::class) @@ -106,7 +107,7 @@ class MixinPositionManager(private val debugProcess: DebugProcess) : MultiReques } override fun getAllClasses(classPosition: SourcePosition): List { - return runReadAction { + return runReadActionBlocking { findMatchingClasses(classPosition) .flatMap { name -> debugProcess.virtualMachineProxy.classesByName(name).asSequence() } .toList() @@ -137,7 +138,7 @@ class MixinPositionManager(private val debugProcess: DebugProcess) : MultiReques requestor: ClassPrepareRequestor, position: SourcePosition, ): List { - return runReadAction { + return runReadActionBlocking { findMatchingClasses(position) .mapNotNull { name -> debugProcess.requestsManager.createClassPrepareRequest(requestor, name) } .toList() diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionContributor.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionContributor.kt index 12b810172..633dc5688 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionContributor.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionContributor.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -126,7 +126,7 @@ class MEExpressionCompletionContributor : CompletionContributor() { BasicExpressionCompletionContributor.createKeywordLookupItem(parameters.position, keyword.name) if (keyword.tailType != TailTypes.noneType()) { lookupItem = object : TailTypeDecorator(lookupItem) { - override fun computeTailType(context: InsertionContext?) = keyword.tailType + override fun computeTailType(context: InsertionContext) = keyword.tailType } } lookupItem diff --git a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt index c85d14ac4..4d20d1990 100644 --- a/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt +++ b/src/main/kotlin/platform/mixin/expression/MEExpressionCompletionUtil.kt @@ -1063,7 +1063,7 @@ object MEExpressionCompletionUtil { ) private fun LookupElement.withTail(tailType: TailType?) = object : TailTypeDecorator(this) { - override fun computeTailType(context: InsertionContext?) = tailType + override fun computeTailType(context: InsertionContext) = tailType } private fun LookupElementBuilder.withDefinition(id: String, definitionValue: String) = diff --git a/src/main/kotlin/platform/mixin/expression/gui/FlowStrings.kt b/src/main/kotlin/platform/mixin/expression/gui/FlowStrings.kt index 2dec83ba6..77fbaca91 100644 --- a/src/main/kotlin/platform/mixin/expression/gui/FlowStrings.kt +++ b/src/main/kotlin/platform/mixin/expression/gui/FlowStrings.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -128,7 +128,7 @@ private fun varString(flow: FlowValue, index: Int, project: Project, clazz: Clas if (location.opcode in Opcodes.ISTORE..Opcodes.ASTORE) { location = location.next } - val localName = ReadAction.compute<_, Nothing> { + val localName = ReadAction.computeBlocking<_, Nothing> { runCatching { LocalVariables.getLocalVariableAt(project, clazz, method, location, index) }.getOrNull() diff --git a/src/main/kotlin/platform/mixin/search/MixinSoftImplementMethodSuperSearcher.kt b/src/main/kotlin/platform/mixin/search/MixinSoftImplementMethodSuperSearcher.kt index 8f4879a8d..a6f1a06e9 100644 --- a/src/main/kotlin/platform/mixin/search/MixinSoftImplementMethodSuperSearcher.kt +++ b/src/main/kotlin/platform/mixin/search/MixinSoftImplementMethodSuperSearcher.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -21,7 +21,7 @@ package com.demonwav.mcdev.platform.mixin.search import com.demonwav.mcdev.platform.mixin.util.forEachSoftImplementedMethods -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.psi.CommonClassNames import com.intellij.psi.PsiModifier import com.intellij.psi.search.searches.SuperMethodsSearch @@ -46,7 +46,7 @@ class MixinSoftImplementMethodSuperSearcher : // This is very simple and probably doesn't handle all cases // Right now we simply check for @Implements annotation on the class and look // for a similar method in the interface - runReadAction run@{ + runReadActionBlocking run@{ if (!method.name.contains('$') || method.hasModifierProperty(PsiModifier.STATIC)) { return@run true } diff --git a/src/main/kotlin/platform/sponge/inspection/SpongeInjectionInspection.kt b/src/main/kotlin/platform/sponge/inspection/SpongeInjectionInspection.kt index 251eda05f..1e8d883e2 100644 --- a/src/main/kotlin/platform/sponge/inspection/SpongeInjectionInspection.kt +++ b/src/main/kotlin/platform/sponge/inspection/SpongeInjectionInspection.kt @@ -38,6 +38,7 @@ import com.intellij.codeInspection.LocalQuickFixOnPsiElement import com.intellij.codeInspection.ProblemDescriptor import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder +import com.intellij.codeInspection.options.OptPane import com.intellij.ide.util.PackageUtil import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.module.Module @@ -59,17 +60,12 @@ import com.intellij.psi.PsiVariable import com.intellij.psi.createSmartPointer import com.intellij.psi.impl.source.PsiClassReferenceType import com.siyeh.ig.BaseInspection -import com.siyeh.ig.BaseInspection.formatString -import com.siyeh.ig.ui.UiUtils -import javax.swing.JComponent import org.jdom.Element class SpongeInjectionInspection : AbstractBaseJavaLocalInspectionTool() { - private val injectableTypesList = Const.defaultInjectableTypes.toMutableList() - @JvmField - var injectableTypes: String = Const.serializedDefaultInjectableTypes + var injectableTypesList = Const.defaultInjectableTypes.toMutableList() override fun getStaticDescription() = "Invalid @Inject usage in Sponge plugin class." @@ -358,8 +354,6 @@ class SpongeInjectionInspection : AbstractBaseJavaLocalInspectionTool() { "org.bstats.sponge.MetricsLite2.Factory", "org.bstats.sponge.Metrics2.Factory", ) - - val serializedDefaultInjectableTypes: String = formatString(defaultInjectableTypes) } class RemoveAnnotationParameters(annotation: PsiAnnotation, val txt: String) : @@ -468,28 +462,23 @@ class SpongeInjectionInspection : AbstractBaseJavaLocalInspectionTool() { } } - override fun createOptionsPanel(): JComponent? { - val chooserList = UiUtils.createTreeClassChooserList( - injectableTypesList, - "Injectable types", - "Choose Injectable Type", - ) - UiUtils.setComponentSize(chooserList, 7, 25) - return chooserList - } + override fun getOptionsPane(): OptPane = OptPane.pane( + OptPane.stringList("injectableTypesList", "Injectable types") + ) override fun readSettings(node: Element) { + val hasNewFormat = node.getChildren("option").any { it.getAttributeValue("name") == "injectableTypesList" } super.readSettings(node) - BaseInspection.parseString(injectableTypes, injectableTypesList) - } - - override fun writeSettings(node: Element) { - injectableTypes = if (injectableTypesList.isEmpty()) { - Const.serializedDefaultInjectableTypes - } else { - formatString(injectableTypesList) + if (!hasNewFormat) { + for (child in node.getChildren("option")) { + if (child.getAttributeValue("name") == "injectableTypes") { + val value = child.getAttributeValue("value") + if (!value.isNullOrEmpty()) { + injectableTypesList.clear() + BaseInspection.parseString(value, injectableTypesList) + } + } + } } - - super.writeSettings(node) } } diff --git a/src/main/kotlin/translations/identification/TranslationExternalAnnotationsArtifactsResolver.kt b/src/main/kotlin/translations/identification/TranslationExternalAnnotationsArtifactsResolver.kt index e0920176c..4f72d2ea2 100644 --- a/src/main/kotlin/translations/identification/TranslationExternalAnnotationsArtifactsResolver.kt +++ b/src/main/kotlin/translations/identification/TranslationExternalAnnotationsArtifactsResolver.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -26,7 +26,7 @@ import com.intellij.codeInsight.ExternalAnnotationsArtifactsResolver import com.intellij.codeInsight.externalAnnotation.location.AnnotationsLocation import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.project.Project @@ -119,7 +119,7 @@ class TranslationExternalAnnotationsArtifactsResolver : ExternalAnnotationsArtif return false } - val annotationsPath = runReadAction { findAnnotationsPath(false) ?: findAnnotationsPath(true) } + val annotationsPath = runReadActionBlocking { findAnnotationsPath(false) ?: findAnnotationsPath(true) } ?: return false val editor = ExistingLibraryEditor(library, null) diff --git a/src/main/kotlin/translations/reference/TranslationReferenceSearch.kt b/src/main/kotlin/translations/reference/TranslationReferenceSearch.kt index b376c2761..e3f506016 100644 --- a/src/main/kotlin/translations/reference/TranslationReferenceSearch.kt +++ b/src/main/kotlin/translations/reference/TranslationReferenceSearch.kt @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 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 @@ -23,7 +23,7 @@ package com.demonwav.mcdev.translations.reference import com.demonwav.mcdev.translations.TranslationFiles import com.intellij.find.FindModel import com.intellij.find.impl.FindInProjectUtil -import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.application.runReadActionBlocking import com.intellij.psi.PsiElement import com.intellij.psi.PsiReference import com.intellij.psi.search.searches.ReferencesSearch @@ -41,7 +41,7 @@ class TranslationReferenceSearch : QueryExecutor PsiFile.applyWriteAction(crossinline func: PsiFile.() -> T): T { fun runReadActionAsync(runnable: () -> T): Promise { return runAsync { - runReadAction(runnable) + runReadActionBlocking(runnable) } } From 2afc669dc7c56d9fe156ecede6e3fd013c166571 Mon Sep 17 00:00:00 2001 From: Desert_Gamer Date: Wed, 15 Apr 2026 01:04:40 +0300 Subject: [PATCH 5/5] Fix Write-unsafe context error in refreshSync during New Project dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RefreshSessionImpl asserts a write-safe context in its constructor via TransactionGuard. When refreshSync was called from a coroutine dispatched inside a modal dialog (New Project wizard), TransactionGuard rejected the call with "Write-unsafe context!" because the modality state of the dialog did not satisfy the write-safe context requirements. The previous implementation wrapped RefreshQueue.refresh in a writeAction, which did not help — the assertion fires at RefreshSession creation time, before any write lock is acquired. Fix: schedule the RefreshQueue.refresh call via ApplicationManager.invokeLater with the correct ModalityState. This ensures TransactionGuard sees a write-safe context when RefreshSessionImpl is constructed. A suspendCancellableCoroutine is used to await completion without blocking EDT. --- src/main/kotlin/util/files.kt | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/util/files.kt b/src/main/kotlin/util/files.kt index 3743fe684..2321afbdc 100644 --- a/src/main/kotlin/util/files.kt +++ b/src/main/kotlin/util/files.kt @@ -33,6 +33,8 @@ import java.nio.file.Path import java.util.jar.Attributes import java.util.jar.JarFile import java.util.jar.Manifest +import kotlin.coroutines.resume +import kotlinx.coroutines.suspendCancellableCoroutine val VirtualFile.localFile: File get() = VfsUtilCore.virtualToIoFile(this) @@ -80,17 +82,20 @@ operator fun Manifest.get(attribute: String): String? = mainAttributes.getValue( operator fun Manifest.get(attribute: Attributes.Name): String? = mainAttributes.getValue(attribute) suspend fun VirtualFile.refreshSync(modalityState: ModalityState): VirtualFile? { - fun refresh() { - RefreshQueue.getInstance().refresh(false, this.isDirectory, null, modalityState, this) + // RefreshSessionImpl asserts a write-safe context in its constructor, which fails when called + // from a modal dialog's dispatched coroutine. We schedule the refresh via invokeLater with + // the correct ModalityState so TransactionGuard sees a write-safe context. + suspendCancellableCoroutine { cont -> + ApplicationManager.getApplication().invokeLater( + { + RefreshQueue.getInstance().refresh(false, this.isDirectory, null, modalityState, this) + cont.resume(Unit) + }, + modalityState, + ) } - if (ApplicationManager.getApplication().isWriteAccessAllowed) { - refresh() - } else { - writeAction { - refresh() - } + return writeAction { + this@refreshSync.parent?.findOrCreateChildData(this@refreshSync, this@refreshSync.name) } - - return this.parent?.findOrCreateChildData(this, this.name) }