@@ -80,6 +80,20 @@ export class DebugSessionFeature implements IFeature, DebugConfigurationProvider
8080 // if nothing is set, prompt for the processId
8181 if ( ! config . customPipeName && ! config . processId ) {
8282 config . processId = await vscode . commands . executeCommand ( "PowerShell.PickPSHostProcess" ) ;
83+
84+ // No process selected. Cancel attach.
85+ if ( ! config . processId ) {
86+ return null ;
87+ }
88+ }
89+
90+ if ( ! config . runspaceId ) {
91+ config . runspaceId = await vscode . commands . executeCommand ( "PowerShell.PickRunspace" , config . processId ) ;
92+
93+ // No runspace selected. Cancel attach.
94+ if ( ! config . runspaceId ) {
95+ return null ;
96+ }
8397 }
8498 }
8599
@@ -386,3 +400,122 @@ export class PickPSHostProcessFeature implements IFeature {
386400 }
387401 }
388402}
403+
404+ interface IRunspaceItem extends vscode . QuickPickItem {
405+ id : string ; // payload for the QuickPick UI
406+ }
407+
408+ interface IRunspace {
409+ id : number ;
410+ name : string ;
411+ availability : string ;
412+ }
413+
414+ export const GetRunspaceRequestType =
415+ new RequestType < any , IRunspace [ ] , string , void > ( "powerShell/getRunspace" ) ;
416+
417+ export class PickRunspaceFeature implements IFeature {
418+
419+ private command : vscode . Disposable ;
420+ private languageClient : LanguageClient ;
421+ private waitingForClientToken : vscode . CancellationTokenSource ;
422+ private getLanguageClientResolve : ( value ?: LanguageClient | Thenable < LanguageClient > ) => void ;
423+
424+ constructor ( ) {
425+ this . command =
426+ vscode . commands . registerCommand ( "PowerShell.PickRunspace" , ( processId ) => {
427+ return this . getLanguageClient ( )
428+ . then ( ( _ ) => this . pickRunspace ( processId ) , ( _ ) => undefined ) ;
429+ } , this ) ;
430+ }
431+
432+ public setLanguageClient ( languageClient : LanguageClient ) {
433+ this . languageClient = languageClient ;
434+
435+ if ( this . waitingForClientToken ) {
436+ this . getLanguageClientResolve ( this . languageClient ) ;
437+ this . clearWaitingToken ( ) ;
438+ }
439+ }
440+
441+ public dispose ( ) {
442+ this . command . dispose ( ) ;
443+ }
444+
445+ private getLanguageClient ( ) : Thenable < LanguageClient > {
446+ if ( this . languageClient ) {
447+ return Promise . resolve ( this . languageClient ) ;
448+ } else {
449+ // If PowerShell isn't finished loading yet, show a loading message
450+ // until the LanguageClient is passed on to us
451+ this . waitingForClientToken = new vscode . CancellationTokenSource ( ) ;
452+
453+ return new Promise < LanguageClient > (
454+ ( resolve , reject ) => {
455+ this . getLanguageClientResolve = resolve ;
456+
457+ vscode . window
458+ . showQuickPick (
459+ [ "Cancel" ] ,
460+ { placeHolder : "Attach to PowerShell host process: Please wait, starting PowerShell..." } ,
461+ this . waitingForClientToken . token )
462+ . then ( ( response ) => {
463+ if ( response === "Cancel" ) {
464+ this . clearWaitingToken ( ) ;
465+ reject ( ) ;
466+ }
467+ } ) ;
468+
469+ // Cancel the loading prompt after 60 seconds
470+ setTimeout ( ( ) => {
471+ if ( this . waitingForClientToken ) {
472+ this . clearWaitingToken ( ) ;
473+ reject ( ) ;
474+
475+ vscode . window . showErrorMessage (
476+ "Attach to PowerShell host process: PowerShell session took too long to start." ) ;
477+ }
478+ } , 60000 ) ;
479+ } ,
480+ ) ;
481+ }
482+ }
483+
484+ private pickRunspace ( processId ) : Thenable < string > {
485+ return this . languageClient . sendRequest ( GetRunspaceRequestType , processId ) . then ( ( response ) => {
486+ const items : IRunspaceItem [ ] = [ ] ;
487+
488+ for ( const runspace of response ) {
489+ // Skip default runspace
490+ if ( runspace . id === 1 || runspace . name === "PSAttachRunspace" ) {
491+ continue ;
492+ }
493+
494+ items . push ( {
495+ label : runspace . name ,
496+ description : `ID: ${ runspace . id } - ${ runspace . availability } ` ,
497+ id : runspace . id . toString ( ) ,
498+ } ) ;
499+ }
500+
501+ const options : vscode . QuickPickOptions = {
502+ placeHolder : "Select PowerShell runspace to debug" ,
503+ matchOnDescription : true ,
504+ matchOnDetail : true ,
505+ } ;
506+
507+ return vscode . window . showQuickPick ( items , options ) . then ( ( item ) => {
508+ // Return undefined when user presses Esc.
509+ // This prevents VSCode from opening launch.json in this case which happens if we return "".
510+ return item ? `${ item . id } ` : undefined ;
511+ } ) ;
512+ } ) ;
513+ }
514+
515+ private clearWaitingToken ( ) {
516+ if ( this . waitingForClientToken ) {
517+ this . waitingForClientToken . dispose ( ) ;
518+ this . waitingForClientToken = undefined ;
519+ }
520+ }
521+ }
0 commit comments