Skip to content

Commit

Permalink
Merge pull request PowerShell#16 from TylerLeonhardt/working-workspac…
Browse files Browse the repository at this point in the history
…esymbolshandler

A working WorkspaceSymbolsHandler
  • Loading branch information
rjmholt authored Jul 10, 2019
2 parents a1882b8 + 18a81d6 commit b022751
Show file tree
Hide file tree
Showing 21 changed files with 1,316 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,15 @@ public void StartLanguageService(
{
while (System.Diagnostics.Debugger.IsAttached)
{
Console.WriteLine($"{System.Diagnostics.Process.GetCurrentProcess().Id}");
System.Threading.Thread.Sleep(2000);
Console.WriteLine($"{Process.GetCurrentProcess().Id}");
Thread.Sleep(2000);
}

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

_serviceCollection.AddSingleton<WorkspaceService>();
_serviceCollection.AddSingleton<SymbolsService>();

_languageServer = new OmnisharpLanguageServerBuilder(_serviceCollection)
{
NamedPipeName = config.InOutPipeName ?? config.InPipeName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private static NamedPipeServerStream CreateNamedPipe(
out NamedPipeServerStream outPipe)
{
// .NET Core implementation is simplest so try that first
if (DotNetFacade.IsNetCore)
if (VersionUtils.IsNetCore)
{
outPipe = outPipeName == null
? null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System.Management.Automation.Language;

namespace Microsoft.PowerShell.EditorServices.Symbols
{
/// <summary>
/// The visitor used to find the the symbol at a specfic location in the AST
/// </summary>
internal class FindSymbolVisitor : AstVisitor
{
private int lineNumber;
private int columnNumber;
private bool includeFunctionDefinitions;

public SymbolReference FoundSymbolReference { get; private set; }

public FindSymbolVisitor(
int lineNumber,
int columnNumber,
bool includeFunctionDefinitions)
{
this.lineNumber = lineNumber;
this.columnNumber = columnNumber;
this.includeFunctionDefinitions = includeFunctionDefinitions;
}

/// <summary>
/// Checks to see if this command ast is the symbol we are looking for.
/// </summary>
/// <param name="commandAst">A CommandAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitCommand(CommandAst commandAst)
{
Ast commandNameAst = commandAst.CommandElements[0];

if (this.IsPositionInExtent(commandNameAst.Extent))
{
this.FoundSymbolReference =
new SymbolReference(
SymbolType.Function,
commandNameAst.Extent);

return AstVisitAction.StopVisit;
}

return base.VisitCommand(commandAst);
}

/// <summary>
/// Checks to see if this function definition is the symbol we are looking for.
/// </summary>
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
{
int startColumnNumber = 1;

if (!this.includeFunctionDefinitions)
{
startColumnNumber =
functionDefinitionAst.Extent.Text.IndexOf(
functionDefinitionAst.Name) + 1;
}

IScriptExtent nameExtent = new ScriptExtent()
{
Text = functionDefinitionAst.Name,
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
StartColumnNumber = startColumnNumber,
EndColumnNumber = startColumnNumber + functionDefinitionAst.Name.Length
};

if (this.IsPositionInExtent(nameExtent))
{
this.FoundSymbolReference =
new SymbolReference(
SymbolType.Function,
nameExtent);

return AstVisitAction.StopVisit;
}

return base.VisitFunctionDefinition(functionDefinitionAst);
}

/// <summary>
/// Checks to see if this command parameter is the symbol we are looking for.
/// </summary>
/// <param name="commandParameterAst">A CommandParameterAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst)
{
if (this.IsPositionInExtent(commandParameterAst.Extent))
{
this.FoundSymbolReference =
new SymbolReference(
SymbolType.Parameter,
commandParameterAst.Extent);
return AstVisitAction.StopVisit;
}
return AstVisitAction.Continue;
}

/// <summary>
/// Checks to see if this variable expression is the symbol we are looking for.
/// </summary>
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
{
if (this.IsPositionInExtent(variableExpressionAst.Extent))
{
this.FoundSymbolReference =
new SymbolReference(
SymbolType.Variable,
variableExpressionAst.Extent);

return AstVisitAction.StopVisit;
}

return AstVisitAction.Continue;
}

/// <summary>
/// Is the position of the given location is in the ast's extent
/// </summary>
/// <param name="extent">The script extent of the element</param>
/// <returns>True if the given position is in the range of the element's extent </returns>
private bool IsPositionInExtent(IScriptExtent extent)
{
return (extent.StartLineNumber == lineNumber &&
extent.StartColumnNumber <= columnNumber &&
extent.EndColumnNumber >= columnNumber);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System.Collections.Generic;
using System.Management.Automation.Language;

namespace Microsoft.PowerShell.EditorServices.Symbols
{
/// <summary>
/// The visitor used to find all the symbols (function and class defs) in the AST.
/// </summary>
/// <remarks>
/// Requires PowerShell v3 or higher
/// </remarks>
internal class FindSymbolsVisitor : AstVisitor
{
public List<SymbolReference> SymbolReferences { get; private set; }

public FindSymbolsVisitor()
{
this.SymbolReferences = new List<SymbolReference>();
}

/// <summary>
/// Adds each function definition as a
/// </summary>
/// <param name="functionDefinitionAst">A functionDefinitionAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
{
IScriptExtent nameExtent = new ScriptExtent() {
Text = functionDefinitionAst.Name,
StartLineNumber = functionDefinitionAst.Extent.StartLineNumber,
EndLineNumber = functionDefinitionAst.Extent.EndLineNumber,
StartColumnNumber = functionDefinitionAst.Extent.StartColumnNumber,
EndColumnNumber = functionDefinitionAst.Extent.EndColumnNumber
};

SymbolType symbolType =
functionDefinitionAst.IsWorkflow ?
SymbolType.Workflow : SymbolType.Function;

this.SymbolReferences.Add(
new SymbolReference(
symbolType,
nameExtent));

return AstVisitAction.Continue;
}

/// <summary>
/// Checks to see if this variable expression is the symbol we are looking for.
/// </summary>
/// <param name="variableExpressionAst">A VariableExpressionAst object in the script's AST</param>
/// <returns>A decision to stop searching if the right symbol was found,
/// or a decision to continue if it wasn't found</returns>
public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
{
if (!IsAssignedAtScriptScope(variableExpressionAst))
{
return AstVisitAction.Continue;
}

this.SymbolReferences.Add(
new SymbolReference(
SymbolType.Variable,
variableExpressionAst.Extent));

return AstVisitAction.Continue;
}

private bool IsAssignedAtScriptScope(VariableExpressionAst variableExpressionAst)
{
Ast parent = variableExpressionAst.Parent;
if (!(parent is AssignmentStatementAst))
{
return false;
}

parent = parent.Parent;
if (parent == null || parent.Parent == null || parent.Parent.Parent == null)
{
return true;
}

return false;
}
}

/// <summary>
/// Visitor to find all the keys in Hashtable AST
/// </summary>
internal class FindHashtableSymbolsVisitor : AstVisitor
{
/// <summary>
/// List of symbols (keys) found in the hashtable
/// </summary>
public List<SymbolReference> SymbolReferences { get; private set; }

/// <summary>
/// Initializes a new instance of FindHashtableSymbolsVisitor class
/// </summary>
public FindHashtableSymbolsVisitor()
{
SymbolReferences = new List<SymbolReference>();
}

/// <summary>
/// Adds keys in the input hashtable to the symbol reference
/// </summary>
public override AstVisitAction VisitHashtable(HashtableAst hashtableAst)
{
if (hashtableAst.KeyValuePairs == null)
{
return AstVisitAction.Continue;
}

foreach (var kvp in hashtableAst.KeyValuePairs)
{
var keyStrConstExprAst = kvp.Item1 as StringConstantExpressionAst;
if (keyStrConstExprAst != null)
{
IScriptExtent nameExtent = new ScriptExtent()
{
Text = keyStrConstExprAst.Value,
StartLineNumber = kvp.Item1.Extent.StartLineNumber,
EndLineNumber = kvp.Item2.Extent.EndLineNumber,
StartColumnNumber = kvp.Item1.Extent.StartColumnNumber,
EndColumnNumber = kvp.Item2.Extent.EndColumnNumber
};

SymbolType symbolType = SymbolType.HashtableKey;

this.SymbolReferences.Add(
new SymbolReference(
symbolType,
nameExtent));

}
}

return AstVisitAction.Continue;
}
}
}
Loading

0 comments on commit b022751

Please sign in to comment.