diff --git a/platform/xdebugger-impl/frontend/resources/intellij.platform.debugger.impl.frontend.xml b/platform/xdebugger-impl/frontend/resources/intellij.platform.debugger.impl.frontend.xml index 33be8b48db0c..fd6c25ff8e4a 100644 --- a/platform/xdebugger-impl/frontend/resources/intellij.platform.debugger.impl.frontend.xml +++ b/platform/xdebugger-impl/frontend/resources/intellij.platform.debugger.impl.frontend.xml @@ -10,6 +10,8 @@ + diff --git a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendDescriptorStateManager.kt b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendDescriptorStateManager.kt new file mode 100644 index 000000000000..0a14acff90f9 --- /dev/null +++ b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendDescriptorStateManager.kt @@ -0,0 +1,50 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.debugger.impl.frontend + +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.project.Project +import com.intellij.xdebugger.frame.XDescriptor +import fleet.multiplatform.shims.ConcurrentHashMap +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.job +import org.jetbrains.annotations.ApiStatus + +/** + * Creates a plugin-specific state for a given [XDescriptor]. + * For example, if a [XDescriptor] contains a flow, this extension should create an object which will keep the flow's state. + */ +@ApiStatus.Internal +interface FrontendDescriptorStateManagerExtension { + fun createState(descriptor: XDescriptor, cs: CoroutineScope): Any? + + companion object { + private val EP_NAME = ExtensionPointName.create("com.intellij.xdebugger.descriptorStateManager") + + fun createState(descriptor: XDescriptor, cs: CoroutineScope): Any? { + return EP_NAME.extensionList.firstNotNullOfOrNull { it.createState(descriptor, cs) } + } + } +} + +@ApiStatus.Internal +@Service(Service.Level.PROJECT) +class FrontendDescriptorStateManager { + private val states = ConcurrentHashMap() + + internal fun registerDescriptor(descriptor: XDescriptor, cs: CoroutineScope) { + val state = FrontendDescriptorStateManagerExtension.createState(descriptor, cs) ?: return + states[descriptor] = state + cs.coroutineContext.job.invokeOnCompletion { states.remove(descriptor) } + } + + fun getState(descriptor: XDescriptor): Any? { + return states[descriptor] + } + + companion object { + @JvmStatic + fun getInstance(project: Project): FrontendDescriptorStateManager = project.service() + } +} diff --git a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt index 6fcfc4a6d94c..bc4c7fa4ef81 100644 --- a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt +++ b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.util.NlsSafe +import com.intellij.platform.debugger.impl.frontend.FrontendDescriptorStateManager import com.intellij.platform.debugger.impl.rpc.* import com.intellij.platform.util.coroutines.childScope import com.intellij.util.ConcurrencyUtil @@ -38,6 +39,13 @@ class FrontendXValue private constructor( private val presentation: StateFlow, ) : XValue(), XValueTextProvider { + init { + cs.launch { + val descriptor = xValueDto.descriptor?.await() ?: return@launch + FrontendDescriptorStateManager.getInstance(project).registerDescriptor(descriptor, cs) + } + } + @Volatile private var modifier: XValueModifier? = null