Skip to content

Commit 5a3144e

Browse files
authored
Don't format if we didn't get a response from the Html formatter (#11646)
Partial fix for the symptoms of #11643 Turns out there is a bug in our handling of Html documents in multi-target projects, and most likely everything has been quietly failing sometimes. Additionally it turns out that the new formatting engine doesn't format things nicely if we don't get a response from Html, so this PR fixes that, and stops things breaking users documents. I'll follow up with a proper fix soon.
2 parents 3cbcd8a + eb2e533 commit 5a3144e

File tree

8 files changed

+57
-22
lines changed

8 files changed

+57
-22
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentFormattingEndpoint.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentFormattingParams
5656

5757
var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine);
5858

59-
var htmlChanges = await _htmlFormatter.GetDocumentFormattingEditsAsync(documentContext.Snapshot, documentContext.Uri, request.Options, cancellationToken).ConfigureAwait(false);
59+
if (await _htmlFormatter.GetDocumentFormattingEditsAsync(
60+
documentContext.Snapshot,
61+
documentContext.Uri,
62+
request.Options,
63+
cancellationToken).ConfigureAwait(false) is not { } htmlChanges)
64+
{
65+
return null;
66+
}
67+
6068
var changes = await _razorFormattingService.GetDocumentFormattingChangesAsync(documentContext, htmlChanges, span: null, options, cancellationToken).ConfigureAwait(false);
6169

6270
return [.. changes.Select(codeDocument.Source.Text.GetTextEdit)];

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,17 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentOnTypeFormatting
106106
}
107107
else if (triggerCharacterKind == RazorLanguageKind.Html)
108108
{
109-
var htmlChanges = await _htmlFormatter.GetOnTypeFormattingEditsAsync(documentContext.Snapshot, documentContext.Uri, request.Position, request.Character, request.Options, cancellationToken).ConfigureAwait(false);
109+
if (await _htmlFormatter.GetOnTypeFormattingEditsAsync(
110+
documentContext.Snapshot,
111+
documentContext.Uri,
112+
request.Position,
113+
request.Character,
114+
request.Options,
115+
cancellationToken).ConfigureAwait(false) is not { } htmlChanges)
116+
{
117+
return null;
118+
}
119+
110120
formattedChanges = await _razorFormattingService.GetHtmlOnTypeFormattingChangesAsync(documentContext, htmlChanges, options, hostDocumentIndex, request.Character[0], cancellationToken).ConfigureAwait(false);
111121
}
112122
else

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentRangeFormattingEndpoint.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentRangeFormattingP
6969

7070
var options = RazorFormattingOptions.From(request.Options, _optionsMonitor.CurrentValue.CodeBlockBraceOnNextLine);
7171

72-
var htmlChanges = await _htmlFormatter.GetDocumentFormattingEditsAsync(documentContext.Snapshot, documentContext.Uri, request.Options, cancellationToken).ConfigureAwait(false);
72+
if (await _htmlFormatter.GetDocumentFormattingEditsAsync(
73+
documentContext.Snapshot,
74+
documentContext.Uri,
75+
request.Options,
76+
cancellationToken).ConfigureAwait(false) is not { } htmlChanges)
77+
{
78+
return null;
79+
}
80+
7381
var changes = await _razorFormattingService.GetDocumentFormattingChangesAsync(documentContext, htmlChanges, request.Range.ToLinePositionSpan(), options, cancellationToken).ConfigureAwait(false);
7482

