POC coroutine panel removed
This commit is contained in:
@@ -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.failure=Failed to retrieve coroutine status
|
||||||
debugger.session.tab.coroutine.message.resume=Application resumed
|
debugger.session.tab.coroutine.message.resume=Application resumed
|
||||||
debugger.session.tab.coroutine.message.error=Coroutine dump failed, see log
|
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 Lint
|
||||||
android.klint.inspections.group.name=Android Lint for Kotlin
|
android.klint.inspections.group.name=Android Lint for Kotlin
|
||||||
|
|||||||
+4
-59
@@ -6,33 +6,19 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.coroutine
|
package org.jetbrains.kotlin.idea.debugger.coroutine
|
||||||
|
|
||||||
import com.intellij.debugger.DebuggerInvocationUtil
|
import com.intellij.debugger.DebuggerInvocationUtil
|
||||||
import com.intellij.debugger.actions.ThreadDumpAction
|
|
||||||
import com.intellij.debugger.engine.JavaDebugProcess
|
import com.intellij.debugger.engine.JavaDebugProcess
|
||||||
import com.intellij.debugger.impl.DebuggerSession
|
|
||||||
import com.intellij.execution.configurations.JavaParameters
|
import com.intellij.execution.configurations.JavaParameters
|
||||||
import com.intellij.execution.configurations.RunConfigurationBase
|
import com.intellij.execution.configurations.RunConfigurationBase
|
||||||
import com.intellij.execution.configurations.RunnerSettings
|
import com.intellij.execution.configurations.RunnerSettings
|
||||||
import com.intellij.execution.ui.RunnerLayoutUi
|
import com.intellij.execution.ui.RunnerLayoutUi
|
||||||
import com.intellij.execution.ui.layout.PlaceInGrid
|
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.project.Project
|
||||||
import com.intellij.openapi.util.registry.Registry
|
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.Content
|
||||||
import com.intellij.ui.content.ContentManagerAdapter
|
|
||||||
import com.intellij.ui.content.ContentManagerEvent
|
|
||||||
import com.intellij.util.messages.MessageBusConnection
|
import com.intellij.util.messages.MessageBusConnection
|
||||||
import com.intellij.xdebugger.*
|
import com.intellij.xdebugger.*
|
||||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
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.util.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.view.CoroutinesPanel
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.view.XCoroutineView
|
import org.jetbrains.kotlin.idea.debugger.coroutine.view.XCoroutineView
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
@@ -79,8 +65,9 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
|
|||||||
|
|
||||||
override fun processStarted(debugProcess: XDebugProcess) =
|
override fun processStarted(debugProcess: XDebugProcess) =
|
||||||
DebuggerInvocationUtil.swingInvokeLater(project) {
|
DebuggerInvocationUtil.swingInvokeLater(project) {
|
||||||
if (debugProcess is JavaDebugProcess)
|
if (debugProcess is JavaDebugProcess) {
|
||||||
registerCoroutinesPanel(debugProcess.session, debugProcess.debuggerSession)
|
registerXCoroutinesPanel(debugProcess.session)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processStopped(debugProcess: XDebugProcess) {
|
override fun processStopped(debugProcess: XDebugProcess) {
|
||||||
@@ -91,7 +78,7 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
|
|||||||
processCounter.decrementAndGet()
|
processCounter.decrementAndGet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createThreadsContent(session: XDebugSession) {
|
private fun registerXCoroutinesPanel(session: XDebugSession) {
|
||||||
val ui = session.ui ?: return
|
val ui = session.ui ?: return
|
||||||
val xCoroutineThreadView = XCoroutineView(project, session as XDebugSessionImpl)
|
val xCoroutineThreadView = XCoroutineView(project, session as XDebugSessionImpl)
|
||||||
val framesContent: Content = createContent(ui, xCoroutineThreadView)
|
val framesContent: Content = createContent(ui, xCoroutineThreadView)
|
||||||
@@ -105,48 +92,6 @@ class CoroutineProjectConnectionListener(val project: Project) : XDebuggerManage
|
|||||||
val param = createContentParamProvider.createContentParams()
|
val param = createContentParamProvider.createContentParams()
|
||||||
return ui.createContent(param.id, param.component, param.displayName, param.icon, param.parentComponent)
|
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
|
val Project.coroutineConnectionListener by projectListener
|
||||||
|
|||||||
-37
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-33
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-152
@@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-75
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+29
@@ -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
|
||||||
|
}
|
||||||
+1
-1
@@ -10,7 +10,7 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl
|
|||||||
import com.intellij.xdebugger.frame.XSuspendContext
|
import com.intellij.xdebugger.frame.XSuspendContext
|
||||||
import com.sun.jdi.*
|
import com.sun.jdi.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.command.CoroutineBuilder
|
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.data.CoroutineInfoData
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.ExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.ExecutionContext
|
||||||
|
|||||||
-96
@@ -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
|
|
||||||
}
|
|
||||||
-44
@@ -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"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-2
@@ -119,7 +119,6 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
|||||||
DebuggerUIUtil.invokeLater {
|
DebuggerUIUtil.invokeLater {
|
||||||
if (! (panel.tree.root is EmptyNode)) {
|
if (! (panel.tree.root is EmptyNode)) {
|
||||||
treeState = XDebuggerTreeState.saveState(panel.tree)
|
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) {
|
if(treeState != null) {
|
||||||
restorer?.dispose()
|
restorer?.dispose()
|
||||||
restorer = treeState?.restoreState(panel.tree)
|
restorer = treeState?.restoreState(panel.tree)
|
||||||
log.info("Tree state restored")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user