Skip to content

Commit b022751

Browse files
authored
Merge pull request PowerShell#16 from TylerLeonhardt/working-workspacesymbolshandler
A working WorkspaceSymbolsHandler
2 parents a1882b8 + 18a81d6 commit b022751

21 files changed

+1316
-124
lines changed

src/PowerShellEditorServices.Engine/Hosting/EditorServicesHost.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,15 @@ public void StartLanguageService(
219219
{
220220
while (System.Diagnostics.Debugger.IsAttached)
221221
{
222-
Console.WriteLine($"{System.Diagnostics.Process.GetCurrentProcess().Id}");
223-
System.Threading.Thread.Sleep(2000);
222+
Console.WriteLine($"{Process.GetCurrentProcess().Id}");
223+
Thread.Sleep(2000);
224224
}
225225

226226
_logger.LogInformation($"LSP NamedPipe: {config.InOutPipeName}\nLSP OutPipe: {config.OutPipeName}");
227227

228+
_serviceCollection.AddSingleton<WorkspaceService>();
229+
_serviceCollection.AddSingleton<SymbolsService>();
230+
228231
_languageServer = new OmnisharpLanguageServerBuilder(_serviceCollection)
229232
{
230233
NamedPipeName = config.InOutPipeName ?? config.InPipeName,

src/PowerShellEditorServices.Engine/LanguageServer/OmnisharpLanguageServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private static NamedPipeServerStream CreateNamedPipe(
8686
out NamedPipeServerStream outPipe)
8787
{
8888
// .NET Core implementation is simplest so try that first
89-
if (DotNetFacade.IsNetCore)
89+
if (VersionUtils.IsNetCore)
9090
{
9191
outPipe = outPipeName == null
9292
? null
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Management.Automation.Language;
7+
8+
namespace Microsoft.PowerShell.EditorServices.Symbols
9+
{
10+
/// <summary>
11+
/// The visitor used to find the the symbol at a specfic location in the AST
12+
/// </summary>
13+
internal class FindSymbolVisitor : AstVisitor
14+
{
15+
private int lineNumber;
16+
private int columnNumber;
17+
private bool includeFunctionDefinitions;
18+
19+
public SymbolReference FoundSymbolReference { get; private set; }
20+
21+
public FindSymbolVisitor(
22+
int lineNumber,
23+
int columnNumber,
24+
bool includeFunctionDefinitions)
25+
{
26+
this.lineNumber = lineNumber;
27+
this.columnNumber = columnNumber;
28+
this.includeFunctionDefinitions = includeFunctionDefinitions;
29+
}
30+
31+
/// <summary>
32+
/// Checks to see if this command ast is the symbol we are looking for.
33+
/// </summary>
34+
/// <param name="commandAst">A CommandAst object in the script's AST</param>
35+
/// <returns>A decision to stop searching if the right symbol was found,
36+
/// or a decision to continue if it wasn't found</returns>
37+
public override AstVisitAction VisitCommand(CommandAst commandAst)
38+
{
39+
Ast commandNameAst = commandAst.CommandElements[0];
40+
41+
if (this.IsPositionInExtent(commandNameAst.Extent))
42+
{
43+
this.FoundSymbolReference =
44+
new SymbolReference(
45+
SymbolType.Function,
46+
commandNameAst.Extent);
47+
48+
return AstVisitAction.StopVisit;
49+
}
50+
51+
return base.VisitCommand(commandAst);
52+
}
53+
54+
/// <summary>
55+
/// Checks to see if this function definition is the symbol we are looking for.
56+
/// </summary>
57+
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param>
58+
/// <returns>A decision to stop searching if the right symbol was found,
59+
/// or a decision to continue if it wasn't found</returns>
60+
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
61+
{
62+
int startColumnNumber = 1;
63+
64+
if (!this.includeFunctionDefinitions)
65+
{
66+
startColumnNumber =
67+
functionDefinitionAst.Extent.Text.IndexOf(
68+
functionDefinitionAst.Name) + 1;
69+
}
70+
71+
IScriptExtent nameExtent = new ScriptExtent()
72+
{
73+
Text = functionDefinitionAst.Name,
74+
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
75+
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
76+
StartColumnNumber = startColumnNumber,
77+
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length
78+
};
79+
80+
if (this.IsPositionInExtent(nameExtent))
81+
{
82+
this.FoundSymbolReference =
83+
new SymbolReference(
84+
SymbolType.Function,
85+
nameExtent);
86+
87+
return AstVisitAction.StopVisit;
88+
}
89+
90+
return base.VisitFunctionDefinition(functionDefinitionAst);
91+
}
92+
93+
/// <summary>
94+
/// Checks to see if this command parameter is the symbol we are looking for.
95+
/// </summary>
96+
/// <param name="commandParameterAst">A CommandParameterAst object in the script's AST</param>
97+
/// <returns>A decision to stop searching if the right symbol was found,
98+
/// or a decision to continue if it wasn't found</returns>
99+
public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst)
100+
{
101+
if (this.IsPositionInExtent(commandParameterAst.Extent))
102+
{
103+
this.FoundSymbolReference =
104+
new SymbolReference(
105+
SymbolType.Parameter,
106+
commandParameterAst.Extent);
107+
return AstVisitAction.StopVisit;
108+
}
109+
return AstVisitAction.Continue;
110+
}
111+
112+
/// <summary>
113+
/// Checks to see if this variable expression is the symbol we are looking for.
114+
/// </summary>
115+
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param>
116+
/// <returns>A decision to stop searching if the right symbol was found,
117+
/// or a decision to continue if it wasn't found</returns>
118+
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
119+
{
120+
if (this.IsPositionInExtent(variableExpressionAst.Extent))
121+
{
122+
this.FoundSymbolReference =
123+
new SymbolReference(
124+
SymbolType.Variable,
125+
variableExpressionAst.Extent);
126+
127+
return AstVisitAction.StopVisit;
128+
}
129+
130+
return AstVisitAction.Continue;
131+
}
132+
133+
/// <summary>
134+
/// Is the position of the given location is in the ast's extent
135+
/// </summary>
136+
/// <param name="extent">The script extent of the element</param>
137+
/// <returns>True if the given position is in the range of the element's extent </returns>
138+
private bool IsPositionInExtent(IScriptExtent extent)
139+
{
140+
return (extent.StartLineNumber == lineNumber &&
141+
extent.StartColumnNumber <= columnNumber &&
142+
extent.EndColumnNumber >= columnNumber);
143+
}
144+
}
145+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
using System.Management.Automation.Language;
8+
9+
namespace Microsoft.PowerShell.EditorServices.Symbols
10+
{
11+
/// <summary>
12+
/// The visitor used to find all the symbols (function and class defs) in the AST.
13+
/// </summary>
14+
/// <remarks>
15+
/// Requires PowerShell v3 or higher
16+
/// </remarks>
17+
internal class FindSymbolsVisitor : AstVisitor
18+
{
19+
public List<SymbolReference> SymbolReferences { get; private set; }
20+
21+
public FindSymbolsVisitor()
22+
{
23+
this.SymbolReferences = new List<SymbolReference>();
24+
}
25+
26+
/// <summary>
27+
/// Adds each function definition as a
28+
/// </summary>
29+
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param>
30+
/// <returns>A decision to stop searching if the right symbol was found,
31+
/// or a decision to continue if it wasn't found</returns>
32+
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
33+
{
34+
IScriptExtent nameExtent = new ScriptExtent() {
35+
Text = functionDefinitionAst.Name,
36+
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
37+
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
38+
StartColumnNumber = functionDefinitionAst.Extent.StartColumnNumber,
39+
EndColumnNumber = functionDefinitionAst.Extent.EndColumnNumber
40+
};
41+
42+
SymbolType symbolType =
43+
functionDefinitionAst.IsWorkflow ?
44+
SymbolType.Workflow : SymbolType.Function;
45+
46+
this.SymbolReferences.Add(
47+
new SymbolReference(
48+
symbolType,
49+
nameExtent));
50+
51+
return AstVisitAction.Continue;
52+
}
53+
54+
/// <summary>
55+
/// Checks to see if this variable expression is the symbol we are looking for.
56+
/// </summary>
57+
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param>
58+
/// <returns>A decision to stop searching if the right symbol was found,
59+
/// or a decision to continue if it wasn't found</returns>
60+
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
61+
{
62+
if (!IsAssignedAtScriptScope(variableExpressionAst))
63+
{
64+
return AstVisitAction.Continue;
65+
}
66+
67+
this.SymbolReferences.Add(
68+
new SymbolReference(
69+
SymbolType.Variable,
70+
variableExpressionAst.Extent));
71+
72+
return AstVisitAction.Continue;
73+
}
74+
75+
private bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst)
76+
{
77+
Ast parent = variableExpressionAst.Parent;
78+
if (!(parent is AssignmentStatementAst))
79+
{
80+
return false;
81+
}
82+
83+
parent = parent.Parent;
84+
if (parent == null || parent.Parent == null || parent.Parent.Parent == null)
85+
{
86+
return true;
87+
}
88+
89+
return false;
90+
}
91+
}
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+
}
148+
}

0 commit comments

Comments
 (0)