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 Mar 11, 2022
1 parent 21a30e2 commit 2f74e1b
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,15 +101,13 @@ 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 changes = RazorCSharpFormattingInteractionService.GetFormattedTextChanges(csharpDocument.Project.Solution, root, spanToFormat, context.Options.GetIndentationOptions(), cancellationToken);

var edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray();
return edits;
Expand All @@ -124,7 +123,7 @@ 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 formattedRoot = RazorCSharpFormattingInteractionService.Format(context.CSharpWorkspaceDocument.Project.Solution, 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 @@ -16,7 +16,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Logging;
Expand All @@ -27,15 +26,18 @@ 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)
{
_logger = loggerFactory.CreateLogger<CSharpOnTypeFormattingPass>();
_globalOptions = globalOptions;
}

public async override Task<FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
Expand All @@ -59,11 +61,14 @@ public async override Task<FormattingResult> ExecuteAsync(FormattingContext cont
return result;
}

var documentOptions = await GetDocumentOptionsAsync(context).ConfigureAwait(false);

// Ask C# for formatting changes.
var formattingChanges = await RazorCSharpFormattingInteractionService.GetFormattingChangesAsync(
context.CSharpWorkspaceDocument, typedChar: context.TriggerCharacter, projectedIndex, documentOptions, cancellationToken).ConfigureAwait(false);
context.CSharpWorkspaceDocument,
typedChar: context.TriggerCharacter,
projectedIndex,
context.Options.GetIndentationOptions(),
_globalOptions.GetAutoFormattingOptions(),
cancellationToken).ConfigureAwait(false);

if (formattingChanges.IsEmpty)
{
Expand Down Expand Up @@ -499,11 +504,5 @@ private static TextEdit[] NormalizeTextEdits(SourceText originalText, TextEdit[]
var cleanEdits = cleanChanges.Select(c => c.AsTextEdit(originalText)).ToArray();
return cleanEdits;
}

private static async Task<DocumentOptionSet> GetDocumentOptionsAsync(FormattingContext context)
{
var documentOptions = await context.CSharpWorkspaceDocument.GetOptionsAsync().ConfigureAwait(false);
return (DocumentOptionSet)context.GetChangedOptionSet(documentOptions);
}
}
}
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 @@ -18,6 +18,10 @@
<NoWarn>$(NoWarn);NU1701</NoWarn>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\Microsoft.CodeAnalysis.Razor.Workspaces\IsExternalInit.cs" Link="IsExternalInit.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -149,22 +149,22 @@ 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 options = @params.Options.GetIndentationOptions();
var changes = RazorCSharpFormattingInteractionService.GetFormattedTextChanges(csharpDocument.Project.Solution, root, spanToFormat, options, CancellationToken.None);

response.Edits = changes.Select(c => c.AsTextEdit(csharpSourceText)).ToArray();
}
Expand Down Expand Up @@ -203,15 +203,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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,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 2f74e1b

Please sign in to comment.