Skip to content

Commit 21c7674

Browse files
authored
Re-architect formatting to prepare for cohosting (and for fun!) (#10778)
I nerd sniped myself thinking about how to get formatting into cohosting, given the limitations Alex ran into doing the relayering for auto insert, and this is the result. I was going to go further and port the actual formatting endpoint to cohosting, but that would have ran into the same issue that Alex did with auto insert, so I figured I'd wait for that to merge, and put this up in the meantime. This unblocks the formatting, code action and completion end points from being ported. Part of #10743 Part of #9519 I **strongly** recommend reviewing commit-at-a-time, as I did this deliberately in an order, and in order to (hopefully) make reviewing easier. Though granted, there are a lot of commits.
2 parents e1f6fba + ee83a6b commit 21c7674

File tree

59 files changed

+1171
-1458
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1171
-1458
lines changed

src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,9 @@ void Method() { }
110110
[Benchmark(Description = "Formatting")]
111111
public async Task RazorCSharpFormattingAsync()
112112
{
113-
var options = new FormattingOptions()
114-
{
115-
TabSize = 4,
116-
InsertSpaces = true
117-
};
118-
119113
var documentContext = new DocumentContext(DocumentUri, DocumentSnapshot, projectContext: null);
120114

121-
var edits = await RazorFormattingService.FormatAsync(documentContext, range: null, options, CancellationToken.None);
115+
var edits = await RazorFormattingService.GetDocumentFormattingEditsAsync(documentContext, htmlEdits: [], range: null, RazorFormattingOptions.Default, CancellationToken.None);
122116

123117
#if DEBUG
124118
// For debugging purposes only.

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System;
55
using System.Collections.Frozen;
66
using System.Collections.Generic;
7-
using System.Collections.Immutable;
7+
using System.Diagnostics;
88
using System.Linq;
99
using System.Threading;
1010
using System.Threading.Tasks;
@@ -185,19 +185,21 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V
185185
}
186186

187187
// For C# we run the edit through our formatting engine
188-
var edits = new[] { delegatedResponse.TextEdit };
188+
Debug.Assert(positionInfo.LanguageKind == RazorLanguageKind.CSharp);
189189

190-
var mappedEdits = delegatedResponse.TextEditFormat == InsertTextFormat.Snippet
191-
? await _razorFormattingService.FormatSnippetAsync(documentContext, positionInfo.LanguageKind, edits, originalRequest.Options, cancellationToken).ConfigureAwait(false)
192-
: await _razorFormattingService.FormatOnTypeAsync(documentContext, positionInfo.LanguageKind, edits, originalRequest.Options, hostDocumentIndex: 0, triggerCharacter: '\0', cancellationToken).ConfigureAwait(false);
193-
if (mappedEdits is not [{ } edit])
190+
var options = RazorFormattingOptions.From(originalRequest.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine);
191+
192+
var mappedEdit = delegatedResponse.TextEditFormat == InsertTextFormat.Snippet
193+
? await _razorFormattingService.GetCSharpSnippetFormattingEditAsync(documentContext, [delegatedResponse.TextEdit], options, cancellationToken).ConfigureAwait(false)
194+
: await _razorFormattingService.GetSingleCSharpEditAsync(documentContext, delegatedResponse.TextEdit, options, cancellationToken).ConfigureAwait(false);
195+
if (mappedEdit is null)
194196
{
195197
return null;
196198
}
197199

198200
return new VSInternalDocumentOnAutoInsertResponseItem()
199201
{
200-
TextEdit = edit,
202+
TextEdit = mappedEdit,
201203
TextEditFormat = delegatedResponse.TextEditFormat,
202204
};
203205
}

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/AddUsingsCodeActionProviderHelper.cs