7583
return [.. changes.Select(codeDocument.Source.Text.GetTextEdit)];

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal sealed class HtmlFormatter(
2121
{
2222
private readonly IClientConnection _clientConnection = clientConnection;
2323

24-
public async Task<ImmutableArray<TextChange>> GetDocumentFormattingEditsAsync(
24+
public async Task<ImmutableArray<TextChange>?> GetDocumentFormattingEditsAsync(
2525
IDocumentSnapshot documentSnapshot,
2626
Uri uri,
2727
FormattingOptions options,
@@ -44,14 +44,14 @@ public async Task<ImmutableArray<TextChange>> GetDocumentFormattingEditsAsync(
4444

4545
if (result?.Edits is null)
4646
{
47-
return [];
47+
return null;
4848
}
4949

5050
var sourceText = await documentSnapshot.GetTextAsync(cancellationToken).ConfigureAwait(false);
5151
return result.Edits.SelectAsArray(sourceText.GetTextChange);
5252
}
5353

54-
public async Task<ImmutableArray<TextChange>> GetOnTypeFormattingEditsAsync(
54+
public async Task<ImmutableArray<TextChange>?> GetOnTypeFormattingEditsAsync(
5555
IDocumentSnapshot documentSnapshot,
5656
Uri uri,
5757
Position position,
@@ -75,7 +75,7 @@ public async Task<ImmutableArray<TextChange>> GetOnTypeFormattingEditsAsync(
7575

7676
if (result?.Edits is null)
7777
{
78-
return [];
78+
return null;
7979
}
8080

8181
var sourceText = await documentSnapshot.GetTextAsync(cancellationToken).ConfigureAwait(false);

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/IHtmlFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
1313

1414
internal interface IHtmlFormatter
1515
{
16-
Task<ImmutableArray<TextChange>> GetDocumentFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, FormattingOptions options, CancellationToken cancellationToken);
17-
Task<ImmutableArray<TextChange>> GetOnTypeFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, Position position, string triggerCharacter, FormattingOptions options, CancellationToken cancellationToken);
16+
Task<ImmutableArray<TextChange>?> GetDocumentFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, FormattingOptions options, CancellationToken cancellationToken);
17+
Task<ImmutableArray<TextChange>?> GetOnTypeFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, Position position, string triggerCharacter, FormattingOptions options, CancellationToken cancellationToken);
1818
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_HtmlFormatting.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal partial class RazorCustomMessageTarget
1616
{
1717
// Called by the Razor Language Server to invoke a razor/htmlFormatting request on the virtual Html buffer.
1818
[JsonRpcMethod(CustomMessageNames.RazorHtmlFormattingEndpoint, UseSingleObjectParameterDeserialization = true)]
19-
public async Task<RazorDocumentFormattingResponse> HtmlFormattingAsync(RazorDocumentFormattingParams request, CancellationToken cancellationToken)
19+
public async Task<RazorDocumentFormattingResponse?> HtmlFormattingAsync(RazorDocumentFormattingParams request, CancellationToken cancellationToken)
2020
{
2121
var response = new RazorDocumentFormattingResponse() { Edits = Array.Empty<TextEdit>() };
2222

@@ -32,7 +32,7 @@ public async Task<RazorDocumentFormattingResponse> HtmlFormattingAsync(RazorDocu
3232
if (!synchronized || htmlDocument is null)
3333
{
3434
Debug.Fail("RangeFormatting not synchronized.");
35-
return response;
35+
return null;
3636
}
3737

3838
var projectedUri = htmlDocument.Uri;
@@ -51,14 +51,19 @@ public async Task<RazorDocumentFormattingResponse> HtmlFormattingAsync(RazorDocu
5151
formattingParams,
5252
cancellationToken).ConfigureAwait(false);
5353

54-
response.Edits = edits?.Response ?? Array.Empty<TextEdit>();
54+
if (edits?.Response is null)
55+
{
56+
return null;
57+
}
58+
59+
response.Edits = edits.Response;
5560

5661
return response;
5762
}
5863

5964
// Called by the Razor Language Server to invoke a razor/htmlOnTypeFormatting request on the virtual Html buffer.
6065
[JsonRpcMethod(CustomMessageNames.RazorHtmlOnTypeFormattingEndpoint, UseSingleObjectParameterDeserialization = true)]
61-
public async Task<RazorDocumentFormattingResponse> HtmlOnTypeFormattingAsync(RazorDocumentOnTypeFormattingParams request, CancellationToken cancellationToken)
66+
public async Task<RazorDocumentFormattingResponse?> HtmlOnTypeFormattingAsync(RazorDocumentOnTypeFormattingParams request, CancellationToken cancellationToken)
6267
{
6368
var response = new RazorDocumentFormattingResponse() { Edits = Array.Empty<TextEdit>() };
6469

@@ -69,7 +74,7 @@ public async Task<RazorDocumentFormattingResponse> HtmlOnTypeFormattingAsync(Raz
6974

7075
if (!synchronized || htmlDocument is null)
7176
{
72-
return response;
77+
return null;
7378
}
7479

7580
var formattingParams = new DocumentOnTypeFormattingParams()
@@ -88,7 +93,12 @@ public async Task<RazorDocumentFormattingResponse> HtmlOnTypeFormattingAsync(Raz
8893
formattingParams,
8994
cancellationToken).ConfigureAwait(false);
9095

91-
response.Edits = edits?.Response ?? Array.Empty<TextEdit>();
96+
if (edits?.Response is null)
97+
{
98+
return null;
99+
}
100+
101+
response.Edits = edits.Response;
92102

93103
return response;
94104
}

src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ private async Task RunFormattingTestInternalAsync(string input, string expected,
113113
var htmlChanges = await htmlFormatter.GetDocumentFormattingEditsAsync(documentSnapshot, uri, options, DisposalToken);
114114

115115
// Act
116-
var changes = await formattingService.GetDocumentFormattingChangesAsync(documentContext, htmlChanges, range, razorOptions, DisposalToken);
116+
var changes = await formattingService.GetDocumentFormattingChangesAsync(documentContext, htmlChanges.AssumeNotNull(), range, razorOptions, DisposalToken);
117117

118118
// Assert
119119
var edited = source.WithChanges(changes);
@@ -182,7 +182,7 @@ private protected async Task RunOnTypeFormattingTestAsync(
182182

183183
var htmlFormatter = new HtmlFormatter(client);
184184
var htmlChanges = await htmlFormatter.GetDocumentFormattingEditsAsync(documentSnapshot, uri, options, DisposalToken);
185-
changes = await formattingService.GetHtmlOnTypeFormattingChangesAsync(documentContext, htmlChanges, razorOptions, hostDocumentIndex: positionAfterTrigger, triggerCharacter: triggerCharacter, DisposalToken);
185+
changes = await formattingService.GetHtmlOnTypeFormattingChangesAsync(documentContext, htmlChanges.AssumeNotNull(), razorOptions, hostDocumentIndex: positionAfterTrigger, triggerCharacter: triggerCharacter, DisposalToken);
186186
}
187187

188188
// Assert

src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestHtmlFormatter.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,20 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using Microsoft.AspNetCore.Razor.ProjectSystem;
9-
using Microsoft.AspNetCore.Razor.Threading;
109
using Microsoft.CodeAnalysis.Text;
1110
using Microsoft.VisualStudio.LanguageServer.Protocol;
1211

1312
namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
1413

1514
internal class TestHtmlFormatter : IHtmlFormatter
1615
{
17-
public Task<ImmutableArray<TextChange>> GetDocumentFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, FormattingOptions options, CancellationToken cancellationToken)
16+
public Task<ImmutableArray<TextChange>?> GetDocumentFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, FormattingOptions options, CancellationToken cancellationToken)
1817
{
19-
return SpecializedTasks.EmptyImmutableArray<TextChange>();
18+
return Task.FromResult<ImmutableArray<TextChange>?>([]);
2019
}
2120

22-
public Task<ImmutableArray<TextChange>> GetOnTypeFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, Position position, string triggerCharacter, FormattingOptions options, CancellationToken cancellationToken)
21+
public Task<ImmutableArray<TextChange>?> GetOnTypeFormattingEditsAsync(IDocumentSnapshot documentSnapshot, Uri uri, Position position, string triggerCharacter, FormattingOptions options, CancellationToken cancellationToken)
2322
{
24-
return SpecializedTasks.EmptyImmutableArray<TextChange>();
23+
return Task.FromResult<ImmutableArray<TextChange>?>([]);
2524
}
2625
}

0 commit comments

Comments
 (0)