diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingVisitor.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingVisitor.cs index be73f528809..0f17c1d5d93 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingVisitor.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingVisitor.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; internal class FormattingVisitor : SyntaxWalker { - private const string HtmlTagName = "html"; + private const string HtmlTag = "html"; private readonly List _spans; private FormattingBlockKind _currentBlockKind; @@ -127,8 +127,13 @@ public override void VisitMarkupElement(MarkupElementSyntax node) { Visit(node.StartTag); - // Temporary fix to not break the default Html formatting behavior. Remove after https://github.com/dotnet/aspnetcore/issues/25475. - if (!string.Equals(node.StartTag?.Name?.Content, HtmlTagName, StringComparison.OrdinalIgnoreCase)) + // Void elements, like or which don't need an end tag don't cause indentation. + // We also cheat and treat the tag as a void element, so it doesn't cause indentation, + // as that's what the Html formatter does, to avoid one level of indentation in every html file. + var voidElement = node.StartTag is { } startTag && + (startTag.IsVoidElement() || string.Equals(startTag.Name.Content, HtmlTag, StringComparison.OrdinalIgnoreCase)); + + if (!voidElement) { _currentHtmlIndentationLevel++; } @@ -138,8 +143,7 @@ public override void VisitMarkupElement(MarkupElementSyntax node) Visit(child); } - // Temporary fix to not break the default Html formatting behavior. Remove after https://github.com/dotnet/aspnetcore/issues/25475. - if (!string.Equals(node.StartTag?.Name?.Content, HtmlTagName, StringComparison.OrdinalIgnoreCase)) + if (!voidElement) { _currentHtmlIndentationLevel--; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/CodeDirectiveFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/CodeDirectiveFormattingTest.cs index f372dd15e9d..b899e463e94 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/CodeDirectiveFormattingTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/CodeDirectiveFormattingTest.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -43,6 +42,36 @@ public interface Bar """); } + [Fact] + public async Task FormatCSharpInsideHtmlTag() + { + await RunFormattingTestAsync( + input: """ + + +
+ @{ + foo + foo + } +
+ + + """, + expected: """ + + +
+ @{ + foo + foo + } +
+ + + """); + } + [Fact] public async Task Format_DocumentWithDiagnostics() { @@ -437,6 +466,50 @@ @section Scripts { fileKind: FileKinds.Legacy); } + [Fact] + public async Task Format_SectionDirectiveBlock6() + { + await RunFormattingTestAsync( + input: """ + @functions { + public class Foo{ + void Method() { } + } + } + + @section Scripts { + + + + + @if(true) + { +

this is a paragraph

+ } + } + """, + expected: """ + @functions { + public class Foo + { + void Method() { } + } + } + + @section Scripts { + + + + + @if (true) + { +

this is a paragraph

+ } + } + """, + fileKind: FileKinds.Legacy); + } + [Fact] public async Task Formats_CodeBlockDirectiveWithRazorComments() {