diff --git a/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowerShellDebugSession.kt b/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowerShellDebugSession.kt index 5a722a0e..baddd66a 100644 --- a/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowerShellDebugSession.kt +++ b/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowerShellDebugSession.kt @@ -19,7 +19,10 @@ import com.intellij.xdebugger.evaluation.XDebuggerEvaluator import com.intellij.xdebugger.frame.* import com.jetbrains.rd.framework.util.adviseSuspend import com.jetbrains.rd.util.lifetime.Lifetime -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import org.apache.xml.resolver.helpers.FileURL @@ -31,7 +34,7 @@ import javax.swing.Icon import kotlin.collections.HashMap import kotlin.io.path.Path -class PowerShellDebugSession(val client: PSDebugClient, val server: IDebugProtocolServer, val session: XDebugSession, val coroutineScope: CoroutineScope) { +class PowerShellDebugSession(val client: PSDebugClient, val server: IDebugProtocolServer, val session: XDebugSession, val coroutineScope: CoroutineScope, val xDebugSession: XDebugSession) { val breakpointMap = mutableMapOf>>>() init{ @@ -39,7 +42,7 @@ class PowerShellDebugSession(val client: PSDebugClient, val server: IDebugProtoc args -> val stack = server.stackTrace(StackTraceArguments().apply { threadId = args!!.threadId }).await() thisLogger().info(stack.toString()) - session.positionReached(PowerShellSuspendContext(stack, server, coroutineScope, args!!.threadId)) + session.positionReached(PowerShellSuspendContext(stack, server, coroutineScope, args!!.threadId, xDebugSession)) } } @@ -154,18 +157,19 @@ class PowerShellDebugSession(val client: PSDebugClient, val server: IDebugProtoc class PowerShellExecutionStack(val stackResponse: StackTraceResponse, val server: IDebugProtocolServer, - val coroutineScope: CoroutineScope): XExecutionStack("PowerShell Debug Execution Stack") { + val coroutineScope: CoroutineScope, val xDebugSession: XDebugSession): XExecutionStack("PowerShell Debug Execution Stack") { override fun getTopFrame(): XStackFrame? { - return stackResponse.stackFrames.firstOrNull()?.let { PowerShellStackFrame(it, server, coroutineScope) } + return stackResponse.stackFrames.firstOrNull()?.let { PowerShellStackFrame(it, server, coroutineScope, xDebugSession) } } override fun computeStackFrames(firstFrameIndex: Int, container: XStackFrameContainer?) { - container?.addStackFrames(stackResponse.stackFrames.drop(firstFrameIndex).map { PowerShellStackFrame(it, server, coroutineScope) }, true) + container?.addStackFrames(stackResponse.stackFrames.drop(firstFrameIndex).map { PowerShellStackFrame(it, server, coroutineScope, xDebugSession) }, true) } } -class PowerShellStackFrame(val stack: StackFrame, val server: IDebugProtocolServer, val coroutineScope: CoroutineScope): XStackFrame() { +class PowerShellStackFrame(val stack: StackFrame, val server: IDebugProtocolServer, val coroutineScope: CoroutineScope, val xDebugSession: XDebugSession): XStackFrame() { + override fun getSourcePosition(): XSourcePosition? { var file = VfsUtil.findFile(Path(stack.source?.path ?: return null), false) return XDebuggerUtil.getInstance().createPosition(file, stack.line - 1, stack.column) @@ -190,7 +194,7 @@ class PowerShellStackFrame(val stack: StackFrame, val server: IDebugProtocolServ val localVariables = server.variables(VariablesArguments().apply { variablesReference = localScope.variablesReference }).await() - localVariables.variables.forEach { list.add(it.name, PowerShellDebuggerVariableValue(it, localScope.variablesReference, server, coroutineScope)) } + localVariables.variables.forEach { list.add(it.name, PowerShellDebuggerVariableValue(it, localScope.variablesReference, server, coroutineScope, xDebugSession)) } scopesResponse.scopes.filter { x -> x.name.lowercase() != "local" }.forEach { val variableRef = it.variablesReference @@ -198,7 +202,7 @@ class PowerShellStackFrame(val stack: StackFrame, val server: IDebugProtocolServ val variables = server.variables(VariablesArguments().apply { variablesReference = variableRef }).await() - val group = PowerShellVariableGroup(groupName, variables, variableRef, server, coroutineScope) + val group = PowerShellVariableGroup(groupName, variables, variableRef, server, coroutineScope, xDebugSession) list.addBottomGroup(group) } @@ -209,13 +213,24 @@ class PowerShellStackFrame(val stack: StackFrame, val server: IDebugProtocolServ class PowerShellDebuggerVariableValue(val variable: Variable, val parentReference: Int?, val server: IDebugProtocolServer, - val coroutineScope: CoroutineScope) : XNamedValue(variable.name ?: "") { + val coroutineScope: CoroutineScope, val xDebugSession: XDebugSession) : XNamedValue(variable.name ?: "") { + + init { + val variablesCache = (xDebugSession.suspendContext as PowerShellSuspendContext).variablesCache + variablesCache.getOrDefault((Pair(parentReference, variable.name)), null)?.let { + variable.value = it.value + variable.type = it.type ?: variable.type + variable.variablesReference = variable.variablesReference + variable.namedVariables = it.namedVariables + variable.indexedVariables = it.indexedVariables + } + } override fun computePresentation(node: XValueNode, place: XValuePlace) { //val kind = variable.presentationHint.kind var icon: Icon? = IconManager.getInstance().getPlatformIcon(PlatformIcons.Variable) - node.setPresentation(icon, "string", variable.value, variable.variablesReference != 0) + node.setPresentation(icon, variable.type, variable.value, variable.variablesReference != 0) } override fun computeChildren(node: XCompositeNode) { @@ -223,7 +238,7 @@ class PowerShellDebuggerVariableValue(val variable: Variable, val parentReferenc if (variable.variablesReference != 0) { val list = XValueChildrenList() server.variables(VariablesArguments().apply { variablesReference = variable.variablesReference }) - .await().variables.forEach { list.add(it.name, PowerShellDebuggerVariableValue(it, variable.variablesReference, server, coroutineScope)) } + .await().variables.forEach { list.add(it.name, PowerShellDebuggerVariableValue(it, variable.variablesReference, server, coroutineScope, xDebugSession)) } node.addChildren(list, true) } } @@ -243,8 +258,9 @@ class PowerShellDebuggerVariableValue(val variable: Variable, val parentReferenc if(parentReference !is Int) return coroutineScope.launch { + val variablesCache = (xDebugSession.suspendContext as PowerShellSuspendContext).variablesCache try { - var response = server.setVariable(SetVariableArguments().apply { + val response = server.setVariable(SetVariableArguments().apply { variablesReference = parentReference name = variable.name value = expression.expression @@ -254,10 +270,10 @@ class PowerShellDebuggerVariableValue(val variable: Variable, val parentReferenc variable.variablesReference = response.variablesReference ?: variable.variablesReference variable.namedVariables = response.namedVariables ?: variable.namedVariables variable.indexedVariables = response.indexedVariables ?: variable.indexedVariables + variablesCache[(Pair(parentReference, variable.name))] = variable callback.valueModified() - } - catch (e: Exception) { + } catch (e: Exception) { callback.errorOccurred(e.message ?: e.javaClass.simpleName) } } @@ -270,23 +286,29 @@ class PowerShellDebuggerVariableValue(val variable: Variable, val parentReferenc } } -class PowerShellVariableGroup(val groupName: String, val variable: VariablesResponse, val parentReference: Int, val server: IDebugProtocolServer, val coroutineScope: CoroutineScope): XValueGroup(groupName){ +class PowerShellVariableGroup(val groupName: String, val variable: VariablesResponse, val parentReference: Int, + val server: IDebugProtocolServer, + val coroutineScope: CoroutineScope, + val xDebugSession: XDebugSession): XValueGroup(groupName){ override fun computeChildren(node: XCompositeNode) { val list = XValueChildrenList() variable.variables.forEach { - list.add(it.name, PowerShellDebuggerVariableValue(it, parentReference, server, coroutineScope)) + list.add(it.name, PowerShellDebuggerVariableValue(it, parentReference, server, coroutineScope, xDebugSession)) } node.addChildren(list, true) } } -class PowerShellSuspendContext(val stack: StackTraceResponse, val server: IDebugProtocolServer, val coroutineScope: CoroutineScope, val threadId: Int = 0):XSuspendContext(){ +class PowerShellSuspendContext(val stack: StackTraceResponse, val server: IDebugProtocolServer, + val coroutineScope: CoroutineScope, + val threadId: Int = 0, val xDebugSession: XDebugSession):XSuspendContext(){ + val variablesCache: MutableMap, Variable> = mutableMapOf() override fun getExecutionStacks(): Array { - return arrayOf(PowerShellExecutionStack(stack, server, coroutineScope)) + return arrayOf(PowerShellExecutionStack(stack, server, coroutineScope, xDebugSession)) } override fun getActiveExecutionStack(): XExecutionStack { - return PowerShellExecutionStack(stack, server, coroutineScope) + return PowerShellExecutionStack(stack, server, coroutineScope, xDebugSession) } } diff --git a/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowershellDebuggerEvaluator.kt b/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowershellDebuggerEvaluator.kt index f4a6a30a..cae1b7d2 100644 --- a/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowershellDebuggerEvaluator.kt +++ b/src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowershellDebuggerEvaluator.kt @@ -28,7 +28,7 @@ class PowershellDebuggerEvaluator(val server: IDebugProtocolServer, val stackFra type = result.type presentationHint = result.presentationHint } - callback.evaluated(PowerShellDebuggerVariableValue(variable, null, server, coroutineScope)) + callback.evaluated(PowerShellDebuggerVariableValue(variable, null, server, coroutineScope, stackFrame.xDebugSession)) } } diff --git a/src/main/kotlin/com/intellij/plugin/powershell/ide/run/PowerShellScriptCommandLineState.kt b/src/main/kotlin/com/intellij/plugin/powershell/ide/run/PowerShellScriptCommandLineState.kt index 31a15c22..0d5aecc4 100644 --- a/src/main/kotlin/com/intellij/plugin/powershell/ide/run/PowerShellScriptCommandLineState.kt +++ b/src/main/kotlin/com/intellij/plugin/powershell/ide/run/PowerShellScriptCommandLineState.kt @@ -167,7 +167,7 @@ class PowerShellScriptCommandLineState( } } private fun processDebuging(inputStream: InputStream, outputStream: OutputStream, debugSession: XDebugSession){ - val targetPath = runConfiguration.scriptPath //"""C:\Users\Sergey.Vardanyan\IdeaProjects\powershellTest\test.ps1""" + val targetPath = runConfiguration.scriptPath val client = PSDebugClient(debugSession) val launcher: Launcher = DSPLauncher.createClientLauncher(client, inputStream, outputStream) @@ -184,7 +184,7 @@ class PowerShellScriptCommandLineState( val scope = PluginProjectRoot.getInstance(environment.project).coroutineScope - val powerShellDebugSession = PowerShellDebugSession(client, remoteProxy, debugSession, scope) + val powerShellDebugSession = PowerShellDebugSession(client, remoteProxy, debugSession, scope, debugSession) environment.putUserData(ClientSessionKey, powerShellDebugSession) val allBreakpoints = XDebuggerManager.getInstance(environment.project).breakpointManager.getBreakpoints(PowerShellBreakpointType::class.java) allBreakpoints.filter{x -> x.sourcePosition != null && x.sourcePosition!!.file.exists() && x.sourcePosition!!.file.isValid}