Skip to content

Commit

Permalink
Update facets in a background task
Browse files Browse the repository at this point in the history
Fixes long UI freezes on huge projects with many modules/libraries

Had to unbundle two coroutines libraries because they were conflicting
 with the platform's bundled library (likely because of the different
  classloaders)
  • Loading branch information
RedNesto committed Nov 7, 2023
1 parent c0544a7 commit bd54763
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 25 deletions.
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ dependencies {
// Kotlin
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation(libs.bundles.coroutines)
implementation(libs.bundles.coroutines) {
exclude(module = "kotlinx-coroutines-core-jvm")
}

implementation(files(gradleToolingExtensionJar))

Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ junit-entine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" }

[bundles]
coroutines = ["coroutines-core", "coroutines-jdk8", "coroutines-swing"]
coroutines = ["coroutines-swing"]
asm = ["asm", "asm-tree", "asm-analysis"]
fuel = ["fuel", "fuel-coroutines"]
23 changes: 13 additions & 10 deletions src/main/kotlin/facet/MinecraftFacet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ 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.runWriteActionAndWait
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleGrouper
import com.intellij.openapi.module.ModuleManager
Expand Down Expand Up @@ -122,17 +123,19 @@ class MinecraftFacet(
roots.clear()
val rootManager = ModuleRootManager.getInstance(module)

rootManager.contentEntries.asSequence()
.flatMap { entry -> entry.sourceFolders.asSequence() }
.filterNotNull { it.file }
.forEach {
when (it.rootType) {
JavaSourceRootType.SOURCE -> roots.put(SourceType.SOURCE, it.file)
JavaSourceRootType.TEST_SOURCE -> roots.put(SourceType.TEST_SOURCE, it.file)
JavaResourceRootType.RESOURCE -> roots.put(SourceType.RESOURCE, it.file)
JavaResourceRootType.TEST_RESOURCE -> roots.put(SourceType.TEST_RESOURCE, it.file)
runWriteActionAndWait {
rootManager.contentEntries.asSequence()
.flatMap { entry -> entry.sourceFolders.asSequence() }
.filterNotNull { it.file }
.forEach {
when (it.rootType) {
JavaSourceRootType.SOURCE -> roots.put(SourceType.SOURCE, it.file)
JavaSourceRootType.TEST_SOURCE -> roots.put(SourceType.TEST_SOURCE, it.file)
JavaResourceRootType.RESOURCE -> roots.put(SourceType.RESOURCE, it.file)
JavaResourceRootType.TEST_RESOURCE -> roots.put(SourceType.TEST_RESOURCE, it.file)
}
}
}
}
}

private fun register(type: AbstractModuleType<*>): AbstractModule {
Expand Down
53 changes: 40 additions & 13 deletions src/main/kotlin/facet/MinecraftFacetDetector.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ import com.demonwav.mcdev.util.runWriteTaskLater
import com.intellij.facet.FacetManager
import com.intellij.facet.impl.ui.libraries.LibrariesValidatorContextImpl
import com.intellij.framework.library.LibraryVersionProperties
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.runWriteActionAndWait
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
Expand All @@ -41,11 +45,17 @@ import com.intellij.openapi.roots.libraries.LibraryDetectionManager
import com.intellij.openapi.roots.libraries.LibraryKind
import com.intellij.openapi.roots.libraries.LibraryProperties
import com.intellij.openapi.roots.ui.configuration.libraries.LibraryPresentationManager
import com.intellij.openapi.startup.StartupActivity
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.util.Key
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.intellij.platform.util.progress.forEachWithProgress
import com.intellij.util.application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.jetbrains.plugins.gradle.util.GradleUtil

class MinecraftFacetDetector : StartupActivity {
class MinecraftFacetDetector : ProjectActivity {
companion object {
private val libraryVersionsKey = Key<MutableMap<LibraryKind, String>>("mcdev.libraryVersions")

Expand All @@ -54,37 +64,54 @@ class MinecraftFacetDetector : StartupActivity {
}
}

override fun runActivity(project: Project) {
MinecraftModuleRootListener.doCheck(project)
override suspend fun execute(project: Project) {
withBackgroundProgress(project, "Detecting Minecraft Frameworks", cancellable = false) {
MinecraftModuleRootListener.doCheck(project)
}
}

@Service(Service.Level.PROJECT)
private class FacetDetectorScopeProvider(val scope: CoroutineScope)

private object MinecraftModuleRootListener : ModuleRootListener {
override fun rootsChanged(event: ModuleRootEvent) {
if (event.isCausedByFileTypesChange) {
return
}

val project = event.source as? Project ?: return
doCheck(project)
project.service<FacetDetectorScopeProvider>().scope.launch(Dispatchers.EDT) {
withBackgroundProgress(project, "Detecting Minecraft Frameworks", cancellable = false) {
doCheck(project)
}
}
}

fun doCheck(project: Project) {
suspend fun doCheck(project: Project) {
val moduleManager = ModuleManager.getInstance(project)

var needsReimport = false

for (module in moduleManager.modules) {
moduleManager.modules.asList().forEachWithProgress(false) { module ->
val facetManager = FacetManager.getInstance(module)
val minecraftFacet = facetManager.getFacetByType(MinecraftFacet.ID)

if (minecraftFacet == null) {
checkNoFacet(module)
} else {
checkExistingFacet(module, minecraftFacet)
if (ProjectReimporter.needsReimport(minecraftFacet)) {
needsReimport = true
val action = {
if (minecraftFacet == null) {
checkNoFacet(module)
} else {
checkExistingFacet(module, minecraftFacet)
if (ProjectReimporter.needsReimport(minecraftFacet)) {
needsReimport = true
}
}
}

if (application.isUnitTestMode) {
action()
} else {
runWriteActionAndWait(action)
}
}

if (needsReimport) {
Expand Down

0 comments on commit bd54763

Please sign in to comment.