From 2cf4516ae6cf49ff00c873bfe766304713eaced3 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Thu, 17 Aug 2023 16:30:25 -0700 Subject: [PATCH 01/13] First attempt, customRequest references the wrong this --- src/features/DebugSession.ts | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 55dd794e55..551540f8c8 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -381,20 +381,29 @@ export class DebugSessionFeature extends LanguageClientConsumer // 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})`); + + // 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. if (dotnetAttachSession.configuration.name == dotnetAttachConfig.name) { - const stopDebugEvent = debug.onDidTerminateDebugSession(async (terminatedDebugSession) => { - // Makes the event one-time - stopDebugEvent.dispose(); + const onTerminateAttachSession = debug.onDidTerminateDebugSession(async parentSession => { + // HACK: Force the "this" on this since we are supplying a "this" to the function via an argument. There probably is a type-safe way to do this, but because we also need a self-reference to the function in order to make it a one-time action, I'm not sure how to do it. + const dotnetAttachSession = this as unknown as DebugSession; - this.logger.writeVerbose(`Debugger session stopped: ${terminatedDebugSession.name} (${terminatedDebugSession.id})`); + if (parentSession.parentSession?.id !== dotnetAttachSession.id) {return;} - if (terminatedDebugSession === session) { - this.logger.writeVerbose("Terminating dotnet debugger session associated with PowerShell debug session!"); - await debug.stopDebugging(dotnetAttachSession); - } - }); - } - }); + this.logger.writeVerbose(`Powershell Binary Debug Session Stop Detected: ${dotnetAttachSession.name} (${dotnetAttachSession.id}), detaching dotnet debugger.`); + + await dotnetAttachSession.customRequest( + "disconnect", + { + restart: false, + terminateDebuggee: false, + suspendDebuggee: false + } + ); + + onTerminateAttachSession.dispose(); + }, session); + }}); // Start a child debug session to attach the dotnet debugger // TODO: Accommodate multi-folder workspaces if the C# code is in a different workspace folder From cb49997e9f1ca3d10317ca11f795a73bd16cc169 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Thu, 17 Aug 2023 18:37:05 -0700 Subject: [PATCH 02/13] Use a customRequest rather than StopDebugger for dotnet detach --- src/features/DebugSession.ts | 41 +++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 551540f8c8..d5bcc10e2e 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -375,35 +375,38 @@ 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})`); - // 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. - if (dotnetAttachSession.configuration.name == dotnetAttachConfig.name) { - const onTerminateAttachSession = debug.onDidTerminateDebugSession(async parentSession => { - // HACK: Force the "this" on this since we are supplying a "this" to the function via an argument. There probably is a type-safe way to do this, but because we also need a self-reference to the function in order to make it a one-time action, I'm not sure how to do it. - const dotnetAttachSession = this as unknown as DebugSession; + tempConsoleDotnetAttachSession = dotnetAttachSession; - if (parentSession.parentSession?.id !== dotnetAttachSession.id) {return;} + const stopDebugEvent = debug.onDidTerminateDebugSession( async tempConsoleSession => { + if (tempConsoleDotnetAttachSession.parentSession?.id !== tempConsoleSession.id) {return;} - this.logger.writeVerbose(`Powershell Binary Debug Session Stop Detected: ${dotnetAttachSession.name} (${dotnetAttachSession.id}), detaching dotnet debugger.`); + // Makes the event one-time + stopDebugEvent.dispose(); - await dotnetAttachSession.customRequest( - "disconnect", - { - restart: false, - terminateDebuggee: false, - suspendDebuggee: false - } - ); + this.logger.writeVerbose(`Debugger session terminated: ${tempConsoleSession.name} (${tempConsoleSession.id})`); - onTerminateAttachSession.dispose(); - }, session); - }}); + // 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. + await dotnetAttachSession.customRequest( + "disconnect", + { + restart: false, + terminateDebuggee: false, + suspendDebuggee: false + } + ); + }); + }); // Start a child debug session to attach the dotnet debugger // TODO: Accommodate multi-folder workspaces if the C# code is in a different workspace folder From 74809c22482b2602dc2c8e09a6ee6390e1f43f35 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Fri, 18 Aug 2023 13:57:15 -0700 Subject: [PATCH 03/13] Strong type disconnectArguments in the debug protocol --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/features/DebugSession.ts | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index b667841bec..77467f01e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,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", @@ -1297,6 +1298,12 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@vscode/debugprotocol": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.61.0.tgz", + "integrity": "sha512-K/kF27jIStVFqlmUaGc2u+Dj8IR7YdEiSqShWr7MWhDudqpAW7uu7XMwoFwjpuC9LSaVwJMIX7EFC5OJ/RmnDQ==", + "dev": true + }, "node_modules/@vscode/extension-telemetry": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.8.2.tgz", @@ -6064,6 +6071,12 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "@vscode/debugprotocol": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.61.0.tgz", + "integrity": "sha512-K/kF27jIStVFqlmUaGc2u+Dj8IR7YdEiSqShWr7MWhDudqpAW7uu7XMwoFwjpuC9LSaVwJMIX7EFC5OJ/RmnDQ==", + "dev": true + }, "@vscode/extension-telemetry": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.8.2.tgz", diff --git a/package.json b/package.json index 8125a7fbc3..fa71b22e75 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index d5bcc10e2e..636e90e736 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -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"; @@ -403,7 +404,7 @@ export class DebugSessionFeature extends LanguageClientConsumer restart: false, terminateDebuggee: false, suspendDebuggee: false - } + } as DebugProtocol.DisconnectArguments ); }); }); From 2c00a1d6068494039baede73de3fda59d54aaaac Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Fri, 18 Aug 2023 14:26:32 -0700 Subject: [PATCH 04/13] Use full request type for better intellisense --- src/features/DebugSession.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 636e90e736..8be610c29a 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -398,13 +398,20 @@ export class DebugSessionFeature extends LanguageClientConsumer 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. - await dotnetAttachSession.customRequest( - "disconnect", - { + const disconnectRequest: DebugProtocol.DisconnectRequest = { + command: "disconnect", + seq: 0, + type: "request", + arguments: { restart: false, terminateDebuggee: false, suspendDebuggee: false - } as DebugProtocol.DisconnectArguments + } + }; + + await dotnetAttachSession.customRequest( + disconnectRequest.command, + disconnectRequest.arguments ); }); }); From 52f43a464a6529cf905c0362a4c2bb6ff7e20060 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 08:22:52 -0700 Subject: [PATCH 05/13] Pin debugProtocol Co-authored-by: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa71b22e75..00bb89705c 100644 --- a/package.json +++ b/package.json @@ -96,7 +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/debugprotocol": "1.61.0", "@vscode/test-electron": "2.3.4", "@vscode/vsce": "2.20.1", "esbuild": "0.19.2", From 595078120a416092ba474b0b4245c9a4c744cf4a Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 08:22:59 -0700 Subject: [PATCH 06/13] Pin debugProtocol Co-authored-by: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 77467f01e2..b1317c7b29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,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/debugprotocol": "1.61.0", "@vscode/test-electron": "2.3.4", "@vscode/vsce": "2.20.1", "esbuild": "0.19.2", From 9c75adb583a0a5e55a639fb986fd611d98e60bfa Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 08:28:06 -0700 Subject: [PATCH 07/13] Cleanup space formatting --- src/features/DebugSession.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 8be610c29a..f37bf19621 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -378,7 +378,7 @@ export class DebugSessionFeature extends LanguageClientConsumer // 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. let tempConsoleDotnetAttachSession: DebugSession; const startDebugEvent = debug.onDidStartDebugSession(dotnetAttachSession => { - if (dotnetAttachSession.configuration.name != dotnetAttachConfig.name) {return;} + 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. @@ -389,8 +389,8 @@ export class DebugSessionFeature extends LanguageClientConsumer tempConsoleDotnetAttachSession = dotnetAttachSession; - const stopDebugEvent = debug.onDidTerminateDebugSession( async tempConsoleSession => { - if (tempConsoleDotnetAttachSession.parentSession?.id !== tempConsoleSession.id) {return;} + const stopDebugEvent = debug.onDidTerminateDebugSession(async tempConsoleSession => { + if (tempConsoleDotnetAttachSession.parentSession?.id !== tempConsoleSession.id) { return; } // Makes the event one-time stopDebugEvent.dispose(); From 40663dbf24bacefbfc20eb8976440898e7374e3a Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 11:30:10 -0700 Subject: [PATCH 08/13] Catch if dotnet debugger already stopped --- src/features/DebugSession.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index f37bf19621..20962a1ed2 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -409,10 +409,14 @@ export class DebugSessionFeature extends LanguageClientConsumer } }; - await dotnetAttachSession.customRequest( - disconnectRequest.command, - disconnectRequest.arguments - ); + try { + await dotnetAttachSession.customRequest( + disconnectRequest.command, + disconnectRequest.arguments + ); + } catch (err) { + this.logger.writeWarning(`Disconnect request to C# debugger failed: ${err}`); + } }); }); From 91ca6f74f643b4f901fd9e8882d5355a7575f62c Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 11:30:24 -0700 Subject: [PATCH 09/13] rename c# to dotnet --- src/features/DebugSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 20962a1ed2..884b01ee7f 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -415,7 +415,7 @@ export class DebugSessionFeature extends LanguageClientConsumer disconnectRequest.arguments ); } catch (err) { - this.logger.writeWarning(`Disconnect request to C# debugger failed: ${err}`); + this.logger.writeWarning(`Disconnect request to dotnet debugger failed: ${err}`); } }); }); From 1f6e11296898cdda1fc30d911bfe896e391e82e1 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 12:07:56 -0700 Subject: [PATCH 10/13] CI Trigger From 6d98f9560f35d8783a4357181cdc6452983343e4 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 12:21:07 -0700 Subject: [PATCH 11/13] Add slow markers for long running tests --- test/features/DebugSession.test.ts | 5 ++++- test/features/ISECompatibility.test.ts | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/features/DebugSession.test.ts b/test/features/DebugSession.test.ts index 3b9b854680..60e18021cc 100644 --- a/test/features/DebugSession.test.ts +++ b/test/features/DebugSession.test.ts @@ -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((resolve) => { const event = debug.onDidStartDebugSession((session) => { diff --git a/test/features/ISECompatibility.test.ts b/test/features/ISECompatibility.test.ts index 792c3dd7bb..0f2152c1c6 100644 --- a/test/features/ISECompatibility.test.ts +++ b/test/features/ISECompatibility.test.ts @@ -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 { From 9eaf7aceeac3f643bd76361f84d2f83c0ebaca64 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 12:47:26 -0700 Subject: [PATCH 12/13] CI Trigger From 4a67f3d957b146e04db1a89362620cad7af194b4 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Sun, 20 Aug 2023 14:48:55 -0700 Subject: [PATCH 13/13] CI Trigger