3
3
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4
4
//
5
5
6
- using Microsoft . PowerShell . EditorServices . Utility ;
7
6
using System ;
8
7
using System . Collections . Generic ;
9
8
using System . Linq ;
10
9
using System . Management . Automation ;
11
10
using System . Threading . Tasks ;
11
+ using Microsoft . PowerShell . EditorServices . Utility ;
12
12
13
13
namespace Microsoft . PowerShell . EditorServices
14
14
{
@@ -165,7 +165,6 @@ public VariableDetailsBase[] GetVariables(int variableReferenceId)
165
165
if ( parentVariable . IsExpandable )
166
166
{
167
167
childVariables = parentVariable . GetChildren ( ) ;
168
-
169
168
foreach ( var child in childVariables )
170
169
{
171
170
// Only add child if it hasn't already been added.
@@ -270,11 +269,15 @@ public StackFrameDetails[] GetStackFrames()
270
269
/// <returns>The list of VariableScope instances which describe the available variable scopes.</returns>
271
270
public VariableScope [ ] GetVariableScopes ( int stackFrameId )
272
271
{
272
+ int localStackFrameVariableId = this . stackFrameDetails [ stackFrameId ] . LocalVariables . Id ;
273
+ int autoVariablesId = this . stackFrameDetails [ stackFrameId ] . AutoVariables . Id ;
274
+
273
275
return new VariableScope [ ]
274
276
{
275
- new VariableScope ( this . stackFrameDetails [ stackFrameId ] . LocalVariables . Id , "Local" ) ,
276
- new VariableScope ( this . scriptScopeVariables . Id , "Script" ) ,
277
- new VariableScope ( this . globalScopeVariables . Id , "Global" ) ,
277
+ new VariableScope ( autoVariablesId , VariableContainerDetails . AutoVariablesName ) ,
278
+ new VariableScope ( localStackFrameVariableId , VariableContainerDetails . LocalScopeName ) ,
279
+ new VariableScope ( this . scriptScopeVariables . Id , VariableContainerDetails . ScriptScopeName ) ,
280
+ new VariableScope ( this . globalScopeVariables . Id , VariableContainerDetails . GlobalScopeName ) ,
278
281
} ;
279
282
}
280
283
@@ -311,35 +314,100 @@ private async Task FetchStackFramesAndVariables()
311
314
// Create a dummy variable for index 0, should never see this.
312
315
this . variables . Add ( new VariableDetails ( "Dummy" , null ) ) ;
313
316
317
+ // Must retrieve global/script variales before stack frame variables
318
+ // as we check stack frame variables against globals.
314
319
await FetchGlobalAndScriptVariables ( ) ;
315
320
await FetchStackFrames ( ) ;
316
-
317
321
}
318
322
319
323
private async Task FetchGlobalAndScriptVariables ( )
320
324
{
321
- this . scriptScopeVariables = await FetchVariableContainer ( "Script" ) ;
322
- this . globalScopeVariables = await FetchVariableContainer ( "Global" ) ;
325
+ // Retrieve globals first as script variable retrieval needs to search globals.
326
+ this . globalScopeVariables =
327
+ await FetchVariableContainer ( VariableContainerDetails . GlobalScopeName , null ) ;
328
+
329
+ this . scriptScopeVariables =
330
+ await FetchVariableContainer ( VariableContainerDetails . ScriptScopeName , null ) ;
323
331
}
324
332
325
- private async Task < VariableContainerDetails > FetchVariableContainer ( string scope )
333
+ private async Task < VariableContainerDetails > FetchVariableContainer (
334
+ string scope ,
335
+ VariableContainerDetails autoVariables )
326
336
{
327
337
PSCommand psCommand = new PSCommand ( ) ;
328
338
psCommand . AddCommand ( "Get-Variable" ) ;
329
339
psCommand . AddParameter ( "Scope" , scope ) ;
330
340
331
- var variableContainerDetails = new VariableContainerDetails ( this . nextVariableId ++ , "Scope: " + scope ) ;
332
- this . variables . Add ( variableContainerDetails ) ;
341
+ var scopeVariableContainer =
342
+ new VariableContainerDetails ( this . nextVariableId ++ , "Scope: " + scope ) ;
343
+ this . variables . Add ( scopeVariableContainer ) ;
333
344
334
345
var results = await this . powerShellContext . ExecuteCommand < PSVariable > ( psCommand ) ;
335
- foreach ( PSVariable variable in results )
346
+ foreach ( PSVariable psvariable in results )
336
347
{
337
- var variableDetails = new VariableDetails ( variable ) { Id = this . nextVariableId ++ } ;
348
+ var variableDetails = new VariableDetails ( psvariable ) { Id = this . nextVariableId ++ } ;
338
349
this . variables . Add ( variableDetails ) ;
339
- variableContainerDetails . Children . Add ( variableDetails ) ;
350
+ scopeVariableContainer . Children . Add ( variableDetails . Name , variableDetails ) ;
351
+
352
+ if ( ( autoVariables != null ) && AddToAutoVariables ( psvariable , scope ) )
353
+ {
354
+ autoVariables . Children . Add ( variableDetails . Name , variableDetails ) ;
355
+ }
340
356
}
341
357
342
- return variableContainerDetails ;
358
+ return scopeVariableContainer ;
359
+ }
360
+
361
+ private bool AddToAutoVariables ( PSVariable psvariable , string scope )
362
+ {
363
+ if ( ( scope == VariableContainerDetails . GlobalScopeName ) ||
364
+ ( scope == VariableContainerDetails . ScriptScopeName ) )
365
+ {
366
+ // We don't A) have a good way of distinguishing built-in from user created variables
367
+ // and B) globalScopeVariables.Children.ContainsKey() doesn't work for built-in variables
368
+ // stored in a child variable container within the globals variable container.
369
+ return false ;
370
+ }
371
+
372
+ var constantAllScope = ScopedItemOptions . AllScope | ScopedItemOptions . Constant ;
373
+ var readonlyAllScope = ScopedItemOptions . AllScope | ScopedItemOptions . ReadOnly ;
374
+
375
+ // Some local variables, if they exist, should be displayed by default
376
+ if ( psvariable . GetType ( ) . Name == "LocalVariable" )
377
+ {
378
+ if ( psvariable . Name . Equals ( "_" ) )
379
+ {
380
+ return true ;
381
+ }
382
+ else if ( psvariable . Name . Equals ( "args" , StringComparison . OrdinalIgnoreCase ) )
383
+ {
384
+ var array = psvariable . Value as Array ;
385
+ return array != null ? array . Length > 0 : false ;
386
+ }
387
+
388
+ return false ;
389
+ }
390
+ else if ( psvariable . GetType ( ) != typeof ( PSVariable ) )
391
+ {
392
+ return false ;
393
+ }
394
+
395
+ if ( ( ( psvariable . Options | constantAllScope ) == constantAllScope ) ||
396
+ ( ( psvariable . Options | readonlyAllScope ) == readonlyAllScope ) )
397
+ {
398
+ string prefixedVariableName = VariableDetails . DollarPrefix + psvariable . Name ;
399
+ if ( this . globalScopeVariables . Children . ContainsKey ( prefixedVariableName ) )
400
+ {
401
+ return false ;
402
+ }
403
+ }
404
+
405
+ if ( ( psvariable . Value != null ) && ( psvariable . Value . GetType ( ) == typeof ( PSDebugContext ) ) )
406
+ {
407
+ return false ;
408
+ }
409
+
410
+ return true ;
343
411
}
344
412
345
413
private async Task FetchStackFrames ( )
@@ -354,8 +422,18 @@ private async Task FetchStackFrames()
354
422
355
423
for ( int i = 0 ; i < callStackFrames . Length ; i ++ )
356
424
{
357
- VariableContainerDetails localVariables = await FetchVariableContainer ( i . ToString ( ) ) ;
358
- this . stackFrameDetails [ i ] = StackFrameDetails . Create ( callStackFrames [ i ] , localVariables ) ;
425
+ VariableContainerDetails autoVariables =
426
+ new VariableContainerDetails (
427
+ this . nextVariableId ++ ,
428
+ VariableContainerDetails . AutoVariablesName ) ;
429
+
430
+ this . variables . Add ( autoVariables ) ;
431
+
432
+ VariableContainerDetails localVariables =
433
+ await FetchVariableContainer ( i . ToString ( ) , autoVariables ) ;
434
+
435
+ this . stackFrameDetails [ i ] =
436
+ StackFrameDetails . Create ( callStackFrames [ i ] , autoVariables , localVariables ) ;
359
437
}
360
438
}
361
439
0 commit comments