POC coroutine panel removed

This commit is contained in:
Vladimir Ilmov
2020-01-15 10:34:22 +01:00
parent c8c0f3383d
commit 4ff8acf5d7
11 changed files with 35 additions and 500 deletions
@@ -259,7 +259,7 @@ debugger.session.tab.coroutine.title=Coroutines
debugger.session.tab.coroutine.message.failure=Failed to retrieve coroutine status
debugger.session.tab.coroutine.message.resume=Application resumed
debugger.session.tab.coroutine.message.error=Coroutine dump failed, see log
debugger.session.tab.xcoroutine.title=XCoroutines
debugger.session.tab.xcoroutine.title=Coroutines
# Android Lint
android.klint.inspections.group.name=Android Lint for Kotlin
@@ -6,33 +6,19 @@
package org.jetbrains.kotlin.idea.debugger.coroutine
import com.intellij.debugger.DebuggerInvocationUtil
import com.intellij.debugger.actions.ThreadDumpAction
import com.intellij.debugger.engine.JavaDebugProcess
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.execution.configurations.JavaParameters
import com.intellij.execution.configurations.RunConfigurationBase
import com.intellij.execution.configurations.RunnerSettings
import com.intellij.execution.ui.RunnerLayoutUi
import com.intellij.execution.ui.layout.PlaceInGrid
import com.intellij.execution.ui.layout.impl.RunnerContentUi
import com.intellij.execution.ui.layout.impl.RunnerLayoutUiImpl
import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.registry.Registry
import com.intellij.ui.OnePixelSplitter
import com.intellij.ui.ScrollPaneFactory
import com.intellij.ui.content.Content
import com.intellij.ui.content.ContentManagerAdapter
import com.intellij.ui.content.ContentManagerEvent
import com.intellij.util.messages.MessageBusConnection
import com.intellij.xdebugger.*
import com.intellij.xdebugger.impl.XDebugSessionImpl
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.debugger.coroutine.util.*
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutinesPanel
import org.jetbrains.kotlin.idea.debugger.coroutine.view.XCoroutineView
import java.util.concurrent.atomic.AtomicInteger
import kotlin.properties.ReadOnlyProperty
@@ -79,8 +65,9 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
override fun processStarted(debugProcess: XDebugProcess) =
DebuggerInvocationUtil.swingInvokeLater(project) {
if (debugProcess is JavaDebugProcess)
registerCoroutinesPanel(debugProcess.session, debugProcess.debuggerSession)
if (debugProcess is JavaDebugProcess) {
registerXCoroutinesPanel(debugProcess.session)
}
}
override fun processStopped(debugProcess: XDebugProcess) {
@@ -91,7 +78,7 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
processCounter.decrementAndGet()
}
private fun createThreadsContent(session: XDebugSession) {
private fun registerXCoroutinesPanel(session: XDebugSession) {
val ui = session.ui ?: return
val xCoroutineThreadView = XCoroutineView(project, session as XDebugSessionImpl)
val framesContent: Content = createContent(ui, xCoroutineThreadView)
@@ -105,48 +92,6 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
val param = createContentParamProvider.createContentParams()
return ui.createContent(param.id, param.component, param.displayName, param.icon, param.parentComponent)
}
/**
* Adds panel to XDebugSessionTab
*/
private fun registerCoroutinesPanel(session: XDebugSession, debuggerSession: DebuggerSession): Boolean {
val ui = session.ui ?: return false
val panel = CoroutinesPanel(project, debuggerSession.contextManager)
// evaluation of `debuggerSession.contextManager.toString()` leads to
// java.lang.Throwable: Assertion failed: Should be invoked in manager thread, use DebuggerManagerThreadImpl.getInstance(..).invoke
// as toString() is not allowed here
createThreadsContent(session)
val content = ui.createContent(
CoroutineDebuggerContentInfo.COROUTINE_THREADS_CONTENT,
panel,
KotlinBundle.message("debugger.session.tab.coroutine.title"),
AllIcons.Debugger.ThreadGroup,
panel)
content.isCloseable = false
ui.addContent(content, 0, PlaceInGrid.left, true)
ui.addListener(object : ContentManagerAdapter() {
override fun selectionChanged(event: ContentManagerEvent) {
if (event.content === content) {
if (content.isSelected) {
panel.setUpdateEnabled(true)
if (panel.isRefreshNeeded) {
panel.rebuildIfVisible(DebuggerSession.Event.CONTEXT)
}
} else {
panel.setUpdateEnabled(false)
}
}
}
}, content)
// add coroutine dump button: due to api problem left toolbar is copied, modified and reset to tab
val runnerContent = (ui.options as RunnerLayoutUiImpl).getData(RunnerContentUi.KEY.name) as RunnerContentUi
val modifiedActions = runnerContent.getActions(true)
val pos = modifiedActions.indexOfLast { it is ThreadDumpAction }
modifiedActions.add(pos + 1, ActionManager.getInstance().getAction("Kotlin.XDebugger.CoroutinesDump"))
ui.options.setLeftToolbar(DefaultActionGroup(modifiedActions), ActionPlaces.DEBUGGER_TOOLBAR)
return true
}
}
val Project.coroutineConnectionListener by projectListener
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.command
import com.intellij.debugger.DebuggerInvocationUtil
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.PrioritizedTask
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl
@Deprecated("moved to XCoroutineView")
open class BuildCoroutineNodeCommand(
val node: DebuggerTreeNodeImpl,
debuggerContext: DebuggerContextImpl,
val myNodeManager: NodeManagerImpl,
thread: ThreadReferenceProxyImpl? = null
) : DebuggerContextCommandImpl(debuggerContext, thread) {
protected val myChildren = mutableListOf<DebuggerTreeNodeImpl>()
override fun getPriority() = PrioritizedTask.Priority.NORMAL
protected fun updateUI(scrollToVisible: Boolean) {
DebuggerInvocationUtil.swingInvokeLater(debuggerContext.project) {
node.removeAllChildren()
for (debuggerTreeNode in myChildren) {
node.add(debuggerTreeNode)
}
node.childrenChanged(scrollToVisible)
}
}
}
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.command
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationFramesDescriptor
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineCreatedStackFrameDescriptor
@Deprecated("moved to XCoroutineView")
class CoroutineBuildCreationFrameCommand(
node: DebuggerTreeNodeImpl,
val descriptor: CreationFramesDescriptor,
nodeManager: NodeManagerImpl,
debuggerContext: DebuggerContextImpl
) : BuildCoroutineNodeCommand(node, debuggerContext, nodeManager) {
override fun threadAction() {
val threadProxy = debuggerContext.suspendContext?.thread ?: return
val evalContext = debuggerContext.createEvaluationContext() ?: return
val proxy = threadProxy.forceFrames().first()
for(it in descriptor.frames) {
val descriptor = myNodeManager.createNode(
CoroutineCreatedStackFrameDescriptor(it, proxy), evalContext)
myChildren.add(descriptor)
}
updateUI(true)
}
}
@@ -1,152 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.command
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.engine.JavaStackFrame
import com.intellij.debugger.engine.evaluation.EvaluationContext
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
import com.intellij.debugger.memory.utils.StackFrameItem
import com.intellij.debugger.ui.impl.watch.*
import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineAsyncStackTraceProvider
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
@Deprecated("Moved to XCoroutineView")
class CoroutineBuildFrameCommand(
node: DebuggerTreeNodeImpl,
val descriptor: CoroutineDescriptorImpl,
nodeManager: NodeManagerImpl,
debuggerContext: DebuggerContextImpl
) : BuildCoroutineNodeCommand(node, debuggerContext, nodeManager) {
companion object {
val creationStackTraceSeparator = "\b\b\b" // the "\b\b\b" is used for creation stacktrace separator in kotlinx.coroutines
}
override fun threadAction() {
val debugProcess = debuggerContext.debugProcess ?: return
val evalContext = debuggerContext.createEvaluationContext() ?: return
when (descriptor.infoData.state) {
CoroutineInfoData.State.RUNNING -> {
if (renderRunningCoroutine(debugProcess, evalContext)) return
}
CoroutineInfoData.State.SUSPENDED, CoroutineInfoData.State.CREATED -> {
if (renderSuspendedCoroutine(evalContext)) return
}
}
createCreationStackTraceDescriptor(evalContext)
updateUI(true)
}
private fun createCreationStackTraceDescriptor(evalContext: EvaluationContextImpl) {
val threadProxy = debuggerContext.suspendContext?.thread ?: return
val proxy = threadProxy.forceFrames().first()
val trace = descriptor.infoData.stackTrace
val index = trace.indexOfFirst { it.className.startsWith(creationStackTraceSeparator) }
val creationNode = myNodeManager.createNode(
CreationFramesDescriptor(trace.subList(index + 1, trace.size)), evalContext)
myChildren.add(creationNode)
trace.subList(index + 1, trace.size).forEach {
val descriptor = myNodeManager.createNode(
CoroutineCreatedStackFrameDescriptor(it, proxy), evalContext)
creationNode.add(descriptor)
}
}
private fun renderSuspendedCoroutine(evalContext: EvaluationContextImpl): Boolean {
val threadProxy = debuggerContext.suspendContext?.thread ?: return true
val proxy = threadProxy.forceFrames().first()
// the thread is paused on breakpoint - it has at least one frame
for (it in descriptor.infoData.stackTrace) {
if (it.className.startsWith(creationStackTraceSeparator)) break
myChildren.add(createCoroutineFrameDescriptor(evalContext, it, proxy))
}
return false
}
private fun createCoroutineFrameDescriptor(
evalContext: EvaluationContextImpl,
frame: StackTraceElement,
proxy: StackFrameProxyImpl,
parent: NodeDescriptorImpl? = null
): DebuggerTreeNodeImpl {
return myNodeManager.createNode(
myNodeManager.getDescriptor(
parent,
CoroutineStackTraceData(descriptor.infoData, proxy, evalContext, frame)
), evalContext
)
}
private fun renderRunningCoroutine(
debugProcess: DebugProcessImpl,
evalContext: EvaluationContextImpl
): Boolean {
if (descriptor.infoData.activeThread == null) {
myChildren.add(myNodeManager.createMessageNode("Frames are not available"))
return true
}
val proxy = ThreadReferenceProxyImpl(
debugProcess.virtualMachineProxy,
descriptor.infoData.activeThread
)
val frames = proxy.forceFrames()
var endRange = findResumeWithMethodFrameIndex(frames)
for (frame in 0..frames.lastIndex) {
if (frame == endRange) {
val javaStackFrame = JavaStackFrame(StackFrameDescriptorImpl(frames[endRange - 1], MethodsTracker()), true)
val async = CoroutineAsyncStackTraceProvider()
.getAsyncStackTrace(javaStackFrame, evalContext.suspendContext)
async?.forEach {
myChildren.add(createAsyncFrameDescriptor(evalContext, it, frames[frame]))
}
} else {
val frameDescriptor = createFrameDescriptor(evalContext, frames[frame])
myChildren.add(frameDescriptor)
}
}
updateUI(true)
return false
}
private fun findResumeWithMethodFrameIndex(frames: List<StackFrameProxyImpl>) : Int {
for (j: Int in frames.lastIndex downTo 0 )
if (isResumeMethodFrame(frames[j])) {
return j
}
return 0
}
private fun isResumeMethodFrame(frame: StackFrameProxyImpl) = frame.location().method().name() == "resumeWith"
private fun createFrameDescriptor(
evalContext: EvaluationContext,
frame: StackFrameProxyImpl
): DebuggerTreeNodeImpl {
return myNodeManager.createNode(
myNodeManager.getStackFrameDescriptor(descriptor, frame),
evalContext
)
}
private fun createAsyncFrameDescriptor(
evalContext: EvaluationContextImpl,
frame: StackFrameItem,
proxy: StackFrameProxyImpl
): DebuggerTreeNodeImpl {
return myNodeManager.createNode(
myNodeManager.getDescriptor(
descriptor,
CoroutineStackFrameData(descriptor.infoData, proxy, evalContext, frame)
), evalContext
)
}
}
@@ -1,75 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.command
import com.intellij.debugger.DebuggerInvocationUtil
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineDescriptorData
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
import org.jetbrains.kotlin.idea.debugger.coroutine.util.ProjectNotification
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutinesDebuggerTree
@Deprecated("moved to XCoroutineView")
class RefreshCoroutinesTreeCommand(
val context: DebuggerContextImpl,
private val debuggerTree: CoroutinesDebuggerTree
) : SuspendContextCommandImpl(context.suspendContext) {
val notification = ProjectNotification(debuggerTree.project)
override fun contextAction() {
val nodeManagerImpl = debuggerTree.nodeFactory
val root = nodeManagerImpl.defaultNode
val suspendContext: SuspendContextImpl? = suspendContext
if (context.debuggerSession is DebuggerSession && suspendContext is SuspendContextImpl && !suspendContext.isResumed) {
var infoCache = CoroutineDebugProbesProxy(suspendContext).dumpCoroutines()
if (infoCache.isOk()) {
val evaluationContext = evaluationContext(suspendContext)
for (state in infoCache.cache) {
val descriptor = createCoroutineDescriptorNode(nodeManagerImpl, state, evaluationContext)
root.add(descriptor)
}
setRoot(root)
} else {
debuggerTree.showMessage(KotlinBundle.message("debugger.session.tab.coroutine.message.failure"))
notification.error(KotlinBundle.message("debugger.session.tab.coroutine.message.error"))
}
} else
debuggerTree.showMessage(KotlinBundle.message("debugger.session.tab.coroutine.message.resume"))
}
private fun evaluationContext(suspendContext : SuspendContextImpl) =
EvaluationContextImpl(suspendContext, suspendContext.frameProxy)
private fun createCoroutineDescriptorNode(
nodeFactory: NodeManagerImpl,
coroutineInfoData: CoroutineInfoData,
evaluationContext: EvaluationContextImpl
): DebuggerTreeNodeImpl {
return nodeFactory.createNode(
nodeFactory.getDescriptor(
null,
CoroutineDescriptorData(coroutineInfoData)
),
evaluationContext
)
}
private fun setRoot(root: DebuggerTreeNodeImpl) {
DebuggerInvocationUtil.swingInvokeLater(debuggerTree.project) {
debuggerTree.mutableModel.setRoot(root)
debuggerTree.treeChanged()
}
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.data
class CoroutineInfoCache(
val cache: MutableList<CoroutineInfoData> = mutableListOf(), var state: CacheState = CacheState.INIT
) {
fun ok(infoList: List<CoroutineInfoData>) {
cache.clear()
cache.addAll(infoList)
state = CacheState.OK
}
fun fail() {
cache.clear()
state = CacheState.FAIL
}
fun isOk(): Boolean {
return state == CacheState.OK
}
}
enum class CacheState {
OK, FAIL, INIT
}
@@ -10,7 +10,7 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.xdebugger.frame.XSuspendContext
import com.sun.jdi.*
import org.jetbrains.kotlin.idea.debugger.coroutine.command.CoroutineBuilder
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutineInfoCache
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoCache
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
import org.jetbrains.kotlin.idea.debugger.evaluate.ExecutionContext
@@ -1,96 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.coroutine.view
import com.intellij.debugger.DebuggerBundle
import com.intellij.debugger.engine.events.DebuggerCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.debugger.ui.impl.ThreadsDebuggerTree
import com.intellij.debugger.ui.impl.watch.*
import com.intellij.debugger.ui.tree.StackFrameDescriptor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.coroutine.command.CoroutineBuildCreationFrameCommand
import org.jetbrains.kotlin.idea.debugger.coroutine.command.CoroutineBuildFrameCommand
import org.jetbrains.kotlin.idea.debugger.coroutine.command.RefreshCoroutinesTreeCommand
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineDescriptorImpl
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationFramesDescriptor
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ManagerThreadExecutor
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
import java.util.*
/**
* Tree of coroutines for [CoroutinesPanel]
*/
@Deprecated("moved to XCoroutineView")
class CoroutinesDebuggerTree(project: Project) : ThreadsDebuggerTree(project) {
// called on every step/frame
override fun build(context: DebuggerContextImpl) {
val session = context.debuggerSession
val command = RefreshCoroutinesTreeCommand(context, this)
val debuggerSessionState = session?.state ?: DebuggerSession.State.DISPOSED
if (ApplicationManager.getApplication().isUnitTestMode || debuggerSessionState in EnumSet
.of(DebuggerSession.State.PAUSED, DebuggerSession.State.RUNNING)
) {
showMessage(MessageDescriptor.EVALUATING)
context.debugProcess!!.managerThread.schedule(command)
} else {
showMessage(session?.stateDescription ?: DebuggerBundle.message("status.debug.stopped"))
}
}
override fun getBuildNodeCommand(node: DebuggerTreeNodeImpl): DebuggerCommandImpl? {
return when (val descriptor = node.descriptor) {
is CoroutineDescriptorImpl ->
CoroutineBuildFrameCommand(node, descriptor, myNodeManager, debuggerContext)
is CreationFramesDescriptor ->
CoroutineBuildCreationFrameCommand(node, descriptor, myNodeManager, debuggerContext)
else -> null
}
}
override fun createNodeManager(project: Project): NodeManagerImpl {
return object : NodeManagerImpl(project, this) {
override fun getContextKey(frame: StackFrameProxyImpl?): String? {
return "CoroutinesView"
}
}
}
override fun isExpandable(node: DebuggerTreeNodeImpl): Boolean {
val descriptor = node.descriptor
return if (descriptor is StackFrameDescriptor) false else descriptor.isExpandable
}
}
class CoroutineInfoCache(
val cache: MutableList<CoroutineInfoData> = mutableListOf(), var state: CacheState = CacheState.INIT
) {
fun ok(infoList: List<CoroutineInfoData>) {
cache.clear()
cache.addAll(infoList)
state = CacheState.OK
}
fun fail() {
cache.clear()
state = CacheState.FAIL
}
fun isOk(): Boolean {
return state == CacheState.OK
}
}
enum class CacheState {
OK, FAIL, INIT
}
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("DEPRECATION")
package org.jetbrains.kotlin.idea.debugger.coroutine.view
import com.intellij.debugger.actions.DebuggerActions
import com.intellij.debugger.impl.DebuggerStateManager
import com.intellij.debugger.ui.impl.ThreadsPanel
import com.intellij.debugger.ui.impl.watch.DebuggerTree
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerActions
/**
* Added into ui in [CoroutineProjectConnectionListener.registerCoroutinesPanel]
*/
@Deprecated("moved to XCoroutineView")
class CoroutinesPanel(project: Project, stateManager: DebuggerStateManager) : ThreadsPanel(project, stateManager) {
override fun createTreeView(): DebuggerTree {
return CoroutinesDebuggerTree(project)
}
override fun createPopupMenu(): ActionPopupMenu {
val group = ActionManager.getInstance().getAction(DebuggerActions.THREADS_PANEL_POPUP) as DefaultActionGroup
return ActionManager.getInstance().createActionPopupMenu(
CoroutineDebuggerActions.COROUTINE_PANEL_POPUP, group)
}
override fun getData(dataId: String): Any? {
return if (helpDataId(dataId)) HELP_ID else super.getData(dataId)
}
private fun helpDataId(dataId: String): Boolean = PlatformDataKeys.HELP_ID.`is`(dataId)
companion object {
val HELP_ID = "debugging.debugCoroutines"
}
}
@@ -119,7 +119,6 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
DebuggerUIUtil.invokeLater {
if (! (panel.tree.root is EmptyNode)) {
treeState = XDebuggerTreeState.saveState(panel.tree)
log.info("Tree state saved")
}
}
}
@@ -135,7 +134,6 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
if(treeState != null) {
restorer?.dispose()
restorer = treeState?.restoreState(panel.tree)
log.info("Tree state restored")
}
}