Skip to content

Use a CustomRequest to disconnect the dotnet debugger from attach sessions. #4704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 20, 2023
13 changes: 13 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"@typescript-eslint/eslint-plugin": "6.4.0",
"@typescript-eslint/parser": "6.4.0",
"@ungap/structured-clone": "1.2.0",
"@vscode/debugprotocol": "1.61.0",
"@vscode/test-electron": "2.3.4",
"@vscode/vsce": "2.20.1",
"esbuild": "0.19.2",
Expand Down
46 changes: 35 additions & 11 deletions src/features/DebugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
QuickPickOptions,
DebugConfigurationProviderTriggerKind
} from "vscode";
import type { DebugProtocol } from "@vscode/debugprotocol";
import { NotificationType, RequestType } from "vscode-languageclient";
import { LanguageClient } from "vscode-languageclient/node";
import { LanguageClientConsumer } from "../languageClientConsumer";
Expand Down Expand Up @@ -375,25 +376,48 @@ export class DebugSessionFeature extends LanguageClientConsumer
dotnetAttachConfig.processId = pid;

// Ensure the .NET session stops before the PowerShell session so that the .NET debug session doesn't emit an error about the process unexpectedly terminating.
const startDebugEvent = debug.onDidStartDebugSession((dotnetAttachSession) => {
let tempConsoleDotnetAttachSession: DebugSession;
const startDebugEvent = debug.onDidStartDebugSession(dotnetAttachSession => {
if (dotnetAttachSession.configuration.name != dotnetAttachConfig.name) { return; }

// Makes the event one-time
// HACK: This seems like you would be calling a method on a variable not assigned yet, but it does work in the flow.
// The dispose shorthand demonry for making an event one-time courtesy of: https://github.com/OmniSharp/omnisharp-vscode/blob/b8b07bb12557b4400198895f82a94895cb90c461/test/integrationTests/launchConfiguration.integration.test.ts#L41-L45
startDebugEvent.dispose();

this.logger.writeVerbose(`Debugger session detected: ${dotnetAttachSession.name} (${dotnetAttachSession.id})`);
if (dotnetAttachSession.configuration.name == dotnetAttachConfig.name) {
const stopDebugEvent = debug.onDidTerminateDebugSession(async (terminatedDebugSession) => {
// Makes the event one-time
stopDebugEvent.dispose();

this.logger.writeVerbose(`Debugger session stopped: ${terminatedDebugSession.name} (${terminatedDebugSession.id})`);
tempConsoleDotnetAttachSession = dotnetAttachSession;

const stopDebugEvent = debug.onDidTerminateDebugSession(async tempConsoleSession => {
if (tempConsoleDotnetAttachSession.parentSession?.id !== tempConsoleSession.id) { return; }

if (terminatedDebugSession === session) {
this.logger.writeVerbose("Terminating dotnet debugger session associated with PowerShell debug session!");
await debug.stopDebugging(dotnetAttachSession);
// Makes the event one-time
stopDebugEvent.dispose();

this.logger.writeVerbose(`Debugger session terminated: ${tempConsoleSession.name} (${tempConsoleSession.id})`);

// HACK: As of 2023-08-17, there is no vscode debug API to request the C# debugger to detach, so we send it a custom DAP request instead.
const disconnectRequest: DebugProtocol.DisconnectRequest = {
command: "disconnect",
seq: 0,
type: "request",
arguments: {
restart: false,
terminateDebuggee: false,
suspendDebuggee: false
}
});
}
};

try {
await dotnetAttachSession.customRequest(
disconnectRequest.command,
disconnectRequest.arguments
);
} catch (err) {
this.logger.writeWarning(`Disconnect request to dotnet debugger failed: ${err}`);
}
});
});

// Start a child debug session to attach the dotnet debugger
Expand Down
5 changes: 4 additions & 1 deletion test/features/DebugSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,16 @@ describe("DebugSessionFeature", () => {
});
});

describe("DebugSessionFeature E2E", () => {
describe("DebugSessionFeature E2E", function() {
// E2E tests can take a while to run since the debugger has to start up and attach
this.slow(20000);
before(async () => {
// Registers and warms up the debug adapter and the PowerShell Extension Terminal
await ensureEditorServicesIsConnected();
});

it("Starts and stops a debugging session", async () => {

// Inspect the debug session via the started events to ensure it is correct
const startDebugSession = new Promise<DebugSession>((resolve) => {
const event = debug.onDidStartDebugSession((session) => {
Expand Down
2 changes: 2 additions & 0 deletions test/features/ISECompatibility.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ describe("ISE compatibility feature", function () {
});

describe("Color theme interactions", function () {
// These tests are slow because they change the user's theme.
this.slow(3000);
beforeEach(enableISEMode);

function assertISESettings(): void {
Expand Down