diff --git a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendXDebugManagerProxy.kt b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendXDebugManagerProxy.kt index 93df0274792f..ef3d1fcb5962 100644 --- a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendXDebugManagerProxy.kt +++ b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/FrontendXDebugManagerProxy.kt @@ -46,6 +46,9 @@ private class FrontendXDebugManagerProxy : XDebugManagerProxy { override fun getXValueId(value: XValue): XValueId? = FrontendXValue.asFrontendXValueOrNull(value)?.xValueDto?.id + override fun getXExecutionStackId(stack: XExecutionStack): XExecutionStackId? = + (stack as? FrontendXExecutionStack)?.id + override suspend fun withId(stack: XExecutionStack, session: XDebugSessionProxy, block: suspend (XExecutionStackId) -> T): T { val executionStackId = (stack as FrontendXExecutionStack).id return block(executionStackId) diff --git a/platform/xdebugger-impl/resources/META-INF/xdebugger.xml b/platform/xdebugger-impl/resources/META-INF/xdebugger.xml index 74eb7989ce01..69774ac5ded1 100644 --- a/platform/xdebugger-impl/resources/META-INF/xdebugger.xml +++ b/platform/xdebugger-impl/resources/META-INF/xdebugger.xml @@ -181,6 +181,7 @@ + UAST diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/MonolithXDebugManagerProxy.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/MonolithXDebugManagerProxy.kt index 549b7b894bdc..646712e69090 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/MonolithXDebugManagerProxy.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/MonolithXDebugManagerProxy.kt @@ -43,6 +43,9 @@ private class MonolithXDebugManagerProxy : XDebugManagerProxy { // This method is not supported in monolith mode override fun getXValueId(value: XValue): XValueId? = null + // This method is not supported in monolith mode + override fun getXExecutionStackId(stack: XExecutionStack): XExecutionStackId? = null + override suspend fun withId(stack: XExecutionStack, session: XDebugSessionProxy, block: suspend (XExecutionStackId) -> T): T { val sessionImpl = (session as XDebugSessionProxy.Monolith).sessionImpl return withCoroutineScopeForId(block) { scope -> diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugManagerProxy.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugManagerProxy.kt index 69440795a83f..a86527e472f4 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugManagerProxy.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugManagerProxy.kt @@ -61,6 +61,14 @@ interface XDebugManagerProxy { */ fun getXValueId(value: XValue): XValueId? + /** + * Gets ID of the given [stack]. + * + * This method is used in split mode to pass the ID of the execution stack from frontend to backend. + * It's not supported in monolith mode. + */ + fun getXExecutionStackId(stack: XExecutionStack): XExecutionStackId? + companion object { private val EP_NAME = ExtensionPointName.create("com.intellij.xdebugger.managerProxy") diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerThreadsList.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerThreadsList.kt index 25ed71c3d5ed..2ec72f52cffe 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerThreadsList.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerThreadsList.kt @@ -12,6 +12,8 @@ import com.intellij.ui.popup.list.GroupedItemsListRenderer import com.intellij.xdebugger.XDebuggerBundle import com.intellij.xdebugger.frame.XExecutionStack import com.intellij.xdebugger.frame.XExecutionStack.AdditionalDisplayInfo +import com.intellij.xdebugger.impl.frame.XDebugManagerProxy.Companion.getInstance +import com.intellij.xdebugger.impl.ui.SplitDebuggerUIUtil import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.Nls import java.awt.Component @@ -61,10 +63,19 @@ class XDebuggerThreadsList( override fun uiDataSnapshot(sink: DataSink) { sink[THREADS_LIST] = this stackUnderMouse?.stack?.let { - sink[XExecutionStack.SELECTED_STACKS] = listOf(it) + setSelectedStacks(sink, it) } } + private fun setSelectedStacks(sink: DataSink, selection: XExecutionStack) { + val xDebugManagerProxy = getInstance() + val xExecutionStackId = xDebugManagerProxy.getXExecutionStackId(selection) + if (xExecutionStackId != null) { + sink[SplitDebuggerUIUtil.SPLIT_SELECTED_STACKS_KEY] = listOf(xExecutionStackId) + } + sink[XExecutionStack.SELECTED_STACKS] = listOf(selection) + } + private fun doInit() { selectionModel.selectionMode = ListSelectionModel.SINGLE_SELECTION cellRenderer = renderer diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/SplitDebuggerUIUtil.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/SplitDebuggerUIUtil.kt index 23bf23d26f9f..c4fa5853c448 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/SplitDebuggerUIUtil.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/SplitDebuggerUIUtil.kt @@ -5,12 +5,18 @@ import com.intellij.execution.RunContentDescriptorIdImpl import com.intellij.execution.findContentValue import com.intellij.execution.runners.ExecutionEnvironment import com.intellij.execution.ui.RunContentDescriptor +import com.intellij.frontend.FrontendApplicationInfo.getFrontendType +import com.intellij.frontend.FrontendType import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataKey import com.intellij.openapi.actionSystem.ExecutionDataKeys import com.intellij.openapi.actionSystem.LangDataKeys +import com.intellij.openapi.diagnostic.Logger import com.intellij.platform.debugger.impl.rpc.XDebuggerTreeSelectedValueId +import com.intellij.platform.debugger.impl.rpc.XExecutionStackId import com.intellij.xdebugger.SplitDebuggerMode +import com.intellij.xdebugger.SplitDebuggerMode.showSplitWarnings +import com.intellij.xdebugger.frame.XExecutionStack import com.intellij.xdebugger.frame.XValue import com.intellij.xdebugger.impl.rpc.ExecutionEnvironmentId import com.intellij.xdebugger.impl.rpc.models.BackendXValueModel @@ -30,6 +36,14 @@ object SplitDebuggerUIUtil { @JvmField internal val SPLIT_SELECTED_VALUES_KEY: DataKey> = DataKey.create("split.xdebugger.tree.selected.values") + /** + * This key is used to pass ids of [XExecutionStack]s corresponding to the selected stacks in the tree from frontend to backend. + */ + @JvmField + internal val SPLIT_SELECTED_STACKS_KEY: DataKey> = DataKey.create("split.xExecutionStack.selected.stacks") + + private val LOG: Logger = Logger.getInstance(SplitDebuggerUIUtil::class.java) + @JvmStatic fun getRunContentDescriptor(dataContext: DataContext): RunContentDescriptor? { LangDataKeys.RUN_CONTENT_DESCRIPTOR.getData(dataContext)?.let { return it } @@ -44,6 +58,10 @@ object SplitDebuggerUIUtil { @JvmStatic fun getXDebuggerTreeSelectedBackendValues(dataContext: DataContext): List { + if (showSplitWarnings() && getFrontendType() is FrontendType.Remote) { + LOG.error("SplitDebuggerUIUtil#getXDebuggerTreeSelectedBackendValues should not be called from the frontend. " + + "Please use XDebuggerTree.SELECTED_NODES#getData instead.") + } return if (SplitDebuggerMode.isSplitDebugger()) { // In Split mode, find backend values by the ids passed from the frontend SPLIT_SELECTED_VALUES_KEY.getData(dataContext)?.mapNotNull { (xValueId, name) -> @@ -57,4 +75,21 @@ object SplitDebuggerUIUtil { } ?: emptyList() } } + + @JvmStatic + fun getSelectedBackendXExecutionStacks(dataContext: DataContext): List { + if (showSplitWarnings() && getFrontendType() is FrontendType.Remote) { + LOG.error("SplitDebuggerUIUtil#getSelectedBackendXExecutionStacks should not be called from the frontend. " + + "Please use XExecutionStack.SELECTED_STACKS#getData instead.") + } + return if (SplitDebuggerMode.isSplitDebugger()) { + // In Split mode, find backend XExecutionStacks by the ids passed from the frontend + SPLIT_SELECTED_STACKS_KEY.getData(dataContext)?.mapNotNull { xExecutionStackId -> + xExecutionStackId.findValue()?.executionStack + } + } else { + // If Split mode is disabled, SELECTED_STACKS contains backend values + XExecutionStack.SELECTED_STACKS.getData(dataContext) + } ?: emptyList() + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/keysSerialization.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/keysSerialization.kt index 790145ae5324..a0a7eba07c73 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/keysSerialization.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/keysSerialization.kt @@ -5,6 +5,7 @@ import com.intellij.execution.RunContentDescriptorIdImpl import com.intellij.ide.CustomDataContextSerializer import com.intellij.openapi.actionSystem.DataKey import com.intellij.platform.debugger.impl.rpc.XDebuggerTreeSelectedValueId +import com.intellij.platform.debugger.impl.rpc.XExecutionStackId import com.intellij.xdebugger.impl.rpc.ExecutionEnvironmentId import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.ListSerializer @@ -28,4 +29,11 @@ private class XDebuggerTreeSelectedValuesSerializer : CustomDataContextSerialize get() = SplitDebuggerUIUtil.SPLIT_SELECTED_VALUES_KEY override val serializer: KSerializer> get() = ListSerializer(XDebuggerTreeSelectedValueId.serializer()) +} + +private class XDebuggerTreeSelectedStacksSerializer : CustomDataContextSerializer> { + override val key: DataKey> + get() = SplitDebuggerUIUtil.SPLIT_SELECTED_STACKS_KEY + override val serializer: KSerializer> + get() = ListSerializer(XExecutionStackId.serializer()) } \ No newline at end of file