зеркало из https://github.com/dotnet/razor.git
Making resolve request handler callable in cohosting
- Making the resolve completion use document for cohosting - Serializing TextDocument property into Data member of completion items so that Roslyn will forward the request to us - Basic sanity test (shows we are getting called now)
This commit is contained in:
Родитель
87e93c7f8a
Коммит
2058042b79
|
@ -25,6 +25,7 @@ using Microsoft.VisualStudio.Razor.Snippets;
|
|||
using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse<Microsoft.VisualStudio.LanguageServer.Protocol.VSInternalCompletionList?>;
|
||||
using RoslynCompletionParams = Roslyn.LanguageServer.Protocol.CompletionParams;
|
||||
using RoslynLspExtensions = Roslyn.LanguageServer.Protocol.RoslynLspExtensions;
|
||||
using RoslynTextDocumentIdentifier = Roslyn.LanguageServer.Protocol.TextDocumentIdentifier;
|
||||
|
||||
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
|
||||
|
||||
|
@ -64,7 +65,7 @@ internal sealed class CohostDocumentCompletionEndpoint(
|
|||
Method = Methods.TextDocumentCompletionName,
|
||||
RegisterOptions = new CompletionRegistrationOptions()
|
||||
{
|
||||
ResolveProvider = true, // TODO - change to true when Resolve is implemented
|
||||
ResolveProvider = false, // TODO - change to true when Resolve is implemented
|
||||
TriggerCharacters = CompletionTriggerAndCommitCharacters.AllTriggerCharacters,
|
||||
AllCommitCharacters = CompletionTriggerAndCommitCharacters.AllCommitCharacters
|
||||
}
|
||||
|
@ -88,8 +89,11 @@ internal sealed class CohostDocumentCompletionEndpoint(
|
|||
return null;
|
||||
}
|
||||
|
||||
// Save as it may be modified if we forward request to HTML language server
|
||||
var originalTextDocumentIdentifier = request.TextDocument;
|
||||
|
||||
// Return immediately if this is auto-shown completion but auto-shown completion is disallowed in settings
|
||||
var clientSettings = _clientSettingsManager.GetClientSettings();
|
||||
var clientSettings = _clientSettingsManager.GetClientSettings();
|
||||
var autoShownCompletion = completionContext.TriggerKind != CompletionTriggerKind.Invoked;
|
||||
if (autoShownCompletion && !clientSettings.ClientCompletionSettings.AutoShowCompletion)
|
||||
{
|
||||
|
@ -187,6 +191,11 @@ internal sealed class CohostDocumentCompletionEndpoint(
|
|||
completionContext.TriggerCharacter);
|
||||
}
|
||||
|
||||
if (combinedCompletionList != null)
|
||||
{
|
||||
AddResolutionParams(combinedCompletionList, originalTextDocumentIdentifier);
|
||||
}
|
||||
|
||||
return combinedCompletionList;
|
||||
}
|
||||
|
||||
|
@ -273,6 +282,15 @@ internal sealed class CohostDocumentCompletionEndpoint(
|
|||
return completionList;
|
||||
}
|
||||
|
||||
private static void AddResolutionParams(VSInternalCompletionList completionList, RoslynTextDocumentIdentifier textDocumentIdentifier)
|
||||
{
|
||||
foreach (var item in completionList.Items)
|
||||
{
|
||||
var resolutionParams = CohostDocumentCompletionResolveParams.Create(textDocumentIdentifier);
|
||||
item.Data = JsonSerializer.SerializeToElement(resolutionParams);
|
||||
}
|
||||
}
|
||||
|
||||
internal TestAccessor GetTestAccessor() => new(this);
|
||||
|
||||
internal readonly struct TestAccessor(CohostDocumentCompletionEndpoint instance)
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
|
|||
[Export(typeof(IDynamicRegistrationProvider))]
|
||||
[ExportCohostStatelessLspService(typeof(CohostDocumentCompletionResolveEndpoint))]
|
||||
#pragma warning restore RS0030 // Do not use banned APIs
|
||||
internal sealed class CohostDocumentCompletionResolveEndpoint : AbstractRazorCohostRequestHandler<RoslynVSInternalCompletionItem, RoslynVSInternalCompletionItem>, IDynamicRegistrationProvider
|
||||
internal sealed class CohostDocumentCompletionResolveEndpoint : AbstractRazorCohostDocumentRequestHandler<RoslynVSInternalCompletionItem, RoslynVSInternalCompletionItem>, IDynamicRegistrationProvider
|
||||
{
|
||||
protected override bool MutatesSolutionState => false;
|
||||
|
||||
|
@ -29,18 +29,45 @@ internal sealed class CohostDocumentCompletionResolveEndpoint : AbstractRazorCoh
|
|||
{
|
||||
return [new Registration()
|
||||
{
|
||||
Method = Methods.TextDocumentCompletionResolveName
|
||||
Method = Methods.TextDocumentCompletionResolveName,
|
||||
RegisterOptions = new CompletionRegistrationOptions()
|
||||
{
|
||||
ResolveProvider = true
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected override Task<RoslynVSInternalCompletionItem> HandleRequestAsync(RoslynVSInternalCompletionItem request, RazorCohostRequestContext context, CancellationToken cancellationToken)
|
||||
=> HandleRequestAsync(request);
|
||||
|
||||
private Task<RoslynVSInternalCompletionItem> HandleRequestAsync(RoslynVSInternalCompletionItem request)
|
||||
protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(RoslynVSInternalCompletionItem request)
|
||||
{
|
||||
var completionResolveParams = CohostDocumentCompletionResolveParams.GetCohostDocumentCompletionResolveParams(request);
|
||||
return Roslyn.LanguageServer.Protocol.RoslynLspExtensions.ToRazorTextDocumentIdentifier(completionResolveParams.TextDocument);
|
||||
}
|
||||
|
||||
protected override Task<RoslynVSInternalCompletionItem> HandleRequestAsync(RoslynVSInternalCompletionItem request, RazorCohostRequestContext context, CancellationToken cancellationToken)
|
||||
=> HandleRequestAsync(request, cancellationToken);
|
||||
|
||||
private Task<RoslynVSInternalCompletionItem> HandleRequestAsync(RoslynVSInternalCompletionItem request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return Task.FromResult(request);
|
||||
}
|
||||
|
||||
// TODO: actual request processing code
|
||||
|
||||
return Task.FromResult(request);
|
||||
}
|
||||
|
||||
internal TestAccessor GetTestAccessor() => new(this);
|
||||
|
||||
internal readonly struct TestAccessor(CohostDocumentCompletionResolveEndpoint instance)
|
||||
{
|
||||
public Task<RoslynVSInternalCompletionItem> HandleRequestAsync(
|
||||
RoslynVSInternalCompletionItem request,
|
||||
CancellationToken cancellationToken)
|
||||
=> instance.HandleRequestAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text.Json;
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Roslyn.LanguageServer.Protocol;
|
||||
|
||||
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
|
||||
|
||||
// Data that's getting sent with each completion item so that we can provide document ID
|
||||
// to Roslyn language server which will use the URI to figure out that language of the request
|
||||
// and forward the request to us. It gets serialized as Data member of the completion item.
|
||||
// Without it, Roslyn won't forward the completion resolve request to us.
|
||||
internal sealed class CohostDocumentCompletionResolveParams
|
||||
{
|
||||
// NOTE: Capital T here is required to match Roslyn's DocumentResolveData structure, so that the Roslyn
|
||||
// language server can correctly route requests to us in cohosting. In future when we normalize
|
||||
// on to Roslyn types, we should inherit from that class so we don't have to remember to do this.
|
||||
[JsonPropertyName("TextDocument")]
|
||||
public required VSTextDocumentIdentifier TextDocument { get; set; }
|
||||
|
||||
public static CohostDocumentCompletionResolveParams Create(TextDocumentIdentifier textDocumentIdentifier)
|
||||
{
|
||||
var vsTextDocumentIdentifier = textDocumentIdentifier is VSTextDocumentIdentifier vsTextDocumentIdentifierValue
|
||||
? vsTextDocumentIdentifierValue
|
||||
: new VSTextDocumentIdentifier() { Uri = textDocumentIdentifier.Uri };
|
||||
|
||||
var resolutionParams = new CohostDocumentCompletionResolveParams()
|
||||
{
|
||||
TextDocument = vsTextDocumentIdentifier
|
||||
};
|
||||
|
||||
return resolutionParams;
|
||||
}
|
||||
|
||||
public static CohostDocumentCompletionResolveParams GetCohostDocumentCompletionResolveParams(VSInternalCompletionItem request)
|
||||
{
|
||||
if (request.Data is not JsonElement paramsObj)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid Completion Resolve Request Received");
|
||||
}
|
||||
|
||||
var resolutionParams = paramsObj.Deserialize<CohostDocumentCompletionResolveParams>();
|
||||
if (resolutionParams is null)
|
||||
{
|
||||
throw new InvalidOperationException($"request.Data should be convertible to {nameof(CohostDocumentCompletionResolveParams)}");
|
||||
}
|
||||
|
||||
return resolutionParams;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Razor.Test.Common;
|
||||
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using RoslynTextDocumentIdentifier = Roslyn.LanguageServer.Protocol.TextDocumentIdentifier;
|
||||
using RoslynVSInternalCompletionItem = Roslyn.LanguageServer.Protocol.VSInternalCompletionItem;
|
||||
|
||||
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
|
||||
|
||||
public class CohostDocumentCompletionResolveEndpointTest(ITestOutputHelper testOutputHelper) : CohostEndpointTestBase(testOutputHelper)
|
||||
{
|
||||
[Fact]
|
||||
public async Task ResolveReturnsSelf()
|
||||
{
|
||||
await VerifyCompletionItemResolveAsync(
|
||||
input: """
|
||||
This is a Razor document.
|
||||
|
||||
<div st$$></div>
|
||||
|
||||
The end.
|
||||
""",
|
||||
initialItemLabel: "TestItem1",
|
||||
expectedItemLabel: "TestItem1");
|
||||
}
|
||||
|
||||
private async Task VerifyCompletionItemResolveAsync(
|
||||
TestCode input,
|
||||
string initialItemLabel,
|
||||
string expectedItemLabel)
|
||||
{
|
||||
var document = await CreateProjectAndRazorDocumentAsync(input.Text);
|
||||
|
||||
var endpoint = new CohostDocumentCompletionResolveEndpoint();
|
||||
|
||||
var textDocumentIdentifier = new RoslynTextDocumentIdentifier()
|
||||
{
|
||||
Uri = document.CreateUri()
|
||||
};
|
||||
|
||||
var resolutionParams = CohostDocumentCompletionResolveParams.Create(textDocumentIdentifier);
|
||||
|
||||
var request = new RoslynVSInternalCompletionItem()
|
||||
{
|
||||
Data = JsonSerializer.SerializeToElement(resolutionParams),
|
||||
Label = initialItemLabel
|
||||
};
|
||||
|
||||
var result = await endpoint.GetTestAccessor().HandleRequestAsync(request, DisposalToken);
|
||||
|
||||
Assert.Equal(result.Label, expectedItemLabel);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче