зеркало из https://github.com/dotnet/razor.git
Fix render fragment formatting in C# blocks
This commit is contained in:
Родитель
fd0673153a
Коммит
16a8596c22
|
@ -32,6 +32,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting
|
|||
_workspaceFactory = workspaceFactory;
|
||||
}
|
||||
|
||||
public static bool SkipValidateComponents { get; set; }
|
||||
|
||||
public DocumentUri Uri { get; private set; } = null!;
|
||||
|
||||
public DocumentSnapshot OriginalSnapshot { get; private set; } = null!;
|
||||
|
@ -239,6 +241,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting
|
|||
[Conditional("DEBUG")]
|
||||
private static void ValidateComponents(RazorCodeDocument oldCodeDocument, RazorCodeDocument newCodeDocument)
|
||||
{
|
||||
if (SkipValidateComponents) return;
|
||||
|
||||
var oldTagHelperElements = oldCodeDocument.GetSyntaxTree().Root.DescendantNodesAndSelf().OfType<Language.Syntax.MarkupTagHelperElementSyntax>().Count();
|
||||
var newTagHelperElements = newCodeDocument.GetSyntaxTree().Root.DescendantNodesAndSelf().OfType<Language.Syntax.MarkupTagHelperElementSyntax>().Count();
|
||||
Debug.Assert(oldTagHelperElements == newTagHelperElements, $"Previous context had {oldTagHelperElements} components, new only has {newTagHelperElements}.");
|
||||
|
|
|
@ -125,6 +125,48 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting
|
|||
|
||||
if (context.Indentations[i].StartsInCSharpContext)
|
||||
{
|
||||
// Normal we don't do HTML things in C# contexts but there is one
|
||||
// edge case when including render fragments in a C# code block, eg:
|
||||
//
|
||||
// @code {
|
||||
// void Foo()
|
||||
// {
|
||||
// Render(@<SurveyPrompt />);
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// This is popular in the bUnit unit testing library. The issue here is that
|
||||
// the HTML formatter sees ~~~~~<SurveyPrompt /> and puts a newline before
|
||||
// the tag, but obviously that breaks things.
|
||||
//
|
||||
// It's straight forward enough to just check for this situation and special case
|
||||
// it by removing the newline again.
|
||||
|
||||
// There needs to be at least one more line, and the current line needs to end with
|
||||
// an @ sign, and have an open angle bracket at the start of the next line.
|
||||
if (sourceText.Lines.Count >= i + 1 &&
|
||||
line.Text?.Length > 1 &&
|
||||
line.Text?[line.End - 1] == '@')
|
||||
{
|
||||
var nextLine = sourceText.Lines[i + 1];
|
||||
var firstChar = nextLine.GetFirstNonWhitespaceOffset().GetValueOrDefault();
|
||||
|
||||
// When the HTML formatter inserts the newline in this scenario, it doesn't
|
||||
// indent the component tag, so we use that as another signal that this is
|
||||
// the scenario we think it is.
|
||||
if (firstChar == 0 &&
|
||||
nextLine.Text?[nextLine.Start] == '<')
|
||||
{
|
||||
var lineBreakLength = line.EndIncludingLineBreak - line.End;
|
||||
var spanToReplace = new TextSpan(line.End, lineBreakLength);
|
||||
var change = new TextChange(spanToReplace, string.Empty);
|
||||
editsToApply.Add(change);
|
||||
|
||||
// Skip the next line because we've essentially just removed it.
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -823,6 +823,49 @@ else
|
|||
");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
[WorkItem("https://github.com/dotnet/razor-tooling/issues/5749")]
|
||||
public async Task FormatRenderFragmentInCSharpCodeBlock(bool useSourceTextDiffer)
|
||||
{
|
||||
// Sadly the first thing the HTML formatter does with this input
|
||||
// is put a newline after the @, which means <SurveyPrompt /> won't be
|
||||
// seen as a component any more, so we have to turn off our validation,
|
||||
// or the test fails before we have a chance to fix the formatting.
|
||||
FormattingContext.SkipValidateComponents = true;
|
||||
|
||||
await RunFormattingTestAsync(useSourceTextDiffer: useSourceTextDiffer,
|
||||
input: @"
|
||||
@code
|
||||
{
|
||||
public void DoStuff(RenderFragment renderFragment)
|
||||
{
|
||||
renderFragment(@<SurveyPrompt Title=""Foo"" />);
|
||||
|
||||
@* comment *@
|
||||
<div></div>
|
||||
|
||||
@* comment *@<div></div>
|
||||
}
|
||||
}
|
||||
",
|
||||
expected: @"@code
|
||||
{
|
||||
public void DoStuff(RenderFragment renderFragment)
|
||||
{
|
||||
renderFragment(@<SurveyPrompt Title=""Foo"" />);
|
||||
|
||||
@* comment *@
|
||||
<div></div>
|
||||
|
||||
@* comment *@
|
||||
<div></div>
|
||||
}
|
||||
}
|
||||
",
|
||||
tagHelpers: GetSurveyPrompt());
|
||||
}
|
||||
|
||||
private IReadOnlyList<TagHelperDescriptor> GetSurveyPrompt()
|
||||
{
|
||||
AdditionalSyntaxTrees.Add(Parse(@"
|
||||
|
|
Загрузка…
Ссылка в новой задаче