Skip to content

Commit

Permalink
Explicitly pass formatting options to Roslyn APIs (via External Access)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Apr 29, 2022
1 parent 632f7f9 commit 9a307d7
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,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;
Expand Down Expand Up @@ -135,15 +136,14 @@ private static async Task<TextEdit[]> 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 services = csharpDocument.Project.Solution.Workspace.Services;
var changes = RazorCSharpFormattingInteractionService.GetFormattedTextChanges(services, root, spanToFormat, context.Options.GetIndentationOptions(), cancellationToken);

var edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray();
return edits;
Expand All @@ -165,7 +165,8 @@ private static async Task<Dictionary<int, int>> 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 services = context.CSharpWorkspaceDocument.Project.Solution.Workspace.Services;
var formattedRoot = RazorCSharpFormattingInteractionService.Format(services, root, context.Options.GetIndentationOptions(), cancellationToken);
var formattedText = formattedRoot.GetText();

var desiredIndentationMap = new Dictionary<int, int>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting
internal class CSharpOnTypeFormattingPass : CSharpFormattingPassBase
{
private readonly ILogger _logger;
private readonly RazorGlobalOptions _globalOptions;

public CSharpOnTypeFormattingPass(
RazorDocumentMappingService documentMappingService,
FilePathNormalizer filePathNormalizer,
ClientNotifierServiceBase server,
RazorGlobalOptions globalOptions,
ILoggerFactory loggerFactory)
: base(documentMappingService, filePathNormalizer, server)
{
Expand All @@ -41,6 +43,7 @@ public CSharpOnTypeFormattingPass(
}

_logger = loggerFactory.CreateLogger<CSharpOnTypeFormattingPass>();
_globalOptions = globalOptions;
}

public async override Task<FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
Expand All @@ -65,19 +68,13 @@ public async override Task<FormattingResult> ExecuteAsync(FormattingContext cont
}

// Ask C# for formatting changes.
var indentationOptions = new RazorIndentationOptions(
UseTabs: !context.Options.InsertSpaces,
TabSize: context.Options.TabSize,
IndentationSize: context.Options.TabSize);
var autoFormattingOptions = new RazorAutoFormattingOptions(
formatOnReturn: true, formatOnTyping: true, formatOnSemicolon: true, formatOnCloseBrace: true);


var formattingChanges = await RazorCSharpFormattingInteractionService.GetFormattingChangesAsync(
context.CSharpWorkspaceDocument,
typedChar: context.TriggerCharacter,
projectedIndex,
indentationOptions,
autoFormattingOptions,
context.Options.GetIndentationOptions(),
_globalOptions.GetAutoFormattingOptions(),
indentStyle: CodeAnalysis.Formatting.FormattingOptions.IndentStyle.Smart,
cancellationToken).ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
using Microsoft.AspNetCore.Razor.LanguageServer.Protocol;
using Microsoft.AspNetCore.Razor.LanguageServer.Test.Common;
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;
Expand All @@ -36,7 +36,6 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Protocol.Server.WorkDone;
using Xunit;
using FormattingOptions = OmniSharp.Extensions.LanguageServer.Protocol.Models.FormattingOptions;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting
{
Expand Down Expand Up @@ -71,7 +70,7 @@ public void AddCodeDocument(RazorCodeDocument codeDocument)
_documents.TryAdd("/" + path, codeDocument);
}

private RazorDocumentFormattingResponse Format(DocumentOnTypeFormattingParams @params)
private RazorDocumentFormattingResponse Format()
{
var response = new RazorDocumentFormattingResponse();

Expand Down Expand Up @@ -150,22 +149,24 @@ private RazorDocumentFormattingResponse Format(RazorDocumentRangeFormattingParam
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);
var csharpDocument = GetCSharpDocument(codeDocument);
if (!csharpDocument.TryGetSyntaxRoot(out var root))
{
throw new InvalidOperationException("Couldn't get syntax root.");
}

var spanToFormat = @params.ProjectedRange.AsTextSpan(csharpSourceText);

var changes = Formatter.GetFormattedTextChanges(root, spanToFormat, csharpDocument.Project.Solution.Workspace);
var services = csharpDocument.Project.Solution.Workspace.Services;
var options = @params.Options.GetIndentationOptions();
var changes = RazorCSharpFormattingInteractionService.GetFormattedTextChanges(
services, root, spanToFormat, options, CancellationToken.None);

response.Edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray();
}
Expand Down Expand Up @@ -204,15 +205,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);
Expand Down Expand Up @@ -265,10 +260,10 @@ public override Task<IResponseRouterReturns> SendRequestAsync<T>(string method,

return Task.FromResult(Convert(response));
}
else if (@params is DocumentOnTypeFormattingParams onTypeFormattingParams &&
else if (@params is DocumentOnTypeFormattingParams &&
string.Equals(method, "textDocument/onTypeFormatting", StringComparison.Ordinal))
{
var response = Format(onTypeFormattingParams);
var response = Format();

return Task.FromResult(Convert(response));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Microsoft.AspNetCore.Razor.LanguageServer.Test;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Serialization;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
Expand Down Expand Up @@ -221,19 +222,22 @@ private RazorFormattingService CreateFormattingService(RazorCodeDocument codeDoc
var dispatcher = new LSPProjectSnapshotManagerDispatcher(LoggerFactory);
var versionCache = new DefaultDocumentVersionCache(dispatcher);

var workspaceFactory = TestAdhocWorkspaceFactory.Instance;
var globalOptions = RazorGlobalOptions.GetGlobalOptions(workspaceFactory.Create());

var client = new FormattingLanguageServerClient();
client.AddCodeDocument(codeDocument);
var passes = new List<IFormattingPass>()
{
new HtmlFormattingPass(mappingService, FilePathNormalizer, client, versionCache, LoggerFactory),
new CSharpFormattingPass(mappingService, FilePathNormalizer, client, LoggerFactory),
new CSharpOnTypeFormattingPass(mappingService, FilePathNormalizer, client, LoggerFactory),
new CSharpOnTypeFormattingPass(mappingService, FilePathNormalizer, client, globalOptions, 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);
return new DefaultRazorFormattingService(passes, LoggerFactory, workspaceFactory);
}

private static SourceText ApplyEdits(SourceText source, TextEdit[] edits)
Expand Down

0 comments on commit 9a307d7

Please sign in to comment.