@@ -22,7 +22,10 @@ import {
22
22
InputBoxOptions ,
23
23
QuickPickItem ,
24
24
QuickPickOptions ,
25
- DebugConfigurationProviderTriggerKind
25
+ DebugConfigurationProviderTriggerKind ,
26
+ DebugAdapterTrackerFactory ,
27
+ DebugAdapterTracker ,
28
+ LogOutputChannel
26
29
} from "vscode" ;
27
30
import type { DebugProtocol } from "@vscode/debugprotocol" ;
28
31
import { NotificationType , RequestType } from "vscode-languageclient" ;
@@ -126,6 +129,7 @@ export class DebugSessionFeature extends LanguageClientConsumer
126
129
private tempSessionDetails : IEditorServicesSessionDetails | undefined ;
127
130
private commands : Disposable [ ] = [ ] ;
128
131
private handlers : Disposable [ ] = [ ] ;
132
+ private adapterName = "PowerShell" ;
129
133
130
134
constructor ( context : ExtensionContext , private sessionManager : SessionManager , private logger : ILogger ) {
131
135
super ( ) ;
@@ -165,12 +169,17 @@ export class DebugSessionFeature extends LanguageClientConsumer
165
169
DebugConfigurationProviderTriggerKind . Dynamic
166
170
] ;
167
171
172
+
168
173
for ( const triggerKind of triggers ) {
169
174
context . subscriptions . push (
170
- debug . registerDebugConfigurationProvider ( "PowerShell" , this , triggerKind ) ) ;
175
+ debug . registerDebugConfigurationProvider ( this . adapterName , this , triggerKind )
176
+ ) ;
171
177
}
172
178
173
- context . subscriptions . push ( debug . registerDebugAdapterDescriptorFactory ( "PowerShell" , this ) ) ;
179
+ context . subscriptions . push (
180
+ debug . registerDebugAdapterTrackerFactory ( this . adapterName , new PowerShellDebugAdapterTrackerFactory ( this . adapterName ) ) ,
181
+ debug . registerDebugAdapterDescriptorFactory ( this . adapterName , this )
182
+ ) ;
174
183
}
175
184
176
185
public override onLanguageClientSet ( languageClient : LanguageClient ) : void {
@@ -595,6 +604,70 @@ export class DebugSessionFeature extends LanguageClientConsumer
595
604
}
596
605
}
597
606
607
+ class PowerShellDebugAdapterTrackerFactory implements DebugAdapterTrackerFactory , Disposable {
608
+ disposables : Disposable [ ] = [ ] ;
609
+ dapLogEnabled : boolean = workspace . getConfiguration ( "powershell" ) . get < boolean > ( "trace.dap" ) ?? false ;
610
+ constructor ( private adapterName = "PowerShell" ) {
611
+ this . disposables . push ( workspace . onDidChangeConfiguration ( change => {
612
+ if (
613
+ change . affectsConfiguration ( "powershell.trace.dap" )
614
+ ) {
615
+ this . dapLogEnabled = workspace . getConfiguration ( "powershell" ) . get < boolean > ( "trace.dap" ) ?? false ;
616
+ if ( this . dapLogEnabled ) {
617
+ // Trigger the output pane to appear. This gives the user time to position it before starting a debug.
618
+ this . log ?. show ( true ) ;
619
+ }
620
+ }
621
+ } ) ) ;
622
+ }
623
+
624
+ /* We want to use a shared output log for separate debug sessions as usually only one is running at a time and we
625
+ * dont need an output window for every debug session. We also want to leave it active so user can copy and paste
626
+ * even on run end. When user changes the setting and disables it getter will return undefined, which will result
627
+ * in a noop for the logging activities, effectively pausing logging but not disposing the output channel. If the
628
+ * user re-enables, then logging resumes.
629
+ */
630
+ _log : LogOutputChannel | undefined ;
631
+ get log ( ) : LogOutputChannel | undefined {
632
+ if ( this . dapLogEnabled && this . _log === undefined ) {
633
+ this . _log = window . createOutputChannel ( `${ this . adapterName } Trace - DAP` , { log : true } ) ;
634
+ this . disposables . push ( this . _log ) ;
635
+ }
636
+ return this . dapLogEnabled ? this . _log : undefined ;
637
+ }
638
+
639
+ createDebugAdapterTracker ( session : DebugSession ) : DebugAdapterTracker {
640
+ const sessionInfo = `${ this . adapterName } Debug Session: ${ session . name } [${ session . id } ]` ;
641
+ return {
642
+ onWillStartSession : ( ) => this . log ?. info ( `Starting ${ sessionInfo } . Set log level to trace to see DAP messages beyond errors` ) ,
643
+ onWillStopSession : ( ) => this . log ?. info ( `Stopping ${ sessionInfo } ` ) ,
644
+ onExit : code => this . log ?. info ( `${ sessionInfo } exited with code ${ code } ` ) ,
645
+ onWillReceiveMessage : ( m ) : void => {
646
+ this . log ?. debug ( `▶️${ m . seq } ${ m . type } : ${ m . command } ` ) ;
647
+ if ( m . arguments && ( Array . isArray ( m . arguments ) ? m . arguments . length > 0 : Object . keys ( m . arguments ) . length > 0 ) ) {
648
+ this . log ?. trace ( `${ m . seq } : ` + JSON . stringify ( m . arguments , undefined , 2 ) ) ;
649
+ }
650
+ } ,
651
+ onDidSendMessage : ( m ) :void => {
652
+ const responseSummary = m . request_seq !== undefined
653
+ ? `${ m . success ? "✅" : "❌" } ${ m . request_seq } ${ m . type } (${ m . seq } ): ${ m . command } `
654
+ : `◀️${ m . seq } ${ m . type } : ${ m . event ?? m . command } ` ;
655
+ this . log ?. debug (
656
+ responseSummary
657
+ ) ;
658
+ if ( m . body && ( Array . isArray ( m . body ) ? m . body . length > 0 : Object . keys ( m . body ) . length > 0 ) ) {
659
+ this . log ?. trace ( `${ m . seq } : ` + JSON . stringify ( m . body , undefined , 2 ) ) ;
660
+ }
661
+ } ,
662
+ onError : e => this . log ?. error ( e ) ,
663
+ } ;
664
+ }
665
+
666
+ dispose ( ) : void {
667
+ this . disposables . forEach ( d => d . dispose ( ) ) ;
668
+ }
669
+ }
670
+
598
671
export class SpecifyScriptArgsFeature implements Disposable {
599
672
private command : Disposable ;
600
673
private context : ExtensionContext ;
0 commit comments