[rd debugger] Refactor Fe session tab creation

GitOrigin-RevId: 9baba3e93fb4011edf6c70614601e604675e1040
This commit is contained in:
Maksim Zuev
2025-10-09 13:52:12 +00:00
committed by intellij-monorepo-bot
parent 8c97eaf436
commit 4df2a2b07f
5 changed files with 48 additions and 40 deletions
@@ -151,7 +151,7 @@ class FrontendXDebuggerManager(private val project: Project, private val cs: Cor
}
private fun getSessionIdByContentDescriptor(descriptor: RunContentDescriptor): XDebugSessionId? {
return sessionsFlow.value.firstOrNull { it.sessionTab?.runContentDescriptor === descriptor }?.id
return sessions.firstOrNull { it.sessionTab?.runContentDescriptor === descriptor }?.id
}
private suspend fun createDebuggerSession(sessionDto: XDebugSessionDto): XDebugSessionProxy {
@@ -11,6 +11,7 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.DataSink
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.application.EDT
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.platform.debugger.impl.frontend.evaluate.quick.FrontendXValue
import com.intellij.platform.debugger.impl.frontend.frame.FrontendDropFrameHandler
@@ -284,45 +285,52 @@ class FrontendXDebuggerSession private constructor(
}
@OptIn(AwaitCancellationAndInvoke::class)
private fun initTabInfo(tabDto: XDebuggerSessionTabDto) {
private suspend fun initTabInfo(tabDto: XDebuggerSessionTabDto) {
val (tabInfo, pausedFlow) = tabDto
tabScope.launch {
if (tabInfo !is XDebuggerSessionTabInfo) return@launch
if (tabInfo !is XDebuggerSessionTabInfo) return
val backendRunContentDescriptorId = tabInfo.backendRunContendDescriptorId.await()
val executionEnvironmentId = tabInfo.executionEnvironmentId
val backendRunContentDescriptorId = tabInfo.backendRunContendDescriptorId.await()
val executionEnvironmentId = tabInfo.executionEnvironmentId
suspend fun onTabClosed() {
tabInfo.tabClosedCallback.send(Unit)
tabInfo.tabClosedCallback.close()
tabScope.cancel()
}
val proxy = this@FrontendXDebuggerSession
withContext(Dispatchers.EDT) {
// TODO restore content to reuse on frontend if needed (it is not used now in create)
XDebugSessionTab.create(proxy, tabInfo.iconId?.icon(), tabInfo.executionEnvironmentProxyDto?.executionEnvironment(project, tabScope), null,
tabInfo.forceNewDebuggerUi, tabInfo.withFramesCustomization, tabInfo.defaultFramesViewKey).apply {
setAdditionalKeysProvider { sink ->
sink[SplitDebuggerUIUtil.SPLIT_RUN_CONTENT_DESCRIPTOR_KEY] = backendRunContentDescriptorId
if (executionEnvironmentId != null) {
sink[SplitDebuggerUIUtil.SPLIT_EXECUTION_ENVIRONMENT_KEY] = executionEnvironmentId
}
}
sessionTabDeferred.complete(this)
proxy.onTabInitialized(this)
showTab()
val descriptorScope = runContentDescriptor?.coroutineScope
// don't subscribe on additional tabs if we have [ExecutionEnvironment] (it means this is Monolith)
if (descriptorScope != null && tabInfo.executionEnvironmentProxyDto?.executionEnvironment == null) {
subscribeOnAdditionalTabs(descriptorScope, this@apply, tabInfo.additionalTabsComponentManagerId)
}
descriptorScope?.awaitCancellationAndInvoke {
tabInfo.tabClosedCallback.send(Unit)
tabInfo.tabClosedCallback.close()
tabScope.cancel()
}
pausedFlow.toFlow().collectLatest { paused ->
if (paused == null) return@collectLatest
withContext(Dispatchers.EDT) {
onPause(paused.pausedByUser, paused.topFrameIsAbsent)
}
val proxy = this@FrontendXDebuggerSession
val tab = withContext(Dispatchers.EDT) {
// TODO restore content to reuse on frontend if needed (it is not used now in create)
XDebugSessionTab.create(proxy, tabInfo.iconId?.icon(), tabInfo.executionEnvironmentProxyDto?.executionEnvironment(project, tabScope), null,
tabInfo.forceNewDebuggerUi, tabInfo.withFramesCustomization, tabInfo.defaultFramesViewKey).apply {
setAdditionalKeysProvider { sink ->
sink[SplitDebuggerUIUtil.SPLIT_RUN_CONTENT_DESCRIPTOR_KEY] = backendRunContentDescriptorId
if (executionEnvironmentId != null) {
sink[SplitDebuggerUIUtil.SPLIT_EXECUTION_ENVIRONMENT_KEY] = executionEnvironmentId
}
}
sessionTabDeferred.complete(this)
proxy.onTabInitialized(this)
showTab()
}
}
val runContentDescriptor = tab.runContentDescriptor
if (runContentDescriptor == null) {
onTabClosed()
thisLogger().error("Run content descriptor is not set for tab")
return
}
runContentDescriptor.coroutineScope.awaitCancellationAndInvoke {
onTabClosed()
}
// don't subscribe on additional tabs if we have [ExecutionEnvironment] (it means this is Monolith)
if (tabInfo.executionEnvironmentProxyDto?.executionEnvironment == null) {
subscribeOnAdditionalTabs(tabScope, tab, tabInfo.additionalTabsComponentManagerId)
}
tabScope.launch(Dispatchers.EDT) {
pausedFlow.toFlow().collectLatest { paused ->
tab.onPause(paused.pausedByUser, paused.topFrameIsAbsent)
}
}
}
@@ -308,7 +308,7 @@ class XDebugSessionImpl @JvmOverloads constructor(
}
@ApiStatus.Internal
fun getPausedEventsFlow(): Flow<XDebugSessionPausedInfo?> {
fun getPausedEventsFlow(): Flow<XDebugSessionPausedInfo> {
return myPausedEvents
}
@@ -551,8 +551,8 @@ class XDebugSessionImpl @JvmOverloads constructor(
}
fun showSessionTab() {
if (sessionTab != null) {
sessionTab!!.showTab()
if (!useFeProxy()) {
sessionTab?.showTab()
}
}
@@ -285,7 +285,7 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers
XDebugSessionImpl session = startSession(contentToReuse, starter,
new XDebugSessionImpl(environment, this, sessionName, icon, showToolWindowOnSuspendOnly, contentToReuse));
if (!showToolWindowOnSuspendOnly && !XDebugSessionProxy.useFeProxy()) {
if (!showToolWindowOnSuspendOnly) {
session.showSessionTab();
}
ProcessHandler handler = session.getDebugProcess().getProcessHandler();
@@ -44,7 +44,7 @@ interface XDebugSessionTabApi : RemoteApi<Unit> {
@Serializable
data class XDebuggerSessionTabDto(
val tabInfo: XDebuggerSessionTabAbstractInfo,
val pausedInfo: RpcFlow<XDebugSessionPausedInfo?>,
val pausedInfo: RpcFlow<XDebugSessionPausedInfo>,
)
@ApiStatus.Internal