Skip to content

Commit ec53532

Browse files
committed
Add option for debugging scripts in a temporary Integrated Console
This change enables the user to configure their debugging sessions to launch a temporary Integrated Console each time they start the debugger. This is useful when debugging scripts or modules which use PowerShell classes or managed assemblies which cannot be reloaded within the same process. Resolves #367.
1 parent a60aae0 commit ec53532

File tree

7 files changed

+145
-32
lines changed

7 files changed

+145
-32
lines changed

Diff for: examples/.vscode/launch.json

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@
99
"args": [],
1010
"cwd": "${file}"
1111
},
12+
{
13+
"type": "PowerShell",
14+
"request": "launch",
15+
"name": "PowerShell Launch Current File in Temporary Console",
16+
"script": "${file}",
17+
"args": [],
18+
"cwd": "${file}",
19+
"createTemporaryIntegratedConsole": true
20+
},
1221
{
1322
"type": "PowerShell",
1423
"request": "launch",

Diff for: package.json

+32
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,19 @@
211211
"cwd": "^\"\\${file}\""
212212
}
213213
},
214+
{
215+
"label": "PowerShell: Launch Current File in Temporary Console",
216+
"description": "Launch current file (in active editor window) under debugger in a temporary Integrated Console.",
217+
"body": {
218+
"type": "PowerShell",
219+
"request": "launch",
220+
"name": "PowerShell Launch Current File in Temporary Console",
221+
"script": "^\"\\${file}\"",
222+
"args": [],
223+
"cwd": "^\"\\${file}\"",
224+
"createTemporaryIntegratedConsole": true
225+
}
226+
},
214227
{
215228
"label": "PowerShell: Launch - Current File w/Args Prompt",
216229
"description": "Launch current file (in active editor window) under debugger, prompting first for script arguments",
@@ -292,6 +305,11 @@
292305
"type": "string",
293306
"description": "Absolute path to the working directory. Default is the current workspace.",
294307
"default": "${workspaceRoot}"
308+
},
309+
"createTemporaryIntegratedConsole": {
310+
"type": "boolean",
311+
"description": "Determines whether a temporary PowerShell Integrated Console is created for each debugging session, useful for debugging PowerShell classes and binary modules. Overrides the user setting 'powershell.debugging.createTemporaryIntegratedConsole'.",
312+
"default": false
295313
}
296314
}
297315
},
@@ -323,6 +341,15 @@
323341
"args": [],
324342
"cwd": "${file}"
325343
},
344+
{
345+
"type": "PowerShell",
346+
"request": "launch",
347+
"name": "PowerShell Launch Current File in Temporary Console",
348+
"script": "${file}",
349+
"args": [],
350+
"cwd": "${file}",
351+
"createTemporaryIntegratedConsole": true
352+
},
326353
{
327354
"type": "PowerShell",
328355
"request": "launch",
@@ -448,6 +475,11 @@
448475
"default": true,
449476
"description": "Switches focus to the console when a script selection is run or a script file is debugged. This is an accessibility feature. To disable it, set to false."
450477
},
478+
"powershell.debugging.createTemporaryIntegratedConsole": {
479+
"type": "boolean",
480+
"default": false,
481+
"description": "Determines whether a temporary PowerShell Integrated Console is created for each debugging session, useful for debugging PowerShell classes and binary modules."
482+
},
451483
"powershell.developer.bundledModulesPath": {
452484
"type": "string",
453485
"description": "Specifies an alternate path to the folder containing modules that are bundled with the PowerShell extension (i.e. PowerShell Editor Services, PSScriptAnalyzer, Plaster)"

Diff for: scripts/Start-EditorServices.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ param(
5555
[switch]
5656
$EnableConsoleRepl,
5757

58-
[string]
58+
[switch]
5959
$DebugServiceOnly,
6060

6161
[string[]]

Diff for: src/features/DebugSession.ts

+41-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import vscode = require('vscode');
66
import utils = require('../utils');
7+
import Settings = require('../settings');
78
import { IFeature } from '../feature';
89
import { SessionManager } from '../session';
910
import { LanguageClient, RequestType, NotificationType } from 'vscode-languageclient';
@@ -13,6 +14,8 @@ export namespace StartDebuggerNotification {
1314
}
1415

1516
export class DebugSessionFeature implements IFeature {
17+
18+
private sessionCount: number = 1;
1619
private command: vscode.Disposable;
1720
private examplesPath: string;
1821

@@ -42,6 +45,9 @@ export class DebugSessionFeature implements IFeature {
4245
let debugCurrentScript = (config.script === "${file}") || !config.request;
4346
let generateLaunchConfig = !config.request;
4447

48+
var settings = Settings.load();
49+
let createNewIntegratedConsole = settings.debugging.createTemporaryIntegratedConsole;
50+
4551
if (generateLaunchConfig) {
4652
// No launch.json, create the default configuration for both unsaved (Untitled) and saved documents.
4753
config.type = 'PowerShell';
@@ -106,20 +112,50 @@ export class DebugSessionFeature implements IFeature {
106112
}
107113
}
108114
}
115+
116+
if (config.createTemporaryIntegratedConsole !== undefined) {
117+
createNewIntegratedConsole = config.createTemporaryIntegratedConsole;
118+
}
109119
}
110120

111121
// Prevent the Debug Console from opening
112122
config.internalConsoleOptions = "neverOpen";
113123

114124
// Create or show the interactive console
115-
// TODO #367: Check if "newSession" mode is configured
116125
vscode.commands.executeCommand('PowerShell.ShowSessionConsole', true);
117126

118-
// Write out temporary debug session file
119-
utils.writeSessionFile(
120-
utils.getDebugSessionFilePath(),
121-
this.sessionManager.getSessionDetails());
127+
var sessionFilePath = utils.getDebugSessionFilePath();
128+
129+
if (createNewIntegratedConsole) {
130+
var debugProcess =
131+
this.sessionManager.createDebugSessionProcess(
132+
sessionFilePath,
133+
settings);
134+
135+
debugProcess
136+
.start(`DebugSession-${this.sessionCount++}`)
137+
.then(
138+
sessionDetails => {
139+
this.startDebugger(
140+
config,
141+
sessionFilePath,
142+
sessionDetails);
143+
});
144+
}
145+
else {
146+
this.startDebugger(
147+
config,
148+
sessionFilePath,
149+
this.sessionManager.getSessionDetails());
150+
}
151+
}
152+
153+
private startDebugger(
154+
config: any,
155+
sessionFilePath: string,
156+
sessionDetails: utils.EditorServicesSessionDetails) {
122157

158+
utils.writeSessionFile(sessionFilePath, sessionDetails);
123159
vscode.commands.executeCommand('vscode.startDebug', config);
124160
}
125161
}

Diff for: src/process.ts

+9-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { Logger } from './logging';
1515

1616
export class PowerShellProcess {
1717

18-
private sessionFilePath: string;
1918
private consoleTerminal: vscode.Terminal = undefined;
2019
private consoleCloseSubscription: vscode.Disposable;
2120
private sessionDetails: utils.EditorServicesSessionDetails;
@@ -25,15 +24,14 @@ export class PowerShellProcess {
2524

2625
constructor(
2726
public exePath: string,
27+
private title: string,
2828
private log: Logger,
29+
private startArgs: string,
30+
private sessionFilePath: string,
2931
private sessionSettings: Settings.ISettings) {
30-
31-
this.sessionFilePath =
32-
utils.getSessionFilePath(
33-
Math.floor(100000 + Math.random() * 900000));
3432
}
3533

36-
public start(startArgs: string): Thenable<utils.EditorServicesSessionDetails> {
34+
public start(logFileName: string): Thenable<utils.EditorServicesSessionDetails> {
3735

3836
return new Promise<utils.EditorServicesSessionDetails>(
3937
(resolve, reject) => {
@@ -44,14 +42,14 @@ export class PowerShellProcess {
4442
__dirname,
4543
'../scripts/Start-EditorServices.ps1');
4644

47-
var editorServicesLogPath = this.log.getLogFilePath("EditorServices");
45+
var editorServicesLogPath = this.log.getLogFilePath(logFileName);
4846

4947
var featureFlags =
5048
this.sessionSettings.developer.featureFlags !== undefined
5149
? this.sessionSettings.developer.featureFlags.map(f => `'${f}'`).join(', ')
5250
: "";
5351

54-
startArgs +=
52+
this.startArgs +=
5553
`-LogPath '${editorServicesLogPath}' ` +
5654
`-SessionDetailsPath '${this.sessionFilePath}' ` +
5755
`-FeatureFlags @(${featureFlags})`
@@ -68,7 +66,7 @@ export class PowerShellProcess {
6866

6967
powerShellArgs.push(
7068
"-Command",
71-
"& '" + startScriptPath + "' " + startArgs);
69+
"& '" + startScriptPath + "' " + this.startArgs);
7270

7371
var powerShellExePath = this.exePath;
7472

@@ -95,7 +93,7 @@ export class PowerShellProcess {
9593
// Launch PowerShell in the integrated terminal
9694
this.consoleTerminal =
9795
vscode.window.createTerminal(
98-
"PowerShell Integrated Console",
96+
this.title,
9997
powerShellExePath,
10098
powerShellArgs);
10199

@@ -148,7 +146,7 @@ export class PowerShellProcess {
148146
"powershell.exe started --",
149147
" pid: " + pid,
150148
" exe: " + powerShellExePath,
151-
" args: " + startScriptPath + ' ' + startArgs + os.EOL + os.EOL);
149+
" args: " + startScriptPath + ' ' + this.startArgs + os.EOL + os.EOL);
152150
});
153151
}
154152
catch (e)

Diff for: src/session.ts

+43-15
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ export class SessionManager implements Middleware {
3636

3737
private hostVersion: string;
3838
private isWindowsOS: boolean;
39+
private editorServicesArgs: string;
3940
private powerShellExePath: string = "";
4041
private sessionStatus: SessionStatus;
4142
private suppressRestartPrompt: boolean;
4243
private focusConsoleOnExecute: boolean;
4344
private extensionFeatures: IFeature[] = [];
4445
private statusBarItem: vscode.StatusBarItem;
45-
private powerShellProcess: PowerShellProcess;
46+
private languageServerProcess: PowerShellProcess;
47+
private debugSessionProcess: PowerShellProcess;
4648
private versionDetails: PowerShellVersionDetails;
4749
private registeredCommands: vscode.Disposable[] = [];
4850
private languageServerClient: LanguageClient = undefined;
@@ -139,7 +141,7 @@ export class SessionManager implements Middleware {
139141
}
140142
}
141143

142-
var startArgs =
144+
this.editorServicesArgs =
143145
"-EditorServicesVersion '" + this.requiredEditorServicesVersion + "' " +
144146
"-HostName 'Visual Studio Code Host' " +
145147
"-HostProfileId 'Microsoft.VSCode' " +
@@ -149,17 +151,17 @@ export class SessionManager implements Middleware {
149151
"-EnableConsoleRepl ";
150152

151153
if (this.sessionSettings.developer.editorServicesWaitForDebugger) {
152-
startArgs += '-WaitForDebugger ';
154+
this.editorServicesArgs += '-WaitForDebugger ';
153155
}
154156
if (this.sessionSettings.developer.editorServicesLogLevel) {
155-
startArgs += "-LogLevel '" + this.sessionSettings.developer.editorServicesLogLevel + "' "
157+
this.editorServicesArgs += "-LogLevel '" + this.sessionSettings.developer.editorServicesLogLevel + "' "
156158
}
157159

158160
this.startPowerShell(
159161
this.powerShellExePath,
160162
this.sessionSettings.developer.powerShellExeIsWindowsDevBuild,
161163
bundledModulesPath,
162-
startArgs);
164+
this.editorServicesArgs);
163165
}
164166
else {
165167
this.setSessionFailure("PowerShell could not be started, click 'Show Logs' for more details.");
@@ -175,7 +177,7 @@ export class SessionManager implements Middleware {
175177
// Before moving further, clear out the client and process if
176178
// the process is already dead (i.e. it crashed)
177179
this.languageServerClient = undefined;
178-
this.powerShellProcess = undefined;
180+
this.languageServerProcess = undefined;
179181
}
180182

181183
this.sessionStatus = SessionStatus.Stopping;
@@ -186,9 +188,12 @@ export class SessionManager implements Middleware {
186188
this.languageServerClient = undefined;
187189
}
188190

189-
// Kill the PowerShell process we spawned
190-
if (this.powerShellProcess) {
191-
this.powerShellProcess.dispose();
191+
// Kill the PowerShell proceses we spawned
192+
if (this.debugSessionProcess) {
193+
this.debugSessionProcess.dispose();
194+
}
195+
if (this.languageServerProcess) {
196+
this.languageServerProcess.dispose();
192197
}
193198

194199
this.sessionStatus = SessionStatus.NotStarted;
@@ -206,6 +211,22 @@ export class SessionManager implements Middleware {
206211
this.registeredCommands.forEach(command => { command.dispose(); });
207212
}
208213

214+
public createDebugSessionProcess(
215+
sessionPath: string,
216+
sessionSettings: Settings.ISettings): PowerShellProcess {
217+
218+
this.debugSessionProcess =
219+
new PowerShellProcess(
220+
this.powerShellExePath,
221+
"[DBG] PowerShell Integrated Console",
222+
this.log,
223+
this.editorServicesArgs + "-DebugServiceOnly ",
224+
sessionPath,
225+
sessionSettings);
226+
227+
return this.debugSessionProcess;
228+
}
229+
209230
private onConfigurationUpdated() {
210231
var settings = Settings.load();
211232

@@ -266,22 +287,29 @@ export class SessionManager implements Middleware {
266287
"Starting PowerShell...",
267288
SessionStatus.Initializing);
268289

269-
this.powerShellProcess =
290+
var sessionFilePath =
291+
utils.getSessionFilePath(
292+
Math.floor(100000 + Math.random() * 900000));
293+
294+
this.languageServerProcess =
270295
new PowerShellProcess(
271296
this.powerShellExePath,
297+
"PowerShell Integrated Console",
272298
this.log,
299+
startArgs,
300+
sessionFilePath,
273301
this.sessionSettings);
274302

275-
this.powerShellProcess.onExited(
303+
this.languageServerProcess.onExited(
276304
() => {
277305
if (this.sessionStatus === SessionStatus.Running) {
278306
this.setSessionStatus("Session exited", SessionStatus.Failed);
279307
this.promptForRestart();
280308
}
281309
});
282310

283-
this.powerShellProcess
284-
.start(startArgs)
311+
this.languageServerProcess
312+
.start("EditorServices")
285313
.then(
286314
sessionDetails => {
287315
this.sessionDetails = sessionDetails;
@@ -612,8 +640,8 @@ export class SessionManager implements Middleware {
612640
}
613641

614642
private showSessionConsole(isExecute?: boolean) {
615-
if (this.powerShellProcess) {
616-
this.powerShellProcess.showConsole(
643+
if (this.languageServerProcess) {
644+
this.languageServerProcess.showConsole(
617645
isExecute && !this.focusConsoleOnExecute);
618646
}
619647
}

0 commit comments

Comments
 (0)