Skip to content

Commit 7551864

Browse files
authored
Merge pull request #327 from PowerShell/kapilmb/provide-psd1-symbols
Provide symbol outline for psd1 files
2 parents f8f6f32 + 3431795 commit 7551864

File tree

3 files changed

+127
-7
lines changed

3 files changed

+127
-7
lines changed

src/PowerShellEditorServices/Language/AstOperations.cs

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,74 @@ static public IEnumerable<SymbolReference> FindSymbolsInDocument(Ast scriptAst,
209209
// }
210210
// else
211211
{
212-
FindSymbolsVisitor findSymbolsVisitor = new FindSymbolsVisitor();
213-
scriptAst.Visit(findSymbolsVisitor);
214-
symbolReferences = findSymbolsVisitor.SymbolReferences;
212+
if (IsPowerShellDataFileAst(scriptAst))
213+
{
214+
var findHashtableSymbolsVisitor = new FindHashtableSymbolsVisitor();
215+
scriptAst.Visit(findHashtableSymbolsVisitor);
216+
symbolReferences = findHashtableSymbolsVisitor.SymbolReferences;
217+
}
218+
else
219+
{
220+
FindSymbolsVisitor findSymbolsVisitor = new FindSymbolsVisitor();
221+
scriptAst.Visit(findSymbolsVisitor);
222+
symbolReferences = findSymbolsVisitor.SymbolReferences;
223+
}
215224
}
216225

217226
return symbolReferences;
218227
}
219228

229+
static private bool IsPowerShellDataFileAst(Ast ast)
230+
{
231+
// sometimes we don't have reliable access to the filename
232+
// so we employ heuristics to check if the contents are
233+
// part of a psd1 file.
234+
return (ast.Extent.File != null
235+
&& ast.Extent.File.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase))
236+
|| IsPowerShellDataFileAstNode(
237+
new { Item = ast, Children = new List<dynamic>() },
238+
new Type[] {
239+
typeof(ScriptBlockAst),
240+
typeof(NamedBlockAst),
241+
typeof(PipelineAst),
242+
typeof(CommandExpressionAst),
243+
typeof(HashtableAst) },
244+
0);
245+
}
246+
247+
static private bool IsPowerShellDataFileAstNode(dynamic node, Type[] levelAstMap, int level)
248+
{
249+
var levelAstTypeMatch = node.Item.GetType().Equals(levelAstMap[level]);
250+
if (!levelAstTypeMatch)
251+
{
252+
return false;
253+
}
254+
255+
if (level == levelAstMap.Length - 1)
256+
{
257+
return levelAstTypeMatch;
258+
}
259+
260+
var astsFound = (node.Item as Ast).FindAll(a => a is Ast, false);
261+
if (astsFound != null)
262+
{
263+
foreach (var astFound in astsFound)
264+
{
265+
if (!astFound.Equals(node.Item)
266+
&& node.Item.Equals(astFound.Parent)
267+
&& IsPowerShellDataFileAstNode(
268+
new { Item = astFound, Children = new List<dynamic>() },
269+
levelAstMap,
270+
level + 1))
271+
{
272+
return true;
273+
}
274+
}
275+
}
276+
277+
return false;
278+
}
279+
220280
/// <summary>
221281
/// Finds all files dot sourced in a script
222282
/// </summary>

src/PowerShellEditorServices/Language/FindSymbolsVisitor.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,60 @@ private bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst
8989
return false;
9090
}
9191
}
92+
93+
/// <summary>
94+
/// Visitor to find all the keys in Hashtable AST
95+
/// </summary>
96+
internal class FindHashtableSymbolsVisitor : AstVisitor
97+
{
98+
/// <summary>
99+
/// List of symbols (keys) found in the hashtable
100+
/// </summary>
101+
public List<SymbolReference> SymbolReferences { get; private set; }
102+
103+
/// <summary>
104+
/// Initializes a new instance of FindHashtableSymbolsVisitor class
105+
/// </summary>
106+
public FindHashtableSymbolsVisitor()
107+
{
108+
SymbolReferences = new List<SymbolReference>();
109+
}
110+
111+
/// <summary>
112+
/// Adds keys in the input hashtable to the symbol reference
113+
/// </summary>
114+
public override AstVisitAction VisitHashtable(HashtableAst hashtableAst)
115+
{
116+
if (hashtableAst.KeyValuePairs == null)
117+
{
118+
return AstVisitAction.Continue;
119+
}
120+
121+
foreach (var kvp in hashtableAst.KeyValuePairs)
122+
{
123+
var keyStrConstExprAst = kvp.Item1 as StringConstantExpressionAst;
124+
if (keyStrConstExprAst != null)
125+
{
126+
IScriptExtent nameExtent = new ScriptExtent()
127+
{
128+
Text = keyStrConstExprAst.Value,
129+
StartLineNumber = kvp.Item1.Extent.StartLineNumber,
130+
EndLineNumber = kvp.Item2.Extent.EndLineNumber,
131+
StartColumnNumber = kvp.Item1.Extent.StartColumnNumber,
132+
EndColumnNumber = kvp.Item2.Extent.EndColumnNumber
133+
};
134+
135+
SymbolType symbolType = SymbolType.HashtableKey;
136+
137+
this.SymbolReferences.Add(
138+
new SymbolReference(
139+
symbolType,
140+
nameExtent));
141+
142+
}
143+
}
144+
145+
return AstVisitAction.Continue;
146+
}
147+
}
92148
}

src/PowerShellEditorServices/Language/SymbolType.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ public enum SymbolType
1414
/// The symbol type is unknown
1515
/// </summary>
1616
Unknown = 0,
17-
17+
1818
/// <summary>
1919
/// The symbol is a vairable
2020
/// </summary>
2121
Variable,
22-
22+
2323
/// <summary>
2424
/// The symbol is a function
2525
/// </summary>
2626
Function,
27-
27+
2828
/// <summary>
2929
/// The symbol is a parameter
3030
/// </summary>
@@ -39,6 +39,10 @@ public enum SymbolType
3939
/// The symbol is a workflow
4040
/// </summary>
4141
Workflow,
42+
43+
/// <summary>
44+
/// The symbol is a hashtable key
45+
/// </summary>
46+
HashtableKey
4247
}
4348
}
44-

0 commit comments

Comments
 (0)