Skip to content

Commit

Permalink
Merge pull request #11 from bryankenote/reference-handler
Browse files Browse the repository at this point in the history
Add reference handler
  • Loading branch information
bryankenote committed Oct 12, 2023
2 parents 2fafff1 + e723408 commit 74adad6
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 0 deletions.
72 changes: 72 additions & 0 deletions src/Facility.LanguageServer/FsdDefinitionUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,68 @@ public static ServiceMemberInfo GetMemberReferencedAtPosition(this ServiceInfo s
select service.FindMember(name)).FirstOrDefault();
}

public static IEnumerable<ServicePart> GetReferencedServicePartsAtPosition(this ServiceInfo service, Position requestPosition, bool includeDeclaration)
{
var members = service.GetDescendants().OfType<ServiceMemberInfo>().ToList().AsReadOnly();

// memberAtCursor will be null if the cursor is not on a member name.
var memberAtCursor = members
.Select(member =>
{
var part = member.GetPart(ServicePartKind.Name);
var name = member.Name;
return (part, name);
})
.Where(x => x.part != null && requestPosition >= x.part.Position && requestPosition < x.part.EndPosition)
.Select(x => (x.name, x.part))
.FirstOrDefault();

var fields = service.GetDescendants().OfType<ServiceFieldInfo>().ToList().AsReadOnly();

// fieldTypeNameAtCursor will be null if the cursor is not on a field type name.
var fieldTypeNameAtCursor = fields
.Select(field =>
{
var part = field.GetPart(ServicePartKind.TypeName);
var typeName = service.GetFieldTypeName(field);
return (part, typeName);
})
.Where(x => x.part != null && requestPosition >= x.part.Position && requestPosition < x.part.EndPosition)
.Select(x => x.typeName)
.FirstOrDefault();

var referencedFields = fields
.Select(field =>
{
var part = field.GetPart(ServicePartKind.TypeName);
var typeName = service.GetFieldTypeName(field);
var type = service.GetFieldType(field);
var memberTypeName = type?.GetMemberTypeName();
return (part, memberTypeName, typeName);
})
.Where(x => x.part != null && ((memberAtCursor.name != null && x.memberTypeName == memberAtCursor.name) || x.typeName == fieldTypeNameAtCursor))
.Select(x => x.part);

var referencedMembers = members
.Select(member =>
{
var part = member.GetPart(ServicePartKind.Name);
var name = member.Name;
return (part, name);
})
.Where(x => x.part != null && x.name == fieldTypeNameAtCursor)
.Select(x => x.part);

return includeDeclaration
? referencedFields.Concat(referencedMembers)
: referencedFields;
}

private static string GetMemberTypeName(this ServiceTypeInfo type)
{
switch (type.Kind)
Expand All @@ -36,5 +98,15 @@ private static string GetMemberTypeName(this ServiceTypeInfo type)
}
return null;
}

private static string GetFieldTypeName(this ServiceInfo service, ServiceFieldInfo field)
{
var type = service.GetFieldType(field);

while (type?.ValueType is { } valueType)
type = valueType;

return type?.ToString() ?? field.TypeName;
}
}
}
47 changes: 47 additions & 0 deletions src/Facility.LanguageServer/FsdReferenceHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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;
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;

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

public ReferenceRegistrationOptions GetRegistrationOptions(ReferenceCapability capability, ClientCapabilities clientCapabilities) =>
new ReferenceRegistrationOptions()
{
DocumentSelector = DocumentSelector,
};

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

var position = new Position(request.Position);

var serviceParts = service.GetReferencedServicePartsAtPosition(position, request.Context.IncludeDeclaration);

var locations = serviceParts.Select(part => new Location()
{
Uri = documentUri,
Range = new Range(new Position(part!.Position), new Position(part.EndPosition)),
});

return new LocationContainer(locations);
}
}
}
1 change: 1 addition & 0 deletions src/Facility.LanguageServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
.AddSingleton<IDictionary<DocumentUri, ServiceInfo>>(serviceInfos))
.WithHandler<FsdSyncHandler>()
.WithHandler<FsdDefinitionHandler>()
.WithHandler<FsdReferenceHandler>()
.WithHandler<FsdHoverHandler>()
.WithServices(
x => x
Expand Down

0 comments on commit 74adad6

Please sign in to comment.