Lines changed: 0 additions & 190 deletions
This file was deleted.

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/DefaultCSharpCodeActionResolver.cs

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,6 @@ internal sealed class DefaultCSharpCodeActionResolver(
2222
IClientConnection clientConnection,
2323
IRazorFormattingService razorFormattingService) : CSharpCodeActionResolver(clientConnection)
2424
{
25-
// Usually when we need to format code, we utilize the formatting options provided
26-
// by the platform. However, we aren't provided such options in the case of code actions
27-
// so we use a default (and commonly used) configuration.
28-
private static readonly FormattingOptions s_defaultFormattingOptions = new FormattingOptions()
29-
{
30-
TabSize = 4,
31-
InsertSpaces = true,
32-
OtherOptions = new Dictionary<string, object>
33-
{
34-
{ "trimTrailingWhitespace", true },
35-
{ "insertFinalNewline", true },
36-
{ "trimFinalNewlines", true },
37-
},
38-
};
39-
4025
private readonly IDocumentContextFactory _documentContextFactory = documentContextFactory;
4126
private readonly IRazorFormattingService _razorFormattingService = razorFormattingService;
4227

@@ -80,11 +65,10 @@ public async override Task<CodeAction> ResolveAsync(
8065

8166
// Remaps the text edits from the generated C# to the razor file,
8267
// as well as applying appropriate formatting.
83-
var formattedEdits = await _razorFormattingService.FormatCodeActionAsync(
68+
var formattedEdit = await _razorFormattingService.GetCSharpCodeActionEditAsync(
8469
documentContext,
85-
RazorLanguageKind.CSharp,
8670
csharpTextEdits,
87-
s_defaultFormattingOptions,
71+
RazorFormattingOptions.Default,
8872
cancellationToken).ConfigureAwait(false);
8973

9074
cancellationToken.ThrowIfCancellationRequested();
@@ -99,7 +83,7 @@ public async override Task<CodeAction> ResolveAsync(
9983
new TextDocumentEdit()
10084
{
10185
TextDocument = codeDocumentIdentifier,
102-
Edits = formattedEdits,
86+
Edits = formattedEdit is null ? [] : [formattedEdit],
10387
}
10488
}
10589
};

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/TypeAccessibilityCodeActionProvider.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.AspNetCore.Razor.PooledObjects;
1717
using Microsoft.AspNetCore.Razor.Threading;
1818
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
19+
using Microsoft.CodeAnalysis.Razor.Formatting;
1920
using Microsoft.CodeAnalysis.Text;
2021
using Microsoft.VisualStudio.LanguageServer.Protocol;
2122

@@ -138,7 +139,7 @@ private static ImmutableArray<RazorVSInternalCodeAction> ProcessCodeActionsVSCod
138139
var fqnCodeAction = CreateFQNCodeAction(context, diagnostic, codeAction, fqn);
139140
typeAccessibilityCodeActions.Add(fqnCodeAction);
140141

141-
if (AddUsingsCodeActionProviderHelper.TryCreateAddUsingResolutionParams(fqn, context.Request.TextDocument.Uri, additionalEdit: null, out var @namespace, out var resolutionParams))
142+
if (AddUsingsCodeActionResolver.TryCreateAddUsingResolutionParams(fqn, context.Request.TextDocument.Uri, additionalEdit: null, out var @namespace, out var resolutionParams))
142143
{
143144
var addUsingCodeAction = RazorCodeActionFactory.CreateAddComponentUsing(@namespace, newTagName: null, resolutionParams);
144145
typeAccessibilityCodeActions.Add(addUsingCodeAction);
@@ -191,7 +192,7 @@ private static ImmutableArray<RazorVSInternalCodeAction> ProcessCodeActionsVS(
191192
// For add using suggestions, the code action title is of the form:
192193
// `using System.Net;`
193194
else if (codeAction.Name is not null && codeAction.Name.Equals(RazorPredefinedCodeFixProviderNames.AddImport, StringComparison.Ordinal) &&
194-
AddUsingsCodeActionProviderHelper.TryExtractNamespace(codeAction.Title, out var @namespace, out var prefix))
195+
AddUsingsHelper.TryExtractNamespace(codeAction.Title, out var @namespace, out var prefix))
195196
{
196197
codeAction.Title = $"{prefix}@using {@namespace}";
197198
typeAccessibilityCodeActions.Add(codeAction.WrapResolvableCodeAction(context, LanguageServerConstants.CodeActions.Default));

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public static async Task RemapAndFixHtmlCodeActionEditAsync(IEditMappingService
5454

5555
foreach (var edit in documentEdits)
5656
{
57-
edit.Edits = HtmlFormatter.FixHtmlTestEdits(htmlSourceText, edit.Edits);
57+
edit.Edits = HtmlFormatter.FixHtmlTextEdits(htmlSourceText, edit.Edits);
5858
}
5959

6060
codeAction.Edit = new WorkspaceEdit

0 commit comments

Comments
 (0)