Create endpoint and remote service interface

This commit is contained in:
David Wengier 2024-07-19 14:54:13 +10:00
Родитель cb90af2a06
Коммит e47b5c63cb
3 изменённых файлов: 136 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight;
using DocumentHighlight = VisualStudio.LanguageServer.Protocol.DocumentHighlight;
[DataContract]
internal readonly record struct RemoteDocumentHighlight(
[property: DataMember(Order = 0)] LinePositionSpan Position,
[property: DataMember(Order = 1)] DocumentHighlightKind Kind)
{
public static RemoteDocumentHighlight FromLspDocumentHighlight(DocumentHighlight h)
=> new RemoteDocumentHighlight(h.Range.ToLinePositionSpan(), h.Kind);
public static DocumentHighlight ToLspDocumentHighlight(RemoteDocumentHighlight r)
=> new DocumentHighlight
{
Range = r.Position.ToRange(),
Kind = r.Kind
};
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.Remote;
internal interface IRemoteDocumentHighlightService
{
ValueTask<RemoteDocumentHighlight[]?> GetHighlightsAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId documentId, LinePosition position, CancellationToken cancellationToken);
}

Просмотреть файл

@ -0,0 +1,94 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
using Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight;
using Microsoft.CodeAnalysis.Razor.Remote;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Razor.LanguageClient.Extensions;
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
#pragma warning disable RS0030 // Do not use banned APIs
[Shared]
[CohostEndpoint(Methods.TextDocumentDocumentHighlightName)]
[Export(typeof(IDynamicRegistrationProvider))]
[ExportCohostStatelessLspService(typeof(CohostDocumentHighlightEndpoint))]
[method: ImportingConstructor]
#pragma warning restore RS0030 // Do not use banned APIs
internal class CohostDocumentHighlightEndpoint(
IRemoteServiceInvoker remoteServiceInvoker,
IHtmlDocumentSynchronizer htmlDocumentSynchronizer,
LSPRequestInvoker requestInvoker)
: AbstractRazorCohostDocumentRequestHandler<DocumentHighlightParams, DocumentHighlight[]?>, IDynamicRegistrationProvider
{
private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker;
private readonly IHtmlDocumentSynchronizer _htmlDocumentSynchronizer = htmlDocumentSynchronizer;
private readonly LSPRequestInvoker _requestInvoker = requestInvoker;
protected override bool MutatesSolutionState => false;
protected override bool RequiresLSPSolution => true;
public Registration? GetRegistration(VSInternalClientCapabilities clientCapabilities, DocumentFilter[] filter, RazorCohostRequestContext requestContext)
{
if (clientCapabilities.SupportsVisualStudioExtensions)
{
return new Registration
{
Method = Methods.TextDocumentDocumentHighlightName,
RegisterOptions = new DocumentHighlightRegistrationOptions()
{
DocumentSelector = filter
}
};
}
return null;
}
protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(DocumentHighlightParams request)
=> request.TextDocument.ToRazorTextDocumentIdentifier();
protected override async Task<DocumentHighlight[]?> HandleRequestAsync(DocumentHighlightParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
{
var razorDocument = context.TextDocument.AssumeNotNull();
var csharpResult = await _remoteServiceInvoker.TryInvokeAsync<IRemoteDocumentHighlightService, RemoteDocumentHighlight[]?>(
razorDocument.Project.Solution,
(service, solutionInfo, cancellationToken) => service.GetHighlightsAsync(solutionInfo, razorDocument.Id, request.Position.ToLinePosition(), cancellationToken),
cancellationToken).ConfigureAwait(false);
// If we got a response back, then either Razor or C# wants to do something with this, so we're good to go
if (csharpResult is not null)
{
return csharpResult.Select(RemoteDocumentHighlight.ToLspDocumentHighlight).ToArray();
}
// If we didn't get anything from Razor or Roslyn, lets ask Html what they want to do
var htmlDocument = await _htmlDocumentSynchronizer.TryGetSynchronizedHtmlDocumentAsync(razorDocument, cancellationToken).ConfigureAwait(false);
if (htmlDocument is null)
{
return null;
}
request.TextDocument = request.TextDocument.WithUri(htmlDocument.Uri);
var result = await _requestInvoker.ReinvokeRequestOnServerAsync<DocumentHighlightParams, DocumentHighlight[]?>(
htmlDocument.Buffer,
Methods.TextDocumentDocumentHighlightName,
RazorLSPConstants.HtmlLanguageServerName,
request,
cancellationToken).ConfigureAwait(false);
// Since we don't need to map positions in Html, and document highlight results don't have Uri's, we can return these results directly
return result?.Response;
}
}