@@ -14,6 +14,7 @@ import { IEditorServicesSessionDetails, SessionManager, SessionStatus } from "..
1414import Settings = require( "../settings" ) ;
1515import { Logger } from "../logging" ;
1616import { LanguageClientConsumer } from "../languageClientConsumer" ;
17+ import path = require( "path" ) ;
1718
1819export const StartDebuggerNotificationType =
1920 new NotificationType < void > ( "powerShell/startDebugger" ) ;
@@ -121,7 +122,6 @@ export class DebugSessionFeature extends LanguageClientConsumer
121122 type : "PowerShell" ,
122123 request : "launch" ,
123124 script : "${file}" ,
124- cwd : "${file}" ,
125125 } ,
126126 ] ;
127127 case DebugConfig . LaunchScript :
@@ -130,8 +130,7 @@ export class DebugSessionFeature extends LanguageClientConsumer
130130 name : "PowerShell: Launch Script" ,
131131 type : "PowerShell" ,
132132 request : "launch" ,
133- script : "enter path or command to execute e.g.: ${workspaceFolder}/src/foo.ps1 or Invoke-Pester" ,
134- cwd : "${workspaceFolder}" ,
133+ script : "Enter path or command to execute, for example: \"${workspaceFolder}/src/foo.ps1\" or \"Invoke-Pester\"" ,
135134 } ,
136135 ] ;
137136 case DebugConfig . InteractiveSession :
@@ -140,7 +139,6 @@ export class DebugSessionFeature extends LanguageClientConsumer
140139 name : "PowerShell: Interactive Session" ,
141140 type : "PowerShell" ,
142141 request : "launch" ,
143- cwd : "" ,
144142 } ,
145143 ] ;
146144 case DebugConfig . AttachHostProcess :
@@ -155,168 +153,133 @@ export class DebugSessionFeature extends LanguageClientConsumer
155153 }
156154 }
157155
158- // DebugConfigurationProvider method
156+ // DebugConfigurationProvider methods
159157 public async resolveDebugConfiguration (
160158 _folder : WorkspaceFolder | undefined ,
161159 config : DebugConfiguration ,
162160 _token ?: CancellationToken ) : Promise < DebugConfiguration > {
163161
164- if ( this . sessionManager . getSessionStatus ( ) !== SessionStatus . Running ) {
165- await this . sessionManager . start ( ) ;
166- }
162+ // Prevent the Debug Console from opening
163+ config . internalConsoleOptions = "neverOpen" ;
167164
168- // Starting a debug session can be done when there is no document open e.g. attach to PS host process
169- const currentDocument = vscode . window . activeTextEditor ? vscode . window . activeTextEditor . document : undefined ;
170- const debugCurrentScript = ( config . script === "${file}" ) || ! config . request ;
171- const generateLaunchConfig = ! config . request ;
165+ // NOTE: We intentionally do not touch the `cwd` setting of the config.
172166
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.
173172 const settings = Settings . load ( ) ;
174-
175- // If the createTemporaryIntegratedConsole field is not specified in the launch config, set the field using
176- // the value from the corresponding setting. Otherwise, the launch config value overrides the setting.
177173 config . createTemporaryIntegratedConsole =
178174 config . createTemporaryIntegratedConsole ??
179175 settings . debugging . createTemporaryIntegratedConsole ;
180176
181- if ( config . request === "attach" ) {
182- const platformDetails = getPlatformDetails ( ) ;
183- const versionDetails = this . sessionManager . getPowerShellVersionDetails ( ) ;
184-
185- // Cross-platform attach to process was added in 6.2.0-preview.4
186- if ( versionDetails . version < "6.2.0" && platformDetails . operatingSystem !== OperatingSystem . Windows ) {
187- const msg = `Attaching to a PowerShell Host Process on ${
188- OperatingSystem [ platformDetails . operatingSystem ] } requires PowerShell 6.2 or higher.`;
189- return vscode . window . showErrorMessage ( msg ) . then ( ( _ ) => {
190- return undefined ;
191- } ) ;
192- }
193-
194- // if nothing is set, prompt for the processId
195- if ( ! config . customPipeName && ! config . processId ) {
196- config . processId = await vscode . commands . executeCommand ( "PowerShell.PickPSHostProcess" ) ;
197-
198- // No process selected. Cancel attach.
199- if ( ! config . processId ) {
200- return null ;
201- }
202- }
203-
204- if ( ! config . runspaceId && ! config . runspaceName ) {
205- config . runspaceId = await vscode . commands . executeCommand ( "PowerShell.PickRunspace" , config . processId ) ;
206-
207- // No runspace selected. Cancel attach.
208- if ( ! config . runspaceId ) {
209- return null ;
210- }
211- }
177+ if ( config . createTemporaryIntegratedConsole ) {
178+ this . tempDebugProcess = this . sessionManager . createDebugSessionProcess ( settings ) ;
179+ this . tempSessionDetails = await this . tempDebugProcess . start ( `DebugSession-${ this . sessionCount ++ } ` ) ;
212180 }
213181
214- // TODO: Use a named debug configuration.
215- if ( generateLaunchConfig ) {
216- // No launch.json, create the default configuration for both unsaved (Untitled) and saved documents.
182+ if ( ! config . request ) {
183+ // No launch.json, create the default configuration for both unsaved
184+ // (Untitled) and saved documents.
185+ config . current_document = true ;
217186 config . type = "PowerShell" ;
218187 config . name = "PowerShell: Launch Current File" ;
219188 config . request = "launch" ;
220189 config . args = [ ] ;
190+ config . script = "${file}"
191+ }
221192
222- config . script =
223- currentDocument . isUntitled
224- ? currentDocument . uri . toString ( )
225- : currentDocument . fileName ;
226-
227- if ( config . createTemporaryIntegratedConsole ) {
228- // For a folder-less workspace, vscode.workspace.rootPath will be undefined.
229- // PSES will convert that undefined to a reasonable working dir.
230- config . cwd =
231- currentDocument . isUntitled
232- ? vscode . workspace . rootPath
233- : currentDocument . fileName ;
234-
235- } else {
236- // If the non-temp Extension Terminal is being used, default to the current working dir.
237- config . cwd = "" ;
193+ if ( config . script === "${file}" || config . script === "${relativeFile}" ) {
194+ if ( vscode . window . activeTextEditor === undefined ) {
195+ vscode . window . showErrorMessage ( "To debug the 'Current File', you must first open a PowerShell script file in the editor." ) ;
196+ return undefined ;
197+ }
198+ config . current_document = true ;
199+ // Special case using the URI for untitled documents.
200+ const currentDocument = vscode . window . activeTextEditor . document ;
201+ if ( currentDocument . isUntitled ) {
202+ config . untitled_document = true ;
203+ config . script = currentDocument . uri . toString ( ) ;
238204 }
239205 }
240206
241- if ( config . request === "launch" ) {
242- // For debug launch of "current script" (saved or unsaved), warn before starting the debugger if either
243- // A) there is not an active document
244- // B) the unsaved document's language type is not PowerShell
245- // C) the saved document's extension is a type that PowerShell can't debug.
246- if ( debugCurrentScript ) {
247-
248- if ( currentDocument === undefined ) {
249- const msg = "To debug the \"Current File\", you must first open a " +
250- "PowerShell script file in the editor." ;
251- vscode . window . showErrorMessage ( msg ) ;
252- return ;
253- }
254-
255- if ( currentDocument . isUntitled ) {
256- if ( config . createTemporaryIntegratedConsole ) {
257- const msg = "Debugging Untitled files in a temporary console is currently not supported." ;
258- vscode . window . showErrorMessage ( msg ) ;
259- return ;
260- }
261-
262- if ( currentDocument . languageId === "powershell" ) {
263- if ( ! generateLaunchConfig ) {
264- // Cover the case of existing launch.json but unsaved (Untitled) document.
265- // In this case, vscode.workspace.rootPath will not be undefined.
266- config . script = currentDocument . uri . toString ( ) ;
267- config . cwd = vscode . workspace . rootPath ;
268- }
269- } else {
270- const msg = "To debug '" + currentDocument . fileName + "', change the document's " +
271- "language mode to PowerShell or save the file with a PowerShell extension." ;
272- vscode . window . showErrorMessage ( msg ) ;
273- return ;
274- }
275- } else {
276- let isValidExtension = false ;
277- const extIndex = currentDocument . fileName . lastIndexOf ( "." ) ;
278- if ( extIndex !== - 1 ) {
279- const ext = currentDocument . fileName . substr ( extIndex + 1 ) . toUpperCase ( ) ;
280- isValidExtension = ( ext === "PS1" || ext === "PSM1" ) ;
281- }
282-
283- if ( ( currentDocument . languageId !== "powershell" ) || ! isValidExtension ) {
284- let docPath = currentDocument . fileName ;
285- const workspaceRootPath = vscode . workspace . rootPath ;
286- if ( currentDocument . fileName . startsWith ( workspaceRootPath ) ) {
287- docPath = currentDocument . fileName . substring ( vscode . workspace . rootPath . length + 1 ) ;
288- }
289-
290- const msg = "PowerShell does not support debugging this file type: '" + docPath + "'." ;
291- vscode . window . showErrorMessage ( msg ) ;
292- return ;
293- }
207+ return config ;
208+ }
294209
295- if ( config . script === "${file}" ) {
296- config . script = currentDocument . fileName ;
297- }
298- }
299- }
210+ public async resolveDebugConfigurationWithSubstitutedVariables (
211+ _folder : WorkspaceFolder | undefined ,
212+ config : DebugConfiguration ,
213+ _token ?: CancellationToken ) : Promise < DebugConfiguration > {
300214
301- // NOTE: There is a tight coupling to a weird setting in
302- // `package.json` for the Launch Current File configuration where
303- // the default cwd is set to ${file}.
304- if ( ( currentDocument !== undefined ) && ( config . cwd === "${file}" ) ) {
305- config . cwd = currentDocument . fileName ;
306- }
215+ if ( config . request === "attach" ) {
216+ config = await this . resolveAttachDebugConfiguration ( config ) ;
217+ } else if ( config . request === "launch" ) {
218+ config = await this . resolveLaunchDebugConfiguration ( config ) ;
219+ } else {
220+ vscode . window . showErrorMessage ( `The request type was invalid: '${ config . request } '` ) ;
221+ return null ;
307222 }
308223
309- // Prevent the Debug Console from opening
310- config . internalConsoleOptions = "neverOpen" ;
311-
312- // Create or show the interactive console
224+ // Start the PowerShell session if needed.
225+ if ( this . sessionManager . getSessionStatus ( ) !== SessionStatus . Running ) {
226+ await this . sessionManager . start ( ) ;
227+ }
228+ // Create or show the Extension Terminal.
313229 vscode . commands . executeCommand ( "PowerShell.ShowSessionConsole" , true ) ;
314230
315- if ( config . createTemporaryIntegratedConsole ) {
316- this . tempDebugProcess = this . sessionManager . createDebugSessionProcess ( settings ) ;
317- this . tempSessionDetails = await this . tempDebugProcess . start ( `DebugSession-${ this . sessionCount ++ } ` ) ;
231+ return config ;
232+ }
233+
234+ private async resolveLaunchDebugConfiguration ( config : DebugConfiguration ) : Promise < DebugConfiguration > {
235+ // Check the languageId only for current documents (which includes untitled documents).
236+ if ( config . current_document ) {
237+ const currentDocument = vscode . window . activeTextEditor . document ;
238+ if ( currentDocument . languageId !== "powershell" ) {
239+ vscode . window . showErrorMessage ( "Please change the current document's language mode to PowerShell." ) ;
240+ return undefined ;
241+ }
242+ }
243+ // Check the temporary console setting for untitled documents only, and
244+ // check the document extension for everything else.
245+ if ( config . untitled_document ) {
246+ if ( config . createTemporaryIntegratedConsole ) {
247+ vscode . window . showErrorMessage ( "Debugging untitled files in a temporary console is not supported." ) ;
248+ return undefined ;
249+ }
250+ } else {
251+ const ext = path . extname ( config . script ) . toLowerCase ( ) ;
252+ if ( ! ( ext === ".ps1" || ext === ".psm1" ) ) {
253+ vscode . window . showErrorMessage ( `PowerShell does not support debugging this file type: '${ path . basename ( config . script ) } '` ) ;
254+ return undefined ;
255+ }
318256 }
257+ return config ;
258+ }
319259
260+ private async resolveAttachDebugConfiguration ( config : DebugConfiguration ) : Promise < DebugConfiguration > {
261+ const platformDetails = getPlatformDetails ( ) ;
262+ const versionDetails = this . sessionManager . getPowerShellVersionDetails ( ) ;
263+ // Cross-platform attach to process was added in 6.2.0-preview.4.
264+ if ( versionDetails . version < "7.0.0" && platformDetails . operatingSystem !== OperatingSystem . Windows ) {
265+ vscode . window . showErrorMessage ( `Attaching to a PowerShell Host Process on ${ OperatingSystem [ platformDetails . operatingSystem ] } requires PowerShell 7.0 or higher.` ) ;
266+ return undefined ;
267+ }
268+ // If nothing is set, prompt for the processId.
269+ if ( ! config . customPipeName && ! config . processId ) {
270+ config . processId = await vscode . commands . executeCommand ( "PowerShell.PickPSHostProcess" ) ;
271+ // No process selected. Cancel attach.
272+ if ( ! config . processId ) {
273+ return null ;
274+ }
275+ }
276+ if ( ! config . runspaceId && ! config . runspaceName ) {
277+ config . runspaceId = await vscode . commands . executeCommand ( "PowerShell.PickRunspace" , config . processId ) ;
278+ // No runspace selected. Cancel attach.
279+ if ( ! config . runspaceId ) {
280+ return null ;
281+ }
282+ }
320283 return config ;
321284 }
322285}
0 commit comments