Skip to content

Commit 2a312d6

Browse files
committed
(#323) Debugger: auto-terminate when the user script terminates
1 parent e1c5ef8 commit 2a312d6

File tree

3 files changed

+32
-5
lines changed

3 files changed

+32
-5
lines changed

src/main/kotlin/com/intellij/plugin/powershell/ide/debugger/PowerShellDebugSession.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import kotlinx.coroutines.sync.Mutex
2020
import kotlinx.coroutines.sync.withLock
2121
import org.eclipse.lsp4j.debug.*
2222
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
23+
import org.jetbrains.concurrency.await
2324
import java.nio.file.Path
2425

2526
class PowerShellDebugSession(
@@ -41,6 +42,11 @@ class PowerShellDebugSession(
4142
client.sendKeyPress.adviseSuspend(Lifetime.Eternal, Dispatchers.EDT) {
4243
sendKeyPress.fire(Unit)
4344
}
45+
client.terminated.adviseSuspend(Lifetime.Eternal, Dispatchers.IO) {
46+
logger.info("Debug session has been terminated. Terminating debug server.")
47+
session.debugProcess.stopAsync().await()
48+
logger.info("Debug process had been terminated.")
49+
}
4450
}
4551

4652
fun setBreakpoint(filePath: Path, breakpoint: XLineBreakpoint<XBreakpointProperties<*>>) {

src/main/kotlin/com/intellij/plugin/powershell/ide/run/PowerShellProgramDebugRunner.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.eclipse.lsp4j.debug.services.IDebugProtocolServer
4141
import org.eclipse.lsp4j.jsonrpc.Launcher
4242
import org.jetbrains.concurrency.Promise
4343
import java.nio.file.Path
44+
import java.util.concurrent.atomic.AtomicBoolean
4445
import kotlin.io.path.Path
4546

4647
class PowerShellProgramDebugRunner : AsyncProgramRunner<RunnerSettings>() {
@@ -78,8 +79,26 @@ suspend fun bootstrapDebugSession(
7879
val inOutPair = processRunner.establishDebuggerConnection()
7980
?: throw CantRunException(MessagesBundle.message("powershell.debugger.cantRunException"))
8081
val process = processRunner.getProcess() ?: error("Cannot get the debugger process.")
81-
val handler = KillableProcessHandler(process, "PowerShellEditorService").apply {
82-
setShouldKillProcessSoftly(false)
82+
val handler = object : KillableProcessHandler(process, "PowerShellEditorService") {
83+
// Here, we have to emulate graceful termination (exit code zero), since PowerShellEditorServices doesn't fully
84+
// support it (in debug mode at least).
85+
//
86+
// The expected flow is:
87+
// 1. We are asked to terminate gracefully. We track the attempt and return false (as if we refuse).
88+
// 2. We are terminated in the hard mode, but we emulate the normal termination by returning a zero exit code.
89+
//
90+
// In case we weren't asked for graceful termination, then it means something else has killed the process, so we
91+
// don't need to emulate graceful termination.
92+
93+
val gracefulTerminationRequested = AtomicBoolean()
94+
override fun destroyProcessGracefully(): Boolean {
95+
gracefulTerminationRequested.set(true)
96+
return false // the graceful termination attempt is not successful, since it isn't supported
97+
}
98+
99+
override fun notifyProcessTerminated(exitCode: Int) {
100+
super.notifyProcessTerminated(if (gracefulTerminationRequested.get()) 0 else exitCode)
101+
}
83102
}
84103
val console = TerminalExecutionConsole(project, handler)
85104
handler.startNotify()

src/main/kotlin/com/intellij/plugin/powershell/lang/debugger/PSDebugClient.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package com.intellij.plugin.powershell.lang.debugger
22

3+
import com.intellij.openapi.diagnostic.logger
4+
import com.intellij.openapi.diagnostic.trace
35
import com.jetbrains.rd.util.reactive.Signal
46
import org.eclipse.lsp4j.debug.*
57
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient
68
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification
79
import java.util.concurrent.CompletableFuture
8-
import com.intellij.openapi.diagnostic.logger
9-
import com.intellij.openapi.diagnostic.trace
1010

1111
class PSDebugClient: IDebugProtocolClient {
1212

1313
val debugStopped = Signal<StoppedEventArguments>()
1414
val sendKeyPress = Signal<Unit>()
15+
val terminated = Signal<Unit>()
1516

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

37-
override fun terminated(args: TerminatedEventArguments) {
38+
override fun terminated(args: TerminatedEventArguments?) {
3839
logger.trace { "TerminatedEventArguments: $args" }
3940
super.terminated(args)
41+
terminated.fire(Unit)
4042
}
4143

4244
override fun thread(args: ThreadEventArguments) {

0 commit comments

Comments
 (0)