diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs index a55bdeaa20f..22b97768e19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs @@ -116,7 +116,7 @@ internal class DelegatedCompletionListProvider( ? DelegatedCompletionHelper.RewriteCSharpResponse(delegatedResponse, absoluteIndex, codeDocument, positionInfo.Position, razorCompletionOptions) : DelegatedCompletionHelper.RewriteHtmlResponse(delegatedResponse, razorCompletionOptions); - var resolutionContext = new DelegatedCompletionResolutionContext(identifier, positionInfo.LanguageKind, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data); + var resolutionContext = new DelegatedCompletionResolutionContext(identifier, positionInfo.LanguageKind, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data, provisionalTextEdit); var resultId = _completionListCache.Add(rewrittenResponse, resolutionContext); rewrittenResponse.SetResultId(resultId, clientCapabilities); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionEndpoint.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionEndpoint.cs index 3eb9d663652..089193b03ab 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/Completion/CohostDocumentCompletionEndpoint.cs @@ -234,7 +234,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie var rewrittenResponse = DelegatedCompletionHelper.RewriteHtmlResponse(result, razorCompletionOptions); var razorDocumentIdentifier = new TextDocumentIdentifierAndVersion(completionParams.TextDocument, Version: 0); - var resolutionContext = new DelegatedCompletionResolutionContext(razorDocumentIdentifier, RazorLanguageKind.Html, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data); + var resolutionContext = new DelegatedCompletionResolutionContext(razorDocumentIdentifier, RazorLanguageKind.Html, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data, ProvisionalTextEdit: null); var resultId = _completionListCache.Add(rewrittenResponse, resolutionContext); rewrittenResponse.SetResultId(resultId, _clientCapabilitiesService.ClientCapabilities); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DelegatedTypes.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DelegatedTypes.cs index 7696904a0a8..285ab352852 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DelegatedTypes.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DelegatedTypes.cs @@ -71,7 +71,8 @@ internal record DelegatedMapCodeParams( internal record DelegatedCompletionResolutionContext( [property: JsonPropertyName("identifier")] TextDocumentIdentifierAndVersion Identifier, [property: JsonPropertyName("projectedKind")] RazorLanguageKind ProjectedKind, - [property: JsonPropertyName("originalCompletionListData")] object? OriginalCompletionListData) : ICompletionResolveContext; + [property: JsonPropertyName("originalCompletionListData")] object? OriginalCompletionListData, + [property: JsonPropertyName("provisionalTextEdit")] TextEdit? ProvisionalTextEdit) : ICompletionResolveContext; internal record DelegatedCompletionItemResolveParams( [property: JsonPropertyName("identifier")] TextDocumentIdentifierAndVersion Identifier, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Completion/RemoteCompletionService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Completion/RemoteCompletionService.cs index 7c3f0e99190..a0eba992293 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Completion/RemoteCompletionService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Completion/RemoteCompletionService.cs @@ -149,6 +149,7 @@ private async ValueTask GetCompletionAsync( completionContext, razorCompletionOptions, correlationId, + positionInfo.ProvisionalTextEdit, cancellationToken) .ConfigureAwait(false); @@ -191,6 +192,7 @@ private async ValueTask GetCompletionAsync( CompletionContext completionContext, RazorCompletionOptions razorCompletionOptions, Guid correlationId, + TextEdit? provisionalTextEdit, CancellationToken cancellationToken) { var clientCapabilities = _clientCapabilitiesService.ClientCapabilities; @@ -236,7 +238,7 @@ private async ValueTask GetCompletionAsync( mappedPosition, razorCompletionOptions); - var resolutionContext = new DelegatedCompletionResolutionContext(identifier, RazorLanguageKind.CSharp, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data); + var resolutionContext = new DelegatedCompletionResolutionContext(identifier, RazorLanguageKind.CSharp, rewrittenResponse.Data ?? rewrittenResponse.ItemDefaults?.Data, provisionalTextEdit); var resultId = _completionListCache.Add(rewrittenResponse, resolutionContext); rewrittenResponse.SetResultId(resultId, clientCapabilities); @@ -326,7 +328,7 @@ private async ValueTask ResolveCSharpCompletionItemAsy } var documentSnapshot = context.Snapshot; - var generatedDocument = await documentSnapshot.GetGeneratedDocumentAsync(cancellationToken).ConfigureAwait(false); + var generatedDocument = await GetCSharpGeneratedDocumentAsync(documentSnapshot, resolutionContext.ProvisionalTextEdit, cancellationToken).ConfigureAwait(false); var clientCapabilities = _clientCapabilitiesService.ClientCapabilities; var completionListSetting = clientCapabilities.TextDocument?.Completion; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs index cfc88f54063..b953770f2c9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs @@ -151,7 +151,7 @@ public async Task ResolveAsync_UsesItemsData() Data = expectedData, }; var containingCompletionList = new RazorVSInternalCompletionList() { Items = [item], Data = new object() }; - var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, new object()); + var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, new object(), ProvisionalTextEdit: null); // Act await resolver.ResolveAsync( @@ -176,7 +176,7 @@ public async Task ResolveAsync_InheritsOriginalCompletionListData() var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, formattingService, DocumentMappingService, optionsMonitor, clientConnection, LoggerFactory); var item = new VSInternalCompletionItem(); var containingCompletionList = new RazorVSInternalCompletionList() { Items = [item], Data = new object() }; - var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, expectedData); + var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, expectedData, ProvisionalTextEdit: null); // Act await resolver.ResolveAsync(item, containingCompletionList, originalRequestContext, s_clientCapabilities, _componentAvailabilityService, DisposalToken); @@ -282,7 +282,7 @@ Task FooAsync() Assert.NotNull(item); - var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data); + var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data, ProvisionalTextEdit: null); var resolvedItem = await resolver.ResolveAsync( item, containingCompletionList, originalRequestContext, s_clientCapabilities, _componentAvailabilityService, DisposalToken); @@ -334,7 +334,7 @@ public async Task ResolveAsync_Html_Resolves() var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, formattingService, DocumentMappingService, optionsMonitor, clientConnection, LoggerFactory); var item = new VSInternalCompletionItem(); var containingCompletionList = new RazorVSInternalCompletionList() { Items = [item] }; - var originalRequestContext = new DelegatedCompletionResolutionContext(_htmlCompletionParams.Identifier, _htmlCompletionParams.ProjectedKind, new object()); + var originalRequestContext = new DelegatedCompletionResolutionContext(_htmlCompletionParams.Identifier, _htmlCompletionParams.ProjectedKind, new object(), ProvisionalTextEdit: null); // Act var resolvedItem = await resolver.ResolveAsync( @@ -363,7 +363,7 @@ private async Task ResolveCompletionItemAsync(string c var resolver = new DelegatedCompletionItemResolver(documentContextFactory, formattingService, DocumentMappingService, optionsMonitor, clientConnection, LoggerFactory); var containingCompletionList = await GetCompletionListAndOriginalParamsAsync(cursorPosition, codeDocument, csharpServer); - var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data); + var originalRequestContext = new DelegatedCompletionResolutionContext(_csharpCompletionParams.Identifier, _csharpCompletionParams.ProjectedKind, containingCompletionList.Data, ProvisionalTextEdit: null); var item = containingCompletionList.Items.FirstOrDefault(item => item.Label == itemToResolve); if (item is null) diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionEndpointTest.cs index 2d29f65b8ca..673ee74023d 100644 --- a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionEndpointTest.cs @@ -123,7 +123,16 @@ The end. TriggerCharacter = ".", TriggerKind = CompletionTriggerKind.TriggerCharacter }, - expectedItemLabels: ["DaysInMonth", "IsLeapYear", "Now"]); + expectedItemLabels: ["DaysInMonth", "IsLeapYear", "Now"], + itemToResolve: "Now", + expectedResolvedItemDescription: "DateTime DateTime.Now { get; }", + expected: """ + This is a Razor document. + +
@DateTime.Now
+ + The end. + """); } [Fact] @@ -1150,9 +1159,17 @@ private async Task VerifyCompletionResolveAsync(CodeAnalysis.TextDocument docume var insertIndex = text.GetRequiredAbsoluteIndex(position); changedText = text.WithChanges(new TextChange(new TextSpan(insertIndex, 0), insertText)); } + else if (result.Label is { } label) + { + // We'll let expected be null here, since its just simple text insertion + + var text = await document.GetTextAsync(DisposalToken).ConfigureAwait(false); + var insertIndex = text.GetRequiredAbsoluteIndex(position); + changedText = text.WithChanges(new TextChange(new TextSpan(insertIndex, 0), label)); + } else if (expected is not null) { - Assert.Fail("Expected a TextEdit or Command with TextEdit, but got none. Presumably resolve failed. Result: " + JsonSerializer.SerializeToElement(result).ToString()); + Assert.Fail("Expected a TextEdit or Command with TextEdit, or InsertText, or Label, but got none. Presumably resolve failed. Result: " + JsonSerializer.SerializeToElement(result).ToString()); } if (result.AdditionalTextEdits is not null) diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionResolveEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionResolveEndpointTest.cs index bfc5f58ad2b..e4568ffbe9d 100644 --- a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionResolveEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostDocumentCompletionResolveEndpointTest.cs @@ -66,7 +66,8 @@ private async Task VerifyCompletionItemResolveAsync(TestCode input) var context = new DelegatedCompletionResolutionContext( textDocumentIdentifier, OriginalCompletionListData: null, - ProjectedKind: RazorLanguageKind.Html); + ProjectedKind: RazorLanguageKind.Html, + ProvisionalTextEdit: null); var list = new RazorVSInternalCompletionList {