diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs index 671d7688d6c..47ffad44ef4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormatter.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; using Microsoft.CodeAnalysis.Text; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -134,15 +135,11 @@ private static async Task FormatOnServerAsync( Range projectedRange, CancellationToken cancellationToken) { + var csharpDocument = context.CSharpWorkspaceDocument; var csharpSourceText = context.CodeDocument.GetCSharpSourceText(); var spanToFormat = projectedRange.AsTextSpan(csharpSourceText); - var root = await context.CSharpWorkspaceDocument.GetSyntaxRootAsync(cancellationToken); - Assumes.NotNull(root); - var workspace = context.CSharpWorkspace; - - // Formatting options will already be set in the workspace. - var changes = CodeAnalysis.Formatting.Formatter.GetFormattedTextChanges(root, spanToFormat, workspace, cancellationToken: cancellationToken); + var changes = await RazorCSharpFormattingInteractionService.GetFormattedTextChangesAsync(csharpDocument, spanToFormat, context.Options.GetIndentationOptions(), cancellationToken).ConfigureAwait(false); var edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray(); return edits; @@ -158,7 +155,7 @@ private static async Task> GetCSharpIndentationCoreAsync(Fo // At this point, we have added all the necessary markers and attached annotations. // Let's invoke the C# formatter and hope for the best. - var formattedRoot = CodeAnalysis.Formatting.Formatter.Format(root, context.CSharpWorkspace, cancellationToken: cancellationToken); + var formattedRoot = await RazorCSharpFormattingInteractionService.FormatAsync(context.CSharpWorkspaceDocument, root, context.Options.GetIndentationOptions(), cancellationToken: cancellationToken); var formattedText = formattedRoot.GetText(); var desiredIndentationMap = new Dictionary(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingOptionsExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingOptionsExtensions.cs new file mode 100644 index 00000000000..4c05cebc667 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingOptionsExtensions.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; + +namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting +{ + internal static class FormattingOptionsExtensions + { + public static RazorIndentationOptions GetIndentationOptions(this FormattingOptions options) + => new( + UseTabs: !options.InsertSpaces, + TabSize: options.TabSize, + IndentationSize: options.TabSize); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs index a42420b99f1..4b17210db65 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; using Microsoft.CodeAnalysis.Text; @@ -32,6 +31,7 @@ internal class RazorFormattingEndpoint : IDocumentFormattingHandler, IDocumentRa private readonly AdhocWorkspaceFactory _adhocWorkspaceFactory; private readonly IOptionsMonitor _optionsMonitor; private readonly ILogger _logger; + private readonly RazorGlobalOptions _globalOptions; private static readonly IReadOnlyList s_csharpTriggerCharacters = new[] { "}", ";" }; private static readonly IReadOnlyList s_htmlTriggerCharacters = Array.Empty(); @@ -44,7 +44,8 @@ public RazorFormattingEndpoint( RazorDocumentMappingService razorDocumentMappingService, AdhocWorkspaceFactory adhocWorkspaceFactory, IOptionsMonitor optionsMonitor, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + RazorGlobalOptions globalOptions) { if (projectSnapshotManagerDispatcher is null) { @@ -88,6 +89,7 @@ public RazorFormattingEndpoint( _adhocWorkspaceFactory = adhocWorkspaceFactory; _optionsMonitor = optionsMonitor; _logger = loggerFactory.CreateLogger(); + _globalOptions = globalOptions; } public DocumentFormattingRegistrationOptions GetRegistrationOptions(DocumentFormattingCapability capability, ClientCapabilities clientCapabilities) @@ -250,11 +252,16 @@ public async Task Handle(DocumentRangeFormattingParams reques using var formattingContext = FormattingContext.Create( request.TextDocument.Uri, documentSnapshot, codeDocument, request.Options, _adhocWorkspaceFactory, isFormatOnType: true, automaticallyAddUsings: false); - var documentOptions = await GetDocumentOptionsAsync(request, formattingContext.CSharpWorkspaceDocument).ConfigureAwait(false); // Ask C# for formatting changes. var formattingChanges = await RazorCSharpFormattingInteractionService.GetFormattingChangesAsync( - formattingContext.CSharpWorkspaceDocument, typedChar: request.Character[0], projectedIndex, documentOptions, cancellationToken).ConfigureAwait(false); + formattingContext.CSharpWorkspaceDocument, + typedChar: request.Character[0], + projectedIndex, + request.Options.GetIndentationOptions(), + _globalOptions.GetAutoFormattingOptions(), + cancellationToken).ConfigureAwait(false); + if (formattingChanges.IsEmpty) { _logger.LogInformation("Received no results."); @@ -292,15 +299,5 @@ private static bool IsApplicableTriggerCharacter(string triggerCharacter, RazorL // Unknown trigger character. return false; } - - // Internal for testing - internal static async Task GetDocumentOptionsAsync(DocumentOnTypeFormattingParams request, Document document) - { - var documentOptions = await document.GetOptionsAsync().ConfigureAwait(false); - documentOptions = documentOptions.WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.TabSize, request.Options.TabSize) - .WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.IndentationSize, request.Options.TabSize) - .WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.UseTabs, !request.Options.InsertSpaces); - return documentOptions; - } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerClient.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerClient.cs index 0a3b2bb20f4..fbac0427869 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerClient.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/FormattingLanguageServerClient.cs @@ -16,7 +16,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Test; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; @@ -131,29 +131,24 @@ private RazorDocumentFormattingResponse Format(DocumentFormattingParams @params) return response; } - private RazorDocumentFormattingResponse Format(RazorDocumentRangeFormattingParams @params) + private async Task FormatAsync(RazorDocumentRangeFormattingParams @params) { if (@params.Kind == RazorLanguageKind.Razor) { throw new InvalidOperationException("We shouldn't be asked to format Razor language kind."); } - var options = @params.Options; var response = new RazorDocumentFormattingResponse(); if (@params.Kind == RazorLanguageKind.CSharp) { var codeDocument = _documents[@params.HostDocumentFilePath]; var csharpSourceText = codeDocument.GetCSharpSourceText(); - var csharpDocument = GetCSharpDocument(codeDocument, @params.Options); - if (!csharpDocument.TryGetSyntaxRoot(out var root)) - { - throw new InvalidOperationException("Couldn't get syntax root."); - } - + var csharpDocument = GetCSharpDocument(codeDocument); var spanToFormat = @params.ProjectedRange.AsTextSpan(csharpSourceText); - var changes = Formatter.GetFormattedTextChanges(root, spanToFormat, csharpDocument.Project.Solution.Workspace); + var options = @params.Options.GetIndentationOptions(); + var changes = await RazorCSharpFormattingInteractionService.GetFormattedTextChangesAsync(csharpDocument, spanToFormat, options, CancellationToken.None); response.Edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray(); } @@ -192,15 +187,9 @@ public TextEdit AsTextEdit(SourceText sourceText) } } - private static Document GetCSharpDocument(RazorCodeDocument codeDocument, FormattingOptions options) + private static Document GetCSharpDocument(RazorCodeDocument codeDocument) { var adhocWorkspace = new AdhocWorkspace(); - var csharpOptions = adhocWorkspace.Options - .WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.TabSize, LanguageNames.CSharp, (int)options.TabSize) - .WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.IndentationSize, LanguageNames.CSharp, (int)options.TabSize) - .WithChangedOption(CodeAnalysis.Formatting.FormattingOptions.UseTabs, LanguageNames.CSharp, !options.InsertSpaces); - adhocWorkspace.TryApplyChanges(adhocWorkspace.CurrentSolution.WithOptions(csharpOptions)); - var project = adhocWorkspace.AddProject("TestProject", LanguageNames.CSharp); var csharpSourceText = codeDocument.GetCSharpSourceText(); var csharpDocument = adhocWorkspace.AddDocument(project.Id, "TestDocument", csharpSourceText); @@ -237,21 +226,21 @@ public void SendNotification(IRequest request) throw new NotImplementedException(); } - public override Task SendRequestAsync(string method, T @params) + public override async Task SendRequestAsync(string method, T @params) { if (@params is RazorDocumentRangeFormattingParams rangeFormattingParams && string.Equals(method, "razor/rangeFormatting", StringComparison.Ordinal)) { - var response = Format(rangeFormattingParams); + var response = await FormatAsync(rangeFormattingParams); - return Task.FromResult(Convert(response)); + return Convert(response); } else if (@params is DocumentFormattingParams formattingParams && string.Equals(method, "textDocument/formatting", StringComparison.Ordinal)) { - var response = Format(formattingParams); + var response = await FormatAsync(formattingParams); - return Task.FromResult(Convert(response)); + return Convert(response); } throw new NotImplementedException();