Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/runConfigurations/runIde.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.eclipse.lsp4j.debug.*
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
import org.jetbrains.concurrency.await
import java.nio.file.Path

class PowerShellDebugSession(
Expand All @@ -41,6 +42,11 @@ class PowerShellDebugSession(
client.sendKeyPress.adviseSuspend(Lifetime.Eternal, Dispatchers.EDT) {
sendKeyPress.fire(Unit)
}
client.terminated.adviseSuspend(Lifetime.Eternal, Dispatchers.IO) {
logger.info("Debug session has been terminated. Terminating debug server.")
session.debugProcess.stopAsync().await()
logger.info("Debug process had been terminated.")
}
}

fun setBreakpoint(filePath: Path, breakpoint: XLineBreakpoint<XBreakpointProperties<*>>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
import org.eclipse.lsp4j.jsonrpc.Launcher
import org.jetbrains.concurrency.Promise
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.io.path.Path

class PowerShellProgramDebugRunner : AsyncProgramRunner<RunnerSettings>() {
Expand Down Expand Up @@ -78,8 +79,26 @@ suspend fun bootstrapDebugSession(
val inOutPair = processRunner.establishDebuggerConnection()
?: throw CantRunException(MessagesBundle.message("powershell.debugger.cantRunException"))
val process = processRunner.getProcess() ?: error("Cannot get the debugger process.")
val handler = KillableProcessHandler(process, "PowerShellEditorService").apply {
setShouldKillProcessSoftly(false)
val handler = object : KillableProcessHandler(process, "PowerShellEditorService") {
// Here, we have to emulate graceful termination (exit code zero), since PowerShellEditorServices doesn't fully
// support it (in debug mode at least).
//
// The expected flow is:
// 1. We are asked to terminate gracefully. We track the attempt and return false (as if we refuse).
// 2. We are terminated in the hard mode, but we emulate the normal termination by returning a zero exit code.
//
// In case we weren't asked for graceful termination, then it means something else has killed the process, so we
// don't need to emulate graceful termination.

val gracefulTerminationRequested = AtomicBoolean()
override fun destroyProcessGracefully(): Boolean {
gracefulTerminationRequested.set(true)
return false // the graceful termination attempt is not successful, since it isn't supported
}

override fun notifyProcessTerminated(exitCode: Int) {
super.notifyProcessTerminated(if (gracefulTerminationRequested.get()) 0 else exitCode)
}
}
val console = TerminalExecutionConsole(project, handler)
handler.startNotify()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import kotlinx.coroutines.withContext
import org.jetbrains.concurrency.Promise

/**
* The main purpose of this runner is to call [RunProfileState.execute] or a background thread instead of a foreground
* The main purpose of this runner is to call [RunProfileState.execute] on a background thread instead of a foreground
* one, as our [RunProfileState] implementation requires FS access that's only possible from the background.
*/
class PowerShellProgramRunner : AsyncProgramRunner<RunnerSettings>() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.intellij.plugin.powershell.lang.debugger

import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.trace
import com.jetbrains.rd.util.reactive.Signal
import org.eclipse.lsp4j.debug.*
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification
import java.util.concurrent.CompletableFuture
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.trace

class PSDebugClient: IDebugProtocolClient {

val debugStopped = Signal<StoppedEventArguments>()
val sendKeyPress = Signal<Unit>()
val terminated = Signal<Unit>()

override fun breakpoint(args: BreakpointEventArguments) {
logger.trace { "BreakpointEventArguments: $args" }
Expand All @@ -34,9 +35,10 @@ class PSDebugClient: IDebugProtocolClient {
super.exited(args)
}

override fun terminated(args: TerminatedEventArguments) {
override fun terminated(args: TerminatedEventArguments?) {
logger.trace { "TerminatedEventArguments: $args" }
super.terminated(args)
terminated.fire(Unit)
}

override fun thread(args: ThreadEventArguments) {
Expand Down