diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs index 1ab0a2fc478..8471184411f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionItemResolver.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Common; +using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -13,10 +15,17 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation { internal class DelegatedCompletionItemResolver : CompletionItemResolver { + private readonly DocumentContextFactory _documentContextFactory; + private readonly RazorFormattingService _formattingService; private readonly ClientNotifierServiceBase _languageServer; - public DelegatedCompletionItemResolver(ClientNotifierServiceBase languageServer) + public DelegatedCompletionItemResolver( + DocumentContextFactory documentContextFactory, + RazorFormattingService formattingService, + ClientNotifierServiceBase languageServer) { + _documentContextFactory = documentContextFactory; + _formattingService = formattingService; _languageServer = languageServer; } @@ -49,6 +58,78 @@ public DelegatedCompletionItemResolver(ClientNotifierServiceBase languageServer) delegatedParams.ProjectedKind); var delegatedRequest = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorCompletionResolveEndpointName, delegatedResolveParams).ConfigureAwait(false); var resolvedCompletionItem = await delegatedRequest.Returning(cancellationToken).ConfigureAwait(false); + + if (resolvedCompletionItem is not null) + { + resolvedCompletionItem = await PostProcessCompletionItemAsync(resolutionContext, resolvedCompletionItem, cancellationToken).ConfigureAwait(false); + } + + return resolvedCompletionItem; + } + + private async Task PostProcessCompletionItemAsync( + DelegatedCompletionResolutionContext context, + VSInternalCompletionItem resolvedCompletionItem, + CancellationToken cancellationToken) + { + if (context.OriginalRequestParams.ProjectedKind != RazorLanguageKind.CSharp) + { + // We currently don't do any post-processing for non-C# items. + return resolvedCompletionItem; + } + + if (!resolvedCompletionItem.VsResolveTextEditOnCommit) + { + // Resolve doesn't typically handle text edit resolution; however, in VS cases it does. + return resolvedCompletionItem; + } + + if (resolvedCompletionItem.TextEdit is null && resolvedCompletionItem.AdditionalTextEdits is null) + { + // Only post-processing work we have to do is formatting text edits on resolution. + return resolvedCompletionItem; + } + + var hostDocumentUri = context.OriginalRequestParams.HostDocument.Uri; + var documentContext = await _documentContextFactory.TryCreateAsync(hostDocumentUri, cancellationToken).ConfigureAwait(false); + if (documentContext is null) + { + return resolvedCompletionItem; + } + + // TODO: Pull active formatting options from client. + var formattingOptions = new FormattingOptions() + { + InsertSpaces = true, + TabSize = 4, + }; + + if (resolvedCompletionItem.TextEdit is not null) + { + var formattedTextEdit = await _formattingService.FormatSnippetAsync( + hostDocumentUri, + documentContext.Snapshot, + RazorLanguageKind.CSharp, + new[] { resolvedCompletionItem.TextEdit }, + formattingOptions, + cancellationToken).ConfigureAwait(false); + + resolvedCompletionItem.TextEdit = formattedTextEdit.FirstOrDefault(); + } + + if (resolvedCompletionItem.AdditionalTextEdits is not null) + { + var formattedTextEdits = await _formattingService.FormatSnippetAsync( + hostDocumentUri, + documentContext.Snapshot, + RazorLanguageKind.CSharp, + resolvedCompletionItem.AdditionalTextEdits, + formattingOptions, + cancellationToken).ConfigureAwait(false); + + resolvedCompletionItem.AdditionalTextEdits = formattedTextEdits; + } + return resolvedCompletionItem; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs index 51d9ee70b14..b7784e7259d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer; using Microsoft.AspNetCore.Razor.LanguageServer.Common; +using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.LanguageServer.Serialization; using Microsoft.AspNetCore.Razor.LanguageServer.Test.Common; using Microsoft.CodeAnalysis; @@ -36,7 +37,7 @@ public LanguageServerTestBase() var logger = new Mock(MockBehavior.Strict).Object; Mock.Get(logger).Setup(l => l.Log(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())).Verifiable(); Mock.Get(logger).Setup(l => l.IsEnabled(It.IsAny())).Returns(false); - LoggerFactory = Mock.Of(factory => factory.CreateLogger(It.IsAny()) == logger, MockBehavior.Strict); + LoggerFactory = TestLoggerFactory.Instance; Serializer = new LspSerializer(); Serializer.RegisterRazorConverters(); Serializer.RegisterVSInternalExtensionConverters(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestDocumentSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestDocumentSnapshot.cs index 47b33788d9c..11f2a086368 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestDocumentSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestDocumentSnapshot.cs @@ -55,7 +55,7 @@ public override Task GetGeneratedOutputAsync() public override IReadOnlyList GetImports() { - throw new NotImplementedException(); + return Array.Empty(); } public override bool TryGetGeneratedOutput(out RazorCodeDocument result) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshot.cs index 1332dc5e654..66ac852f691 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshot.cs @@ -78,7 +78,7 @@ public override DocumentSnapshot GetDocument(string filePath) public override RazorProjectEngine GetProjectEngine() { - throw new NotImplementedException(); + return RazorProjectEngine.Create(RazorConfiguration.Default, RazorProjectFileSystem.Create("C:/")); } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.cs index 73e9a1107f8..f1298c34c0c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.cs @@ -3,22 +3,24 @@ #nullable disable -using System.Collections.Generic; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Common; +using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; +using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.LanguageServer.Protocol; using Microsoft.AspNetCore.Razor.LanguageServer.Test; using Microsoft.AspNetCore.Razor.LanguageServer.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common; +using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; -using System.Linq; -using Microsoft.VisualStudio.TestPlatform.Utilities; -using Microsoft.AspNetCore.Razor.Language; using Xunit.Sdk; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation @@ -44,6 +46,9 @@ public DelegatedCompletionItemResolverTest() var documentContext = TestDocumentContext.From("C:/path/to/file.cshtml"); CSharpCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, new Position(10, 6), RazorLanguageKind.CSharp, new VSInternalCompletionContext(), ProvisionalTextEdit: null); HtmlCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, new Position(0, 0), RazorLanguageKind.Html, new VSInternalCompletionContext(), ProvisionalTextEdit: null); + DocumentContextFactory = new TestDocumentContextFactory(); + FormattingService = TestRazorFormattingService.Instance; + MappingService = new DefaultRazorDocumentMappingService(LoggerFactory); } private VSInternalClientCapabilities ClientCapabilities { get; } @@ -52,12 +57,18 @@ public DelegatedCompletionItemResolverTest() private DelegatedCompletionParams HtmlCompletionParams { get; } + private DocumentContextFactory DocumentContextFactory { get; } + + private RazorFormattingService FormattingService { get; } + + private RazorDocumentMappingService MappingService { get; } + [Fact] public async Task ResolveAsync_CanNotFindCompletionItem_Noops() { // Arrange var server = TestDelegatedCompletionItemResolverServer.Create(); - var resolver = new DelegatedCompletionItemResolver(server); + var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, FormattingService, server); var item = new VSInternalCompletionItem(); var notContainingCompletionList = new VSInternalCompletionList(); var originalRequestContext = new object(); @@ -74,7 +85,7 @@ public async Task ResolveAsync_UnknownRequestContext_Noops() { // Arrange var server = TestDelegatedCompletionItemResolverServer.Create(); - var resolver = new DelegatedCompletionItemResolver(server); + var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, FormattingService, server); var item = new VSInternalCompletionItem(); var containingCompletionList = new VSInternalCompletionList() { Items = new[] { item, } }; var originalRequestContext = new object(); @@ -91,7 +102,7 @@ public async Task ResolveAsync_UsesItemsData() { // Arrange var server = TestDelegatedCompletionItemResolverServer.Create(); - var resolver = new DelegatedCompletionItemResolver(server); + var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, FormattingService, server); var expectedData = new object(); var item = new VSInternalCompletionItem() { @@ -112,7 +123,7 @@ public async Task ResolveAsync_InheritsOriginalCompletionListData() { // Arrange var server = TestDelegatedCompletionItemResolverServer.Create(); - var resolver = new DelegatedCompletionItemResolver(server); + var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, FormattingService, server); var item = new VSInternalCompletionItem(); var containingCompletionList = new VSInternalCompletionList() { Items = new[] { item, }, Data = new object() }; var expectedData = new object(); @@ -135,13 +146,47 @@ public async Task ResolveAsync_CSharp_Resolves() Assert.NotNull(resolvedItem.Description); } + [Fact] + public async Task ResolveAsync_CSharp_RemapAndFormatsTextEdit() + { + // Arrange + var input = + """ + @{ + Task FooAsync() + { + awai$$ + } + } + """; + TestFileMarkupParser.GetPosition(input, out var documentContent, out _); + var originalSourceText = SourceText.From(documentContent); + var expectedSourceText = SourceText.From( + """ + @{ + async Task FooAsync() + { + await + } + } + """); + + // Act + var resolvedItem = await ResolveCompletionItemAsync(input, itemToResolve: "await", CancellationToken.None).ConfigureAwait(false); + + // Assert + var textChange = resolvedItem.TextEdit.AsTextChange(originalSourceText); + var actualSourceText = originalSourceText.WithChanges(textChange); + Assert.True(expectedSourceText.ContentEquals(actualSourceText)); + } + [Fact] public async Task ResolveAsync_Html_Resolves() { // Arrange var expectedResolvedItem = new VSInternalCompletionItem(); var server = TestDelegatedCompletionItemResolverServer.Create(expectedResolvedItem); - var resolver = new DelegatedCompletionItemResolver(server); + var resolver = new DelegatedCompletionItemResolver(DocumentContextFactory, FormattingService, server); var item = new VSInternalCompletionItem(); var containingCompletionList = new VSInternalCompletionList() { Items = new[] { item, } }; var originalRequestContext = new DelegatedCompletionResolutionContext(HtmlCompletionParams, new object()); @@ -155,14 +200,15 @@ public async Task ResolveAsync_Html_Resolves() Assert.Same(expectedResolvedItem, resolvedItem); } - private async Task ResolveCompletionItemAsync(string content, string itemToResolve, CancellationToken none) + private async Task ResolveCompletionItemAsync(string content, string itemToResolve, CancellationToken cancellationToken) { TestFileMarkupParser.GetPosition(content, out var documentContent, out var cursorPosition); var codeDocument = CreateCodeDocument(documentContent); await using var csharpServer = await CreateCSharpServerAsync(codeDocument).ConfigureAwait(false); var server = TestDelegatedCompletionItemResolverServer.Create(csharpServer); - var resolver = new DelegatedCompletionItemResolver(server); + var documentContextFactory = new TestDocumentContextFactory("C:/path/to/file.razor", codeDocument); + var resolver = new DelegatedCompletionItemResolver(documentContextFactory, FormattingService, server); var (containingCompletionList, csharpCompletionParams) = await GetCompletionListAndOriginalParamsAsync(cursorPosition, codeDocument, csharpServer).ConfigureAwait(false); var originalRequestContext = new DelegatedCompletionResolutionContext(csharpCompletionParams, containingCompletionList.Data); @@ -173,7 +219,7 @@ private async Task ResolveCompletionItemAsync(string c throw new XunitException($"Could not locate completion item '{item.Label}' for completion resolve test"); } - var resolvedItem = await resolver.ResolveAsync(item, containingCompletionList, originalRequestContext, ClientCapabilities, CancellationToken.None).ConfigureAwait(false); + var resolvedItem = await resolver.ResolveAsync(item, containingCompletionList, originalRequestContext, ClientCapabilities, cancellationToken).ConfigureAwait(false); return resolvedItem; } @@ -216,7 +262,7 @@ internal class TestDelegatedCompletionItemResolverServer : TestOmnisharpLanguage private TestDelegatedCompletionItemResolverServer(CompletionResolveRequestResponseFactory requestHandler) : base(new Dictionary>>() { - [LanguageServerConstants.RazorCompletionResolveEndpointName] = requestHandler.OnDelegationAsync, + [LanguageServerConstants.RazorCompletionResolveEndpointName] = requestHandler.OnCompletionResolveDelegationAsync, }) { _requestHandler = requestHandler; @@ -251,7 +297,7 @@ public StaticCompletionResolveRequestHandler(VSInternalCompletionItem resolveRes public override DelegatedCompletionItemResolveParams DelegatedParams => _delegatedParams; - public override Task OnDelegationAsync(object parameters) + public override Task OnCompletionResolveDelegationAsync(object parameters) { var resolveParams = (DelegatedCompletionItemResolveParams)parameters; _delegatedParams = resolveParams; @@ -272,11 +318,11 @@ public DelegatedCSharpCompletionRequestHandler(CSharpTestLspServer csharpServer) public override DelegatedCompletionItemResolveParams DelegatedParams => _delegatedParams; - public override async Task OnDelegationAsync(object parameters) + public override async Task OnCompletionResolveDelegationAsync(object parameters) { var resolveParams = (DelegatedCompletionItemResolveParams)parameters; _delegatedParams = resolveParams; - + var resolvedCompletionItem = await _csharpServer.ExecuteRequestAsync( Methods.TextDocumentCompletionResolveName, _delegatedParams.CompletionItem, @@ -290,7 +336,7 @@ private abstract class CompletionResolveRequestResponseFactory { public abstract DelegatedCompletionItemResolveParams DelegatedParams { get; } - public abstract Task OnDelegationAsync(object parameters); + public abstract Task OnCompletionResolveDelegationAsync(object parameters); } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerTestBase.cs index 319c8b0d925..0c66b6580b7 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerTestBase.cs @@ -45,7 +45,7 @@ internal static IOptionsMonitor GetOptionsMonitor(bool enableFo return monitor.Object; } - internal class TestRazorFormattingService : RazorFormattingService + internal class DummyRazorFormattingService : RazorFormattingService { public bool Called { get; private set; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingTestBase.cs index 83d43a7a3ea..bdedd546437 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingTestBase.cs @@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Protocol; -using Microsoft.AspNetCore.Razor.LanguageServer.Test; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -94,7 +93,7 @@ protected async Task RunFormattingTestAsync( InsertSpaces = insertSpaces, }; - var formattingService = CreateFormattingService(codeDocument); + var formattingService = TestRazorFormattingService.CreateWithFullSupport(codeDocument); // Act var edits = await formattingService.FormatAsync(uri, documentSnapshot, range, options, CancellationToken.None); @@ -133,7 +132,7 @@ protected async Task RunOnTypeFormattingTestAsync( var mappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger, rightAssociative: false); - var formattingService = CreateFormattingService(codeDocument); + var formattingService = TestRazorFormattingService.CreateWithFullSupport(codeDocument); var options = new FormattingOptions() { TabSize = tabSize, @@ -200,7 +199,7 @@ protected async Task RunCodeActionFormattingTestAsync( throw new InvalidOperationException("Could not map from Razor document to generated document"); } - var formattingService = CreateFormattingService(codeDocument); + var formattingService = TestRazorFormattingService.CreateWithFullSupport(codeDocument); var options = new FormattingOptions() { TabSize = tabSize, @@ -228,28 +227,6 @@ protected static TextEdit Edit(int startLine, int startChar, int endLine, int en NewText = newText, }; - private RazorFormattingService CreateFormattingService(RazorCodeDocument codeDocument) - { - var mappingService = new DefaultRazorDocumentMappingService(LoggerFactory); - - var dispatcher = new LSPProjectSnapshotManagerDispatcher(LoggerFactory); - var versionCache = new DefaultDocumentVersionCache(dispatcher); - - var client = new FormattingLanguageServerClient(); - client.AddCodeDocument(codeDocument); - var passes = new List() - { - new HtmlFormattingPass(mappingService, FilePathNormalizer, client, versionCache, LoggerFactory), - new CSharpFormattingPass(mappingService, FilePathNormalizer, client, LoggerFactory), - new CSharpOnTypeFormattingPass(mappingService, FilePathNormalizer, client, LoggerFactory), - new RazorFormattingPass(mappingService, FilePathNormalizer, client, LoggerFactory), - new FormattingDiagnosticValidationPass(mappingService, FilePathNormalizer, client, LoggerFactory), - new FormattingContentValidationPass(mappingService, FilePathNormalizer, client, LoggerFactory), - }; - - return new DefaultRazorFormattingService(passes, LoggerFactory, TestAdhocWorkspaceFactory.Instance); - } - private static SourceText ApplyEdits(SourceText source, TextEdit[] edits) { var changes = edits.Select(e => e.AsTextChange(source)); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentOnTypeFormattingEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentOnTypeFormattingEndpointTest.cs index 057bcec6140..92d603b42d0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentOnTypeFormattingEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentOnTypeFormattingEndpointTest.cs @@ -21,7 +21,7 @@ public async Task Handle_OnTypeFormatting_FormattingDisabled_ReturnsNull() { // Arrange var uri = new Uri("file://path/test.razor"); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: false); var endpoint = new RazorDocumentOnTypeFormattingEndpoint( @@ -47,7 +47,7 @@ public async Task Handle_OnTypeFormatting_DocumentNotFound_ReturnsNull() var codeDocument = CreateCodeDocument(content, sourceMappings); var uri = new Uri("file://path/test.razor"); var documentResolver = CreateDocumentContextFactory(new Uri("file://path/testDifferentFile.razor"), codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentOnTypeFormattingEndpoint( @@ -79,7 +79,7 @@ public async Task Handle_OnTypeFormatting_RemapFailed_ReturnsNull() var codeDocument = CreateCodeDocument(content, sourceMappings); var uri = new Uri("file://path/test.razor"); var documentResolver = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentOnTypeFormattingEndpoint( @@ -111,7 +111,7 @@ public async Task Handle_OnTypeFormatting_HtmlLanguageKind_ReturnsNull() var codeDocument = CreateCodeDocument(content, sourceMappings); var uri = new Uri("file://path/test.razor"); var documentResolver = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Html); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); @@ -144,7 +144,7 @@ public async Task Handle_OnTypeFormatting_RazorLanguageKind_ReturnsNull() var codeDocument = CreateCodeDocument(content, sourceMappings); var uri = new Uri("file://path/test.razor"); var documentResolver = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new Mock(MockBehavior.Strict); documentMappingService.Setup(s => s.GetLanguageKind(codeDocument, 17, false)).Returns(RazorLanguageKind.Razor); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); @@ -177,7 +177,7 @@ public async Task Handle_OnTypeFormatting_UnexpectedTriggerCharacter_ReturnsNull var codeDocument = CreateCodeDocument(content, sourceMappings); var uri = new Uri("file://path/test.razor"); var documentResolver = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var documentMappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentOnTypeFormattingEndpoint( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentRangeFormattingEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentRangeFormattingEndpointTest.cs index e01dcad2768..5274f11daa9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentRangeFormattingEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/RazorDocumentRangeFormattingEndpointTest.cs @@ -21,7 +21,7 @@ public async Task Handle_FormattingEnabled_InvokesFormattingService() var codeDocument = TestRazorCodeDocument.CreateEmpty(); var uri = new Uri("file://path/test.razor"); var documentContextFactory = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentRangeFormattingEndpoint( documentContextFactory, formattingService, optionsMonitor); @@ -42,7 +42,7 @@ public async Task Handle_FormattingEnabled_InvokesFormattingService() public async Task Handle_DocumentNotFound_ReturnsNull() { // Arrange - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentRangeFormattingEndpoint( EmptyDocumentContextFactory, formattingService, optionsMonitor); @@ -67,7 +67,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() codeDocument.SetUnsupported(); var uri = new Uri("file://path/test.razor"); var documentContextFactory = CreateDocumentContextFactory(uri, codeDocument); - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var optionsMonitor = GetOptionsMonitor(enableFormatting: true); var endpoint = new RazorDocumentRangeFormattingEndpoint( documentContextFactory, formattingService, optionsMonitor); @@ -87,7 +87,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() public async Task Handle_FormattingDisabled_ReturnsNull() { // Arrange - var formattingService = new TestRazorFormattingService(); + var formattingService = new DummyRazorFormattingService(); var optionsMonitor = GetOptionsMonitor(enableFormatting: false); var endpoint = new RazorDocumentRangeFormattingEndpoint( EmptyDocumentContextFactory, formattingService, optionsMonitor); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs new file mode 100644 index 00000000000..ccf02c0ae07 --- /dev/null +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.LanguageServer.Common; +using Microsoft.AspNetCore.Razor.LanguageServer.Test; +using Microsoft.AspNetCore.Razor.Test.Common; + +namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting +{ + internal class TestRazorFormattingService + { + public static readonly RazorFormattingService Instance = CreateWithFullSupport(TestRazorCodeDocument.CreateEmpty()); + + private TestRazorFormattingService() + { + } + + public static RazorFormattingService CreateWithFullSupport(RazorCodeDocument codeDocument) + { + var mappingService = new DefaultRazorDocumentMappingService(TestLoggerFactory.Instance); + + var dispatcher = new LSPProjectSnapshotManagerDispatcher(TestLoggerFactory.Instance); + var versionCache = new DefaultDocumentVersionCache(dispatcher); + + var client = new FormattingLanguageServerClient(); + client.AddCodeDocument(codeDocument); + + var passes = new List() + { + new HtmlFormattingPass(mappingService, FilePathNormalizer.Instance, client, versionCache, TestLoggerFactory.Instance), + new CSharpFormattingPass(mappingService, FilePathNormalizer.Instance, client, TestLoggerFactory.Instance), + new CSharpOnTypeFormattingPass(mappingService, FilePathNormalizer.Instance, client, TestLoggerFactory.Instance), + new RazorFormattingPass(mappingService, FilePathNormalizer.Instance, client, TestLoggerFactory.Instance), + new FormattingDiagnosticValidationPass(mappingService, FilePathNormalizer.Instance, client, TestLoggerFactory.Instance), + new FormattingContentValidationPass(mappingService, FilePathNormalizer.Instance, client, TestLoggerFactory.Instance), + }; + + return new DefaultRazorFormattingService(passes, TestLoggerFactory.Instance, TestAdhocWorkspaceFactory.Instance); + } + } +}