9
9
using System . Linq ;
10
10
using System . Management . Automation ;
11
11
using System . Threading . Tasks ;
12
+ using Microsoft . PowerShell . EditorServices . Debugging ;
12
13
13
14
namespace Microsoft . PowerShell . EditorServices
14
15
{
@@ -27,8 +28,10 @@ public class DebugService
27
28
new Dictionary < string , List < Breakpoint > > ( ) ;
28
29
29
30
private int nextVariableId ;
30
- private List < VariableDetails > currentVariables ;
31
- private StackFrameDetails [ ] callStackFrames ;
31
+ private List < VariableDetailsBase > variables ;
32
+ private VariableContainerDetails globalScopeVariables ;
33
+ private VariableContainerDetails scriptScopeVariables ;
34
+ private StackFrameDetails [ ] stackFrameDetails ;
32
35
33
36
#endregion
34
37
@@ -155,38 +158,28 @@ public void Abort()
155
158
/// </summary>
156
159
/// <param name="variableReferenceId"></param>
157
160
/// <returns>An array of VariableDetails instances which describe the requested variables.</returns>
158
- public VariableDetails [ ] GetVariables ( int variableReferenceId )
161
+ public VariableDetailsBase [ ] GetVariables ( int variableReferenceId )
159
162
{
160
- VariableDetails [ ] childVariables = null ;
163
+ VariableDetailsBase [ ] childVariables ;
161
164
162
- if ( variableReferenceId >= VariableDetails . FirstVariableId )
165
+ VariableDetailsBase parentVariable = this . variables [ variableReferenceId ] ;
166
+ if ( parentVariable . IsExpandable )
163
167
{
164
- int correctedId =
165
- ( variableReferenceId - VariableDetails . FirstVariableId ) ;
168
+ childVariables = parentVariable . GetChildren ( ) ;
166
169
167
- VariableDetails parentVariable =
168
- this . currentVariables [ correctedId ] ;
169
-
170
- if ( parentVariable . IsExpandable )
170
+ foreach ( var child in childVariables )
171
171
{
172
- childVariables = parentVariable . GetChildren ( ) ;
173
-
174
- foreach ( var child in childVariables )
172
+ // Only add child if it hasn't already been added.
173
+ if ( child . Id < 0 )
175
174
{
176
- this . currentVariables . Add ( child ) ;
177
- child . Id = this . nextVariableId ;
178
- this . nextVariableId ++ ;
175
+ child . Id = this . nextVariableId ++ ;
176
+ this . variables . Add ( child ) ;
179
177
}
180
178
}
181
- else
182
- {
183
- childVariables = new VariableDetails [ 0 ] ;
184
- }
185
179
}
186
180
else
187
181
{
188
- // TODO: Get variables for the desired scope ID
189
- childVariables = this . currentVariables . ToArray ( ) ;
182
+ childVariables = new VariableDetailsBase [ 0 ] ;
190
183
}
191
184
192
185
return childVariables ;
@@ -200,13 +193,13 @@ public VariableDetails[] GetVariables(int variableReferenceId)
200
193
/// <param name="variableExpression">The variable expression string to evaluate.</param>
201
194
/// <param name="stackFrameId">The ID of the stack frame in which the expression should be evaluated.</param>
202
195
/// <returns>A VariableDetails object containing the result.</returns>
203
- public VariableDetails GetVariableFromExpression ( string variableExpression , int stackFrameId )
196
+ public VariableDetailsBase GetVariableFromExpression ( string variableExpression , int stackFrameId )
204
197
{
205
198
// Break up the variable path
206
199
string [ ] variablePathParts = variableExpression . Split ( '.' ) ;
207
200
208
- VariableDetails resolvedVariable = null ;
209
- IEnumerable < VariableDetails > variableList = this . currentVariables ;
201
+ VariableDetailsBase resolvedVariable = null ;
202
+ IEnumerable < VariableDetailsBase > variableList = this . variables ;
210
203
211
204
foreach ( var variableName in variablePathParts )
212
205
{
@@ -267,7 +260,7 @@ await this.powerShellContext.ExecuteScriptString(
267
260
/// </returns>
268
261
public StackFrameDetails [ ] GetStackFrames ( )
269
262
{
270
- return this . callStackFrames ;
263
+ return this . stackFrameDetails ;
271
264
}
272
265
273
266
/// <summary>
@@ -278,10 +271,11 @@ public StackFrameDetails[] GetStackFrames()
278
271
/// <returns>The list of VariableScope instances which describe the available variable scopes.</returns>
279
272
public VariableScope [ ] GetVariableScopes ( int stackFrameId )
280
273
{
281
- // TODO: Return different scopes based on PowerShell scoping mechanics
282
274
return new VariableScope [ ]
283
275
{
284
- new VariableScope ( 1 , "Locals" )
276
+ new VariableScope ( this . stackFrameDetails [ stackFrameId ] . LocalVariables . Id , "Local" ) ,
277
+ new VariableScope ( this . scriptScopeVariables . Id , "Script" ) ,
278
+ new VariableScope ( this . globalScopeVariables . Id , "Global" ) ,
285
279
} ;
286
280
}
287
281
@@ -310,25 +304,44 @@ private async Task ClearBreakpointsInFile(ScriptFile scriptFile)
310
304
}
311
305
}
312
306
313
- private async Task FetchVariables ( )
307
+ private async Task FetchStackFramesAndVariables ( )
314
308
{
315
- this . nextVariableId = VariableDetails . FirstVariableId ;
316
- this . currentVariables = new List < VariableDetails > ( ) ;
309
+ // Avoid using 0 as it indicates a variable node with no children.
310
+ this . nextVariableId = 1 ;
311
+ this . variables = new List < VariableDetailsBase > ( ) ;
312
+
313
+ // Create a dummy variable for index 0, should never see this.
314
+ this . variables . Add ( new VariableDetails ( "Dummy" , null ) ) ;
317
315
316
+ await FetchGlobalAndScriptVariables ( ) ;
317
+ await FetchStackFrames ( ) ;
318
+
319
+ }
320
+
321
+ private async Task FetchGlobalAndScriptVariables ( )
322
+ {
323
+ this . scriptScopeVariables = await FetchVariableContainer ( "Script" ) ;
324
+ this . globalScopeVariables = await FetchVariableContainer ( "Global" ) ;
325
+ }
326
+
327
+ private async Task < VariableContainerDetails > FetchVariableContainer ( string scope )
328
+ {
318
329
PSCommand psCommand = new PSCommand ( ) ;
319
330
psCommand . AddCommand ( "Get-Variable" ) ;
320
- psCommand . AddParameter ( "Scope" , "Local" ) ;
331
+ psCommand . AddParameter ( "Scope" , scope ) ;
321
332
322
- var results = await this . powerShellContext . ExecuteCommand < PSVariable > ( psCommand ) ;
333
+ var variableContainerDetails = new VariableContainerDetails ( this . nextVariableId ++ , "Scope: " + scope ) ;
334
+ this . variables . Add ( variableContainerDetails ) ;
323
335
324
- foreach ( var variable in results )
336
+ var results = await this . powerShellContext . ExecuteCommand < PSVariable > ( psCommand ) ;
337
+ foreach ( PSVariable variable in results )
325
338
{
326
- var details = new VariableDetails ( variable ) ;
327
- details . Id = this . nextVariableId ;
328
- this . currentVariables . Add ( details ) ;
329
-
330
- this . nextVariableId ++ ;
339
+ var variableDetails = new VariableDetails ( variable ) { Id = this . nextVariableId ++ } ;
340
+ this . variables . Add ( variableDetails ) ;
341
+ variableContainerDetails . Children . Add ( variableDetails ) ;
331
342
}
343
+
344
+ return variableContainerDetails ;
332
345
}
333
346
334
347
private async Task FetchStackFrames ( )
@@ -338,10 +351,14 @@ private async Task FetchStackFrames()
338
351
339
352
var results = await this . powerShellContext . ExecuteCommand < CallStackFrame > ( psCommand ) ;
340
353
341
- this . callStackFrames =
342
- results
343
- . Select ( StackFrameDetails . Create )
344
- . ToArray ( ) ;
354
+ var callStackFrames = results . ToArray ( ) ;
355
+ this . stackFrameDetails = new StackFrameDetails [ callStackFrames . Length ] ;
356
+
357
+ for ( int i = 0 ; i < callStackFrames . Length ; i ++ )
358
+ {
359
+ VariableContainerDetails localVariables = await FetchVariableContainer ( i . ToString ( ) ) ;
360
+ this . stackFrameDetails [ i ] = StackFrameDetails . Create ( callStackFrames [ i ] , localVariables ) ;
361
+ }
345
362
}
346
363
347
364
#endregion
@@ -355,9 +372,8 @@ private async Task FetchStackFrames()
355
372
356
373
private async void OnDebuggerStop ( object sender , DebuggerStopEventArgs e )
357
374
{
358
- // Get the call stack and local variables
359
- await this . FetchStackFrames ( ) ;
360
- await this . FetchVariables ( ) ;
375
+ // Get call stack and variables.
376
+ await this . FetchStackFramesAndVariables ( ) ;
361
377
362
378
// Notify the host that the debugger is stopped
363
379
if ( this . DebuggerStopped != null )
0 commit comments