Skip to content

Commit 66b1a15

Browse files
committed
Cleanup flow and breakout temporary console to dedicated functions
1 parent e08a782 commit 66b1a15

File tree

1 file changed

+82
-70
lines changed

1 file changed

+82
-70
lines changed

src/features/DebugSession.ts

+82-70
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@
33

44
import vscode = require("vscode");
55
import {
6-
CancellationToken, DebugConfiguration, DebugConfigurationProvider,
7-
ExtensionContext, WorkspaceFolder
6+
CancellationToken,
7+
DebugAdapterDescriptor,
8+
DebugAdapterDescriptorFactory,
9+
DebugAdapterExecutable,
10+
DebugAdapterNamedPipeServer,
11+
DebugConfiguration,
12+
DebugConfigurationProvider,
13+
DebugSession,
14+
ExtensionContext,
15+
WorkspaceFolder
816
} from "vscode";
917
import { NotificationType, RequestType } from "vscode-languageclient";
1018
import { LanguageClient } from "vscode-languageclient/node";
11-
import { getPlatformDetails, OperatingSystem } from "../platform";
19+
import { LanguageClientConsumer } from "../languageClientConsumer";
20+
import { ILogger } from "../logging";
21+
import { OperatingSystem, getPlatformDetails } from "../platform";
1222
import { PowerShellProcess } from "../process";
1323
import { IEditorServicesSessionDetails, SessionManager, SessionStatus } from "../session";
1424
import { getSettings } from "../settings";
15-
import { ILogger } from "../logging";
16-
import { LanguageClientConsumer } from "../languageClientConsumer";
1725
import path = require("path");
1826
import utils = require("../utils");
1927

@@ -31,7 +39,7 @@ enum DebugConfig {
3139
}
3240

3341
export class DebugSessionFeature extends LanguageClientConsumer
34-
implements DebugConfigurationProvider, vscode.DebugAdapterDescriptorFactory {
42+
implements DebugConfigurationProvider, DebugAdapterDescriptorFactory {
3543

3644
private sessionCount = 1;
3745
private tempDebugProcess: PowerShellProcess | undefined;
@@ -72,12 +80,14 @@ export class DebugSessionFeature extends LanguageClientConsumer
7280
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("PowerShell", this));
7381
}
7482

75-
createDebugAdapterDescriptor(
76-
session: vscode.DebugSession,
77-
_executable: vscode.DebugAdapterExecutable | undefined): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
83+
// This is our factory entrypoint hook to when a debug session starts, and where we will lazy initialize everything needed to do the debugging such as a temporary console if required
84+
public async createDebugAdapterDescriptor(
85+
session: DebugSession,
86+
_executable: DebugAdapterExecutable | undefined): Promise<DebugAdapterDescriptor | undefined> {
87+
// NOTE: A Promise meets the shape of a ProviderResult, which allows us to make this method async.
7888

7989
const sessionDetails = session.configuration.createTemporaryIntegratedConsole
80-
? this.tempSessionDetails
90+
? await this.createTemporaryIntegratedConsole(session)
8191
: this.sessionManager.getSessionDetails();
8292

8393
if (sessionDetails === undefined) {
@@ -88,7 +98,7 @@ export class DebugSessionFeature extends LanguageClientConsumer
8898
this.logger.writeVerbose(`Connecting to pipe: ${sessionDetails.debugServicePipeName}`);
8999
this.logger.writeVerbose(`Debug configuration: ${JSON.stringify(session.configuration)}`);
90100

91-
return new vscode.DebugAdapterNamedPipeServer(sessionDetails.debugServicePipeName);
101+
return new DebugAdapterNamedPipeServer(sessionDetails.debugServicePipeName);
92102
}
93103

94104
public dispose() {
@@ -114,6 +124,59 @@ export class DebugSessionFeature extends LanguageClientConsumer
114124
];
115125
}
116126

127+
public async createTemporaryIntegratedConsole(session: DebugSession) {
128+
const settings = getSettings();
129+
this.tempDebugProcess = await this.sessionManager.createDebugSessionProcess(settings);
130+
this.tempSessionDetails = await this.tempDebugProcess.start(`DebugSession-${this.sessionCount++}`);
131+
132+
// NOTE: Dotnet attach debugging is only currently supported if a temporary console is used, otherwise we get lots of lock conflicts from loading the assemblies
133+
if (session.configuration.attachDotnetDebugger) {
134+
if (!vscode.extensions.getExtension("ms-dotnettools.csharp")) {
135+
void this.logger.writeAndShowError("You specified attachDotnetDebugger in your PowerShell Launch configuration but the C# extension is not installed. Please install the C# extension and try again.");
136+
return undefined;
137+
}
138+
139+
// Will wait until the process is started and available before attaching
140+
const pid = await this.tempDebugProcess.getPid();
141+
if (pid === undefined) {
142+
void this.logger.writeAndShowError("Attach Dotnet Debugger was specified but the PowerShell temporary debug session failed to start. This is probably a bug.");
143+
return undefined;
144+
}
145+
146+
const dotnetDebuggerConfig = this.getDotnetNamedConfigOrDefault(session, pid);
147+
if (dotnetDebuggerConfig === undefined) {
148+
void this.logger.writeAndShowError(`You specified dotnetDebuggerConfigName in your PowerShell Launch configuration but a matching launch config was not found. Please ensure you have a coreclr attach config with the name ${session.configuration.dotnetDebuggerConfigName} in your launch.json file or remove dotnetDebuggerConfigName from your PowerShell Launch configuration to use the defaults`);
149+
return undefined;
150+
}
151+
152+
// Start a child debug session to attach the dotnet debugger
153+
// TODO: Accomodate multi-folder workspaces if the C# code is in a different workspace folder
154+
await vscode.debug.startDebugging(undefined, dotnetDebuggerConfig, session);
155+
this.logger.write(`Attached dotnet debugger to process ${pid}`);
156+
}
157+
return this.tempSessionDetails;
158+
}
159+
160+
public getDotnetNamedConfigOrDefault(session: DebugSession, pid: number) {
161+
if (session.configuration.dotnetDebuggerConfigName) {
162+
const debugConfigs = vscode.workspace.getConfiguration("launch").get<DebugConfiguration[]>("configurations") ?? [];
163+
164+
return debugConfigs.find((config) => {
165+
return config.type === "coreclr"
166+
&& config.request === "attach"
167+
&& config.name === config.dotnetDebuggerConfigName;
168+
});
169+
}
170+
171+
// Default debugger config if none provided
172+
return {
173+
name: "Dotnet Debugger: PSIC Temporary Console",
174+
type: "coreclr",
175+
request: "attach",
176+
processId: pid
177+
};
178+
}
179+
117180
public async provideDebugConfigurations(
118181
_folder: WorkspaceFolder | undefined,
119182
_token?: CancellationToken): Promise<DebugConfiguration[]> {
@@ -159,66 +222,8 @@ export class DebugSessionFeature extends LanguageClientConsumer
159222
config: DebugConfiguration,
160223
_token?: CancellationToken): Promise<DebugConfiguration | undefined> {
161224

162-
// Prevent the Debug Console from opening
163-
config.internalConsoleOptions = "neverOpen";
164-
165225
// NOTE: We intentionally do not touch the `cwd` setting of the config.
166226

167-
// If the createTemporaryIntegratedConsole field is not specified in the
168-
// launch config, set the field using the value from the corresponding
169-
// setting. Otherwise, the launch config value overrides the setting.
170-
//
171-
// Also start the temporary process and console for this configuration.
172-
const settings = getSettings();
173-
config.createTemporaryIntegratedConsole =
174-
config.createTemporaryIntegratedConsole ??
175-
settings.debugging.createTemporaryIntegratedConsole;
176-
177-
if (config.createTemporaryIntegratedConsole) {
178-
this.tempDebugProcess = await this.sessionManager.createDebugSessionProcess(settings);
179-
this.tempSessionDetails = await this.tempDebugProcess.start(`DebugSession-${this.sessionCount++}`);
180-
181-
// This only works if in a temporary console
182-
if (config.attachDotnetDebugger) {
183-
184-
if (!vscode.extensions.getExtension("ms-dotnettools.csharp")) {
185-
this.logger.writeAndShowError("You specified attachDotnetDebugger in your PowerShell Launch configuration but the C# extension is not installed. Please install the C# extension and try again.");
186-
return undefined;
187-
}
188-
189-
// Will wait until the process is started and available before attaching
190-
const pid = await this.tempDebugProcess.getPid();
191-
192-
if (config.dotnetDebuggerConfigName) {
193-
const debugConfigs = vscode.workspace.getConfiguration('launch').get<DebugConfiguration[]>('configurations') || [];
194-
195-
const configMatch = debugConfigs.find((config) => {
196-
return config.type === "coreclr"
197-
&& config.request === "attach"
198-
&& config.name === config.dotnetDebuggerConfigName;
199-
});
200-
201-
if (!configMatch) {
202-
this.logger.writeAndShowError(`You specified dotnetDebuggerConfigName in your PowerShell Launch configuration but a matching launch config was not found. Please ensure you have a coreclr attach config with the name ${config.dotnetDebuggerConfigName} in your launch.json file or remove dotnetDebuggerConfigName from your PowerShell Launch configuration to use the defaults`);
203-
204-
// Fail the debug session by returning undefined
205-
return undefined;
206-
}
207-
return configMatch;
208-
}
209-
210-
// Start a secondary debug session to attach the dotnet debugger
211-
// TODO: Accomodate multi-folder workspaces if the C# code is in a different workspace folder
212-
await vscode.debug.startDebugging(undefined, {
213-
name: "Dotnet Debugger: PSIC Temporary Console",
214-
type: "coreclr",
215-
request: "attach",
216-
processId: pid
217-
});
218-
this.logger.write(`Attached dotnet debugger to process ${pid}`);
219-
}
220-
}
221-
222227
if (!config.request) {
223228
// No launch.json, create the default configuration for both unsaved
224229
// (Untitled) and saved documents.
@@ -227,9 +232,15 @@ export class DebugSessionFeature extends LanguageClientConsumer
227232
config.current_document = true;
228233
}
229234

235+
// Prevent the Debug Console from opening
236+
config.internalConsoleOptions = "neverOpen";
237+
238+
const settings = getSettings();
239+
config.createTemporaryIntegratedConsole ??= settings.debugging.createTemporaryIntegratedConsole;
240+
230241
if (config.script === "${file}" || config.script === "${relativeFile}") {
231242
if (vscode.window.activeTextEditor === undefined) {
232-
void this.logger.writeAndShowError("To debug the 'Current File', you must first open a PowerShell script file in the editor.");
243+
await this.logger.writeAndShowError("To debug the 'Current File', you must first open a PowerShell script file in the editor.");
233244
return undefined;
234245
}
235246
config.current_document = true;
@@ -259,6 +270,7 @@ export class DebugSessionFeature extends LanguageClientConsumer
259270
return null;
260271
}
261272

273+
// TODO: This should move to createDebugAdapterDescriptor
262274
if (resolvedConfig) {
263275
// Start the PowerShell session if needed.
264276
if (this.sessionManager.getSessionStatus() !== SessionStatus.Running) {

0 commit comments

Comments
 (0)