[devkit] IJPL-210990 Compose UI Preview internal failure when running a preview of Chat Sample App

GitOrigin-RevId: 8e9910241d9af11da86517001d2ecd0a9cce6f6b
This commit is contained in:
Yuriy Artamonov
2025-12-23 18:14:53 +00:00
committed by intellij-monorepo-bot
parent 0ef938a6e3
commit 10e7d4988c
4 changed files with 33 additions and 10 deletions
+7 -1
View File
@@ -5,6 +5,7 @@ package com.intellij.ui
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.DevTimeClassLoader
import com.intellij.openapi.components.service
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.util.registry.EarlyAccessRegistryManager
@@ -54,7 +55,12 @@ abstract class ExperimentalUI {
fun getInstance(): ExperimentalUI = ApplicationManager.getApplication().service<ExperimentalUI>()
@JvmStatic
fun isNewUI(): Boolean = NewUiValue.isEnabled()
fun isNewUI(): Boolean {
// always true for development time tools, e.g., in Compose UI Preview
if (Thread.currentThread().contextClassLoader is DevTimeClassLoader) return true
return NewUiValue.isEnabled()
}
val isNewNavbar: Boolean
get() = NewUiValue.isEnabled() && Registry.`is`("ide.experimental.ui.navbar.scroll", true)
@@ -83,7 +83,7 @@ internal suspend fun compileCode(fileToCompile: VirtualFile, project: Project):
.toTypedArray()
val pluginByClass = PluginManager.getPluginByClass(ComposePreviewToolWindowFactory::class.java)
val filteringClassLoader = FilteringClassLoader(pluginByClass!!.classLoader)
val filteringClassLoader = FilteringClassLoader(pluginByClass!!.pluginClassLoader!!)
val loader = ComposeUIPreviewClassLoader(diskPaths, filteringClassLoader)
val functions = ComposableFunctionFinder(loader).findPreviewFunctions(analysis.targetClassName, analysis.composableMethodNames)
@@ -6,6 +6,7 @@ import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.fileEditor.*
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
@@ -80,7 +81,12 @@ internal class ComposePreviewChangesTracker(val project: Project, val coroutineS
FileDocumentManager.getInstance().saveAllDocuments()
}
processor(virtualFile)
try {
processor(virtualFile)
}
catch (e: Throwable) {
thisLogger().error("Error during Compose UI Preview refresh chain", e)
}
}
}
}
@@ -9,7 +9,7 @@ import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.application.UI
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.getUserData
@@ -27,6 +27,8 @@ import javax.swing.JComponent
internal const val TOOLWINDOW_ID = "ComposeUIPreview"
private val LOG = fileLogger()
internal class ComposePreviewToolWindowFactory : ToolWindowFactory, DumbAware {
override fun shouldBeAvailable(project: Project): Boolean {
@@ -47,6 +49,8 @@ internal class ComposePreviewToolWindowFactory : ToolWindowFactory, DumbAware {
toolWindow.setTitleActions(titleActionsGroup.getChildren(actionManager).toList())
project.service<ComposePreviewChangesTracker>().startTracking(project, toolWindowContent) { virtualFile ->
LOG.debug("New incoming change for preview $virtualFile")
val oldContent = withContext(Dispatchers.UI) {
val current = wrapperPanel.components.firstOrNull()
wrapperPanel.setPaintBusy(true)
@@ -58,7 +62,7 @@ internal class ComposePreviewToolWindowFactory : ToolWindowFactory, DumbAware {
compileCode(virtualFile, project)
}
catch (e: Throwable) {
thisLogger().warn("Unable to compile code for preview", e)
LOG.warn("Unable to compile code for preview of $virtualFile", e)
return@startTracking
}
finally {
@@ -78,19 +82,26 @@ internal class ComposePreviewToolWindowFactory : ToolWindowFactory, DumbAware {
}
withContext(Dispatchers.UI) {
LOG.debug("Apply new UI preview for $virtualFile")
// free up the previous content JVM classes, register new
try {
wrapperPanel.getUserData(PROVIDER_KEY)?.classLoader?.close()
}
catch (e: Exception) {
thisLogger().warn("Unable to release classloader for UI preview", e)
LOG.warn("Unable to release classloader for UI preview", e)
}
wrapperPanel.putUserData(PROVIDER_KEY, provider)
wrapperPanel.setPaintBusy(false)
wrapperPanel.setContent(compose(focusOnClickInside = true) {
provider.build(currentComposer, currentCompositeKeyHashCode)
})
try {
wrapperPanel.setContent(compose(focusOnClickInside = true) {
provider.build(currentComposer, currentCompositeKeyHashCode)
})
}
catch (e: Exception) {
LOG.error("Unable to apply content for UI preview of $virtualFile", e)
}
}
}
}