Skip to content

Commit

Permalink
Pre co-hosting Hover tweaks (#11131)
Browse files Browse the repository at this point in the history
This pull request makes a couple of changes to
`HoverFactory.GetHoverAsync(...)` to prepare for co-hosting:

1. `HoverFactory.GetHoverAsync(...)` returns an LSP `Hover` rather than
`VSInternalHover`.
2. `HoverFactory.GetHoverAsync(...)` no longer takes a document file
path. It already takes a `RazorCodeDocument`, and the file path can be
retrieved from that.
  • Loading branch information
DustinCampbell authored Nov 1, 2024
2 parents 6ff6566 + 155e3c9 commit 3adf6fe
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Microsoft.CodeAnalysis.Razor.Protocol;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using LspHover = Microsoft.VisualStudio.LanguageServer.Protocol.Hover;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover;

Expand All @@ -27,7 +28,7 @@ internal sealed class HoverEndpoint(
IDocumentMappingService documentMappingService,
IClientConnection clientConnection,
ILoggerFactory loggerFactory)
: AbstractRazorDelegatingEndpoint<TextDocumentPositionParams, VSInternalHover?>(
: AbstractRazorDelegatingEndpoint<TextDocumentPositionParams, LspHover?>(
languageServerFeatureOptions,
documentMappingService,
clientConnection,
Expand Down Expand Up @@ -61,7 +62,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V
positionInfo.LanguageKind));
}

protected override async Task<VSInternalHover?> TryHandleAsync(TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken)
protected override async Task<LspHover?> TryHandleAsync(TextDocumentPositionParams request, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken)
{
var documentContext = requestContext.DocumentContext;
if (documentContext is null)
Expand Down Expand Up @@ -89,15 +90,14 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V

return await HoverFactory.GetHoverAsync(
codeDocument,
documentContext.FilePath,
positionInfo.HostDocumentIndex,
options,
_projectManager.GetQueryOperations(),
cancellationToken)
.ConfigureAwait(false);
}

protected override async Task<VSInternalHover?> HandleDelegatedResponseAsync(VSInternalHover? response, TextDocumentPositionParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken)
protected override async Task<LspHover?> HandleDelegatedResponseAsync(LspHover? response, TextDocumentPositionParams originalRequest, RazorRequestContext requestContext, DocumentPositionInfo positionInfo, CancellationToken cancellationToken)
{
var documentContext = requestContext.DocumentContext;
if (documentContext is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Text.Adornments;
using LspHover = Microsoft.VisualStudio.LanguageServer.Protocol.Hover;

namespace Microsoft.CodeAnalysis.Razor.Hover;

internal static class HoverFactory
{
public static Task<VSInternalHover?> GetHoverAsync(
public static Task<LspHover?> GetHoverAsync(
RazorCodeDocument codeDocument,
string documentFilePath,
int absoluteIndex,
HoverDisplayOptions options,
ISolutionQueryOperations solutionQueryOperations,
Expand All @@ -38,7 +38,7 @@ internal static class HoverFactory
if (owner is null)
{
Debug.Fail("Owner should never be null.");
return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}

// For cases where the point in the middle of an attribute,
Expand All @@ -59,7 +59,7 @@ internal static class HoverFactory
{
// It's possible for there to be a <Text> component that is in scope, and would be found by the GetTagHelperBinding
// call below, but a text tag, regardless of casing, inside C# code, is always just a text tag, not a component.
return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}

// We want to find the parent tag, but looking up ancestors in the tree can find other things,
Expand All @@ -82,20 +82,20 @@ internal static class HoverFactory
if (binding is null)
{
// No matching tagHelpers, it's just HTML
return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}
else if (binding.IsAttributeMatch)
{
// Hovered over a HTML tag name but the binding matches an attribute
return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}

Debug.Assert(binding.Descriptors.Any());

var span = containingTagNameToken.GetLinePositionSpan(codeDocument.Source);

return ElementInfoToHoverAsync(
documentFilePath, binding.Descriptors, span, options, solutionQueryOperations, cancellationToken);
codeDocument.Source.FilePath, binding.Descriptors, span, options, solutionQueryOperations, cancellationToken);
}

if (HtmlFacts.TryGetAttributeInfo(owner, out containingTagNameToken, out _, out var selectedAttributeName, out var selectedAttributeNameLocation, out attributes) &&
Expand All @@ -120,7 +120,7 @@ internal static class HoverFactory
if (binding is null)
{
// No matching TagHelpers, it's just HTML
return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}

Debug.Assert(binding.Descriptors.Any());
Expand Down Expand Up @@ -172,10 +172,10 @@ internal static class HoverFactory
return Task.FromResult(AttributeInfoToHover(tagHelperAttributes, attributeName, span, options));
}

return SpecializedTasks.Null<VSInternalHover>();
return SpecializedTasks.Null<LspHover>();
}

private static VSInternalHover? AttributeInfoToHover(
private static LspHover? AttributeInfoToHover(
ImmutableArray<BoundAttributeDescriptor> boundAttributes,
string attributeName,
LinePositionSpan span,
Expand Down Expand Up @@ -205,7 +205,7 @@ internal static class HoverFactory
return null;
}

return new VSInternalHover
return new LspHover
{
Contents = new MarkupContent()
{
Expand All @@ -216,8 +216,8 @@ internal static class HoverFactory
};
}

private static async Task<VSInternalHover?> ElementInfoToHoverAsync(
string documentFilePath,
private static async Task<LspHover?> ElementInfoToHoverAsync(
string? documentFilePath,
ImmutableArray<TagHelperDescriptor> descriptors,
LinePositionSpan span,
HoverDisplayOptions options,
Expand Down Expand Up @@ -253,7 +253,7 @@ internal static class HoverFactory
return null;
}

return new VSInternalHover
return new LspHover
{
Contents = new MarkupContent()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal static class ClassifiedTagHelperTooltipFactory
private static readonly ClassifiedTextRun s_nullableType = new(ClassificationTypeNames.Punctuation, "?");

public static async Task<ContainerElement?> TryCreateTooltipContainerAsync(
string documentFilePath,
string? documentFilePath,
AggregateBoundElementDescription elementDescriptionInfo,
ISolutionQueryOperations solutionQueryOperations,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -140,7 +140,7 @@ public static bool TryCreateTooltip(AggregateBoundAttributeDescription attribute
}

private static async Task<ImmutableArray<DescriptionClassification>> TryClassifyElementAsync(
string documentFilePath,
string? documentFilePath,
AggregateBoundElementDescription elementInfo,
ISolutionQueryOperations solutionQueryOperations,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -169,8 +169,11 @@ private static async Task<ImmutableArray<DescriptionClassification>> TryClassify
TryClassifySummary(documentationRuns, descriptionInfo.Documentation);

// 3. Project availability
await AddProjectAvailabilityInfoAsync(
documentFilePath, descriptionInfo.TagHelperTypeName, solutionQueryOperations, documentationRuns, cancellationToken).ConfigureAwait(false);
if (documentFilePath is not null)
{
await AddProjectAvailabilityInfoAsync(
documentFilePath, descriptionInfo.TagHelperTypeName, solutionQueryOperations, documentationRuns, cancellationToken).ConfigureAwait(false);
}

// 4. Combine type + summary information
descriptions.Add(new DescriptionClassification(typeRuns, documentationRuns));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Razor.Tooltip;
internal static class MarkupTagHelperTooltipFactory
{
public static async Task<MarkupContent?> TryCreateTooltipAsync(
string documentFilePath,
string? documentFilePath,
AggregateBoundElementDescription elementDescriptionInfo,
ISolutionQueryOperations solutionQueryOperations,
MarkupKind markupKind,
Expand Down Expand Up @@ -73,14 +73,17 @@ internal static class MarkupTagHelperTooltipFactory
descriptionBuilder.Append(finalSummaryContent);
}

var availability = await solutionQueryOperations
.GetProjectAvailabilityTextAsync(documentFilePath, tagHelperType, cancellationToken)
.ConfigureAwait(false);

if (availability is not null)
if (documentFilePath is not null)
{
descriptionBuilder.AppendLine();
descriptionBuilder.Append(availability);
var availability = await solutionQueryOperations
.GetProjectAvailabilityTextAsync(documentFilePath, tagHelperType, cancellationToken)
.ConfigureAwait(false);

if (availability is not null)
{
descriptionBuilder.AppendLine();
descriptionBuilder.Append(availability);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using Moq;
using Xunit;
using Xunit.Abstractions;
using LspHover = Microsoft.VisualStudio.LanguageServer.Protocol.Hover;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Test.Hover;

Expand All @@ -36,11 +37,11 @@ public async Task Handle_Hover_SingleServer_CallsDelegatedLanguageServer()
options.SingleServerSupport == true &&
options.UseRazorCohostServer == false);

var delegatedHover = new VSInternalHover();
var delegatedHover = new LspHover();

var clientConnection = TestMocks.CreateClientConnection(builder =>
{
builder.SetupSendRequest<IDelegatedParams, VSInternalHover>(CustomMessageNames.RazorHoverEndpointName, response: delegatedHover);
builder.SetupSendRequest<IDelegatedParams, LspHover>(CustomMessageNames.RazorHoverEndpointName, response: delegatedHover);
});

var documentMappingServiceMock = new StrictMock<IDocumentMappingService>();
Expand Down Expand Up @@ -227,7 +228,11 @@ public async Task Handle_Hover_SingleServer_AddTagHelper()
var documentContext = CreateDocumentContext(razorFileUri, codeDocument);
var requestContext = CreateRazorRequestContext(documentContext: documentContext);

return await endpoint.HandleRequestAsync(request, requestContext, DisposalToken);
var hover = await endpoint.HandleRequestAsync(request, requestContext, DisposalToken);

// Note: This should always be a VSInternalHover because
// VSInternalClientCapabilities.SupportsVisualStudioExtensions is set to true above.
return Assert.IsType<VSInternalHover>(hover);
}

private static (DocumentContext, Position) CreateDefaultDocumentContext()
Expand Down
Loading

0 comments on commit 3adf6fe

Please sign in to comment.