@@ -20,6 +20,9 @@ public class DebugAdapter : DebugAdapterBase
20
20
{
21
21
private EditorSession editorSession ;
22
22
private OutputDebouncer outputDebouncer ;
23
+ private object syncLock = new object ( ) ;
24
+ private bool isConfigurationDoneRequestComplete ;
25
+ private bool isLaunchRequestComplete ;
23
26
private string scriptPathToLaunch ;
24
27
private string arguments ;
25
28
@@ -65,6 +68,23 @@ protected override void Initialize()
65
68
this . SetRequestHandler ( EvaluateRequest . Type , this . HandleEvaluateRequest ) ;
66
69
}
67
70
71
+ protected Task LaunchScript ( RequestContext < object > requestContext )
72
+ {
73
+ return editorSession . PowerShellContext
74
+ . ExecuteScriptAtPath ( this . scriptPathToLaunch , this . arguments )
75
+ . ContinueWith (
76
+ async ( t ) => {
77
+ Logger . Write ( LogLevel . Verbose , "Execution completed, terminating..." ) ;
78
+
79
+ await requestContext . SendEvent (
80
+ TerminatedEvent . Type ,
81
+ null ) ;
82
+
83
+ // Stop the server
84
+ this . Stop ( ) ;
85
+ } ) ;
86
+ }
87
+
68
88
protected override void Shutdown ( )
69
89
{
70
90
// Make sure remaining output is flushed before exiting
@@ -81,6 +101,31 @@ protected override void Shutdown()
81
101
82
102
#region Built-in Message Handlers
83
103
104
+ protected async Task HandleConfigurationDoneRequest (
105
+ object args ,
106
+ RequestContext < object > requestContext )
107
+ {
108
+ // Ensure that only the second message between launch and
109
+ // configurationDone - actually launches the script.
110
+ lock ( syncLock )
111
+ {
112
+ if ( ! this . isLaunchRequestComplete )
113
+ {
114
+ this . isConfigurationDoneRequestComplete = true ;
115
+ }
116
+ }
117
+
118
+ // The order of debug protocol messages apparently isn't as guaranteed as we might like.
119
+ // Need to be able to handle the case where we get configurationDone after launch request
120
+ // and vice-versa.
121
+ if ( this . isLaunchRequestComplete )
122
+ {
123
+ this . LaunchScript ( requestContext ) ;
124
+ }
125
+
126
+ await requestContext . SendResult ( null ) ;
127
+ }
128
+
84
129
protected async Task HandleLaunchRequest (
85
130
LaunchRequestArguments launchParams ,
86
131
RequestContext < object > requestContext )
@@ -114,14 +159,32 @@ protected async Task HandleLaunchRequest(
114
159
Logger . Write ( LogLevel . Verbose , "Script arguments are: " + arguments ) ;
115
160
}
116
161
117
- // NOTE: We don't actually launch the script in response to this
118
- // request. We wait until we receive the configurationDone request
119
- // to actually launch the script under the debugger. This gives
120
- // us and VSCode a chance to finish configuring all the types of
121
- // breakpoints.
162
+ // We may not actually launch the script in response to this
163
+ // request unless it comes after the configurationDone request.
164
+ // If the launch request comes first, then stash the launch
165
+ // params so that the subsequent configurationDone request can
166
+ // launch the script.
122
167
this . scriptPathToLaunch = launchParams . Program ;
123
168
this . arguments = arguments ;
124
169
170
+ // Ensure that only the second message between launch and
171
+ // configurationDone - actually launches the script.
172
+ lock ( syncLock )
173
+ {
174
+ if ( ! this . isConfigurationDoneRequestComplete )
175
+ {
176
+ this . isLaunchRequestComplete = true ;
177
+ }
178
+ }
179
+
180
+ // The order of debug protocol messages apparently isn't as guaranteed as we might like.
181
+ // Need to be able to handle the case where we get configurationDone after launch request
182
+ // and vice-versa.
183
+ if ( this . isConfigurationDoneRequestComplete )
184
+ {
185
+ this . LaunchScript ( requestContext ) ;
186
+ }
187
+
125
188
await requestContext . SendResult ( null ) ;
126
189
}
127
190
@@ -133,31 +196,6 @@ protected Task HandleAttachRequest(
133
196
throw new NotImplementedException ( ) ;
134
197
}
135
198
136
- protected async Task HandleConfigurationDoneRequest (
137
- object args ,
138
- RequestContext < object > requestContext )
139
- {
140
- // Execute the given PowerShell script and send the response.
141
- // Note that we aren't waiting for execution to complete here
142
- // because the debugger could stop while the script executes.
143
- Task executeTask =
144
- editorSession . PowerShellContext
145
- . ExecuteScriptAtPath ( this . scriptPathToLaunch , this . arguments )
146
- . ContinueWith (
147
- async ( t ) => {
148
- Logger . Write ( LogLevel . Verbose , "Execution completed, terminating..." ) ;
149
-
150
- await requestContext . SendEvent (
151
- TerminatedEvent . Type ,
152
- null ) ;
153
-
154
- // Stop the server
155
- this . Stop ( ) ;
156
- } ) ;
157
-
158
- await requestContext . SendResult ( null ) ;
159
- }
160
-
161
199
protected Task HandleDisconnectRequest (
162
200
object disconnectParams ,
163
201
RequestContext < object > requestContext )
0 commit comments