Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add document symbol handler #12

Merged
merged 4 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/Facility.LanguageServer/FsdDocumentSymbolHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Facility.Definition;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;

namespace Facility.LanguageServer
{
internal sealed class FsdDocumentSymbolHandler : FsdRequestHandler, IDocumentSymbolHandler
{
public FsdDocumentSymbolHandler(ILanguageServerFacade router, ILanguageServerConfiguration configuration, IDictionary<DocumentUri, ServiceInfo> serviceInfos)
: base(router, configuration, serviceInfos)
{
}

public async Task<SymbolInformationOrDocumentSymbolContainer> Handle(DocumentSymbolParams request, CancellationToken cancellationToken)
{
var documentUri = request.TextDocument.Uri;
var service = GetService(documentUri);
if (service == null)
return null;

var symbols = service.GetServiceSymbols();
return symbols;
}

public DocumentSymbolRegistrationOptions GetRegistrationOptions(DocumentSymbolCapability capability, ClientCapabilities clientCapabilities)
=> new()
{
DocumentSelector = DocumentSelector.ForLanguage("fsd"),
};
}
}
118 changes: 118 additions & 0 deletions src/Facility.LanguageServer/FsdSymbolUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using Facility.Definition;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;

namespace Facility.LanguageServer;

internal static class FsdSymbolUtility
{
public static List<SymbolInformationOrDocumentSymbol> GetServiceSymbols(this ServiceInfo service)
{
var symbols = new List<SymbolInformationOrDocumentSymbol>();
foreach (var member in service.Members)
{
var memberNamePart = member.GetPart(ServicePartKind.Name);
if (memberNamePart == null)
continue;

var symbolKind = member switch
{
ServiceMethodInfo => SymbolKind.Method,
ServiceDtoInfo => SymbolKind.Interface,
ServiceEnumInfo => SymbolKind.Enum,
ServiceExternalDtoInfo => SymbolKind.Interface,
ServiceExternalEnumInfo => SymbolKind.Enum,
ServiceErrorSetInfo => SymbolKind.Interface,
_ => SymbolKind.Null,
};

var maxColumn = memberNamePart.EndPosition.ColumnNumber;
var maxLine = memberNamePart.EndPosition.LineNumber;

var childSymbols = new List<DocumentSymbol>();
foreach (var child in member.GetDescendants().OfType<ServiceElementWithAttributesInfo>())
{
var childNamePart = child.GetPart(ServicePartKind.Name);
if (childNamePart == null)
continue;

maxColumn = Math.Max(maxColumn, childNamePart.EndPosition.ColumnNumber);
maxLine = Math.Max(maxLine, childNamePart.EndPosition.LineNumber);

var childTypePart = child.GetPart(ServicePartKind.TypeName);

var childName = child switch
{
ServiceFieldInfo field => field.Name,
ServiceErrorInfo error => error.Name,
_ => null,
};

if (childName == null)
continue;

var childSymbol = new DocumentSymbol
{
Name = childName,
Kind = SymbolKind.Field,
Range = new Range(
new Position(childNamePart.Position),
new Position(
new ServiceDefinitionPosition(
childName,
childTypePart?.EndPosition.LineNumber ?? childNamePart.EndPosition.LineNumber,
childTypePart?.EndPosition.ColumnNumber ?? childNamePart.EndPosition.ColumnNumber))),
SelectionRange = new Range(
new Position(childNamePart.Position),
new Position(childNamePart.EndPosition)),
};
childSymbols.Add(childSymbol);
}

foreach (var child in member.GetDescendants().OfType<ServiceEnumValueInfo>())
{
var childNamePart = child.GetPart(ServicePartKind.Name);
if (childNamePart == null)
continue;

maxColumn = Math.Max(maxColumn, childNamePart.EndPosition.ColumnNumber);
maxLine = Math.Max(maxLine, childNamePart.EndPosition.LineNumber);
var childSymbol = new DocumentSymbol
{
Name = child.Name,
Kind = SymbolKind.EnumMember,
Range = new Range(
new Position(childNamePart.Position),
new Position(childNamePart.EndPosition)),
SelectionRange = new Range(
new Position(childNamePart.Position),
new Position(childNamePart.EndPosition)),
};
childSymbols.Add(childSymbol);
}

var keywordPart = member.GetPart(ServicePartKind.Keyword);
var minColumn = keywordPart?.Position.ColumnNumber ?? memberNamePart.Position.ColumnNumber;
var minLine = keywordPart?.Position.LineNumber ?? memberNamePart.Position.LineNumber;

var symbol = new DocumentSymbol
{
Name = member.Name,
Kind = symbolKind,

Range = new Range(
new Position(
new ServiceDefinitionPosition(member.Name, minLine, minColumn)),
new Position(
new ServiceDefinitionPosition(member.Name, maxLine + 1, maxColumn))),
SelectionRange = new Range(
new Position(memberNamePart.Position),
new Position(memberNamePart.EndPosition)),
Children = childSymbols,
};
symbols.Add(symbol);
}

return symbols;
}
}
1 change: 1 addition & 0 deletions src/Facility.LanguageServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
.WithHandler<FsdDefinitionHandler>()
.WithHandler<FsdReferenceHandler>()
.WithHandler<FsdHoverHandler>()
.WithHandler<FsdDocumentSymbolHandler>()
.WithServices(
x => x
.AddLogging(b => b.SetMinimumLevel(LogLevel.Trace)))).ConfigureAwait(false);
Expand Down