diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs
index 77b8b9b1b8e..954acc93ae1 100644
--- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs
+++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs
@@ -296,4 +296,33 @@ public static TextEdit[] MinimizeTextEdits(this SourceText text, TextEdit[] edit
var cleanEdits = cleanChanges.Select(text.GetTextEdit).ToArray();
return cleanEdits;
}
+
+ ///
+ /// Determines if the given has more LF line endings ('\n') than CRLF line endings ('\r\n').
+ ///
+ /// The to examine.
+ ///
+ /// true if the is deemed to use LF line endings; otherwise, false.
+ ///
+ public static bool HasLFLineEndings(this SourceText text)
+ {
+ var crlfCount = 0;
+ var lfCount = 0;
+
+ foreach (var line in text.Lines)
+ {
+ var lineBreakSpan = TextSpan.FromBounds(line.End, line.EndIncludingLineBreak);
+ var lineBreak = line.Text?.ToString(lineBreakSpan) ?? string.Empty;
+ if (lineBreak == "\r\n")
+ {
+ crlfCount++;
+ }
+ else if (lineBreak == "\n")
+ {
+ lfCount++;
+ }
+ }
+
+ return lfCount > crlfCount;
+ }
}
diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPassBase.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPassBase.cs
index 4387ce3d7e6..e785aa49500 100644
--- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPassBase.cs
+++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPassBase.cs
@@ -133,7 +133,10 @@ protected async Task> AdjustIndentationAsync(FormattingContext
}
var scopeOwner = syntaxTreeRoot.FindInnermostNode(originalLocation);
- sourceMappingIndentations[originalLocation] = new IndentationData(indentation);
+ if (!sourceMappingIndentations.ContainsKey(originalLocation))
+ {
+ sourceMappingIndentations[originalLocation] = new IndentationData(indentation);
+ }
// For @section blocks we have special handling to add a fake source mapping/significant location at the end of the
// section, to return the indentation back to before the start of the section block.
diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs
index d9f012ff881..176d050550b 100644
--- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs
+++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs
@@ -108,7 +108,8 @@ public async Task GetDocumentFormattingEditsAsync(
? result
: result.Where(e => range.LineOverlapsWith(e.Range)).ToArray();
- return originalText.MinimizeTextEdits(filteredEdits);
+ var normalizedEdits = NormalizeLineEndings(originalText, filteredEdits);
+ return originalText.MinimizeTextEdits(normalizedEdits);
}
public Task GetCSharpOnTypeFormattingEditsAsync(DocumentContext documentContext, RazorFormattingOptions options, int hostDocumentIndex, char triggerCharacter, CancellationToken cancellationToken)
@@ -279,4 +280,22 @@ private static void UnwrapCSharpSnippets(TextEdit[] razorEdits)
edit.NewText = edit.NewText.Replace("/*$0*/", "$0");
}
}
+
+ ///
+ /// This method counts the occurrences of CRLF and LF line endings in the original text.
+ /// If LF line endings are more prevalent, it removes any CR characters from the text edits
+ /// to ensure consistency with the LF style.
+ ///
+ private TextEdit[] NormalizeLineEndings(SourceText originalText, TextEdit[] edits)
+ {
+ if (originalText.HasLFLineEndings())
+ {
+ foreach (var edit in edits)
+ {
+ edit.NewText = edit.NewText.Replace("\r", "");
+ }
+ }
+
+ return edits;
+ }
}
diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs
index 80589eb18ff..24ca9cf007a 100644
--- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs
+++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/CodeDirectiveFormattingTest.cs
@@ -1699,7 +1699,8 @@ await RunFormattingTestAsync(
private IEnumerable _items = new[] { 1, 2, 3, 4, 5 };
}
""",
- tagHelpers: GetComponentWithCascadingTypeParameter());
+ tagHelpers: GetComponentWithCascadingTypeParameter(),
+ skipFlipLineEndingTest: true);
}
[Fact]
@@ -1789,7 +1790,8 @@ await RunFormattingTestAsync(
private IEnumerable _items2 = new long[] { 1, 2, 3, 4, 5 };
}
""",
- tagHelpers: GetComponentWithTwoCascadingTypeParameter());
+ tagHelpers: GetComponentWithTwoCascadingTypeParameter(),
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs
index 8835b479edc..a43adfed09a 100644
--- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs
+++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs
@@ -49,14 +49,26 @@ private protected async Task RunFormattingTestAsync(
ImmutableArray tagHelpers = default,
bool allowDiagnostics = false,
RazorLSPOptions? razorLSPOptions = null,
- bool inGlobalNamespace = false)
+ bool inGlobalNamespace = false,
+ bool skipFlipLineEndingTest = false)
{
// Run with and without forceRuntimeCodeGeneration
- await RunFormattingTestAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: true);
- await RunFormattingTestAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: false);
+ await RunFormattingTestInternalAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: true);
+ await RunFormattingTestInternalAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: false);
+
+ // some tests are failing, skip for now, tracked by https://github.com/dotnet/razor/issues/10836
+ if (!skipFlipLineEndingTest)
+ {
+ // flip the line endings of the stings (LF to CRLF and vice versa) and run again
+ input = FlipLineEndings(input);
+ expected = FlipLineEndings(expected);
+
+ await RunFormattingTestInternalAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: true);
+ await RunFormattingTestInternalAsync(input, expected, tabSize, insertSpaces, fileKind, tagHelpers, allowDiagnostics, razorLSPOptions, inGlobalNamespace, forceRuntimeCodeGeneration: false);
+ }
}
- private async Task RunFormattingTestAsync(string input, string expected, int tabSize, bool insertSpaces, string? fileKind, ImmutableArray tagHelpers, bool allowDiagnostics, RazorLSPOptions? razorLSPOptions, bool inGlobalNamespace, bool forceRuntimeCodeGeneration)
+ private async Task RunFormattingTestInternalAsync(string input, string expected, int tabSize, bool insertSpaces, string? fileKind, ImmutableArray tagHelpers, bool allowDiagnostics, RazorLSPOptions? razorLSPOptions, bool inGlobalNamespace, bool forceRuntimeCodeGeneration)
{
// Arrange
fileKind ??= FileKinds.Component;
@@ -351,4 +363,26 @@ internal static IDocumentSnapshot CreateDocumentSnapshot(string path, ImmutableA
});
return documentSnapshot.Object;
}
+
+ private static string FlipLineEndings(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ {
+ return input;
+ }
+
+ var hasCRLF = input.Contains("\r\n");
+ var hasLF = !hasCRLF && input.Contains("\n");
+
+ if (hasCRLF)
+ {
+ return input.Replace("\r\n", "\n");
+ }
+ else if (hasLF)
+ {
+ return input.Replace("\n", "\r\n");
+ }
+
+ return input;
+ }
}
diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs
index 6ef32d08326..300f2fc42c1 100644
--- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs
+++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/HtmlFormattingTest.cs
@@ -487,7 +487,8 @@ await RunFormattingTestAsync(
}
""",
- tagHelpers: tagHelpers);
+ tagHelpers: tagHelpers,
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
@@ -595,7 +596,8 @@ await RunFormattingTestAsync(
@{
}
- """);
+ """,
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
@@ -1316,7 +1318,8 @@ await RunFormattingTestAsync(
public bool VarBool { get; set; }
}
""",
- fileKind: FileKinds.Component);
+ fileKind: FileKinds.Component,
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
@@ -1428,7 +1431,8 @@ await RunFormattingTestAsync(
public bool VarBool { get; set; }
}
""",
- fileKind: FileKinds.Component);
+ fileKind: FileKinds.Component,
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
@@ -1486,7 +1490,8 @@ await RunFormattingTestAsync(
public bool VarBool { get; set; }
}
""",
- fileKind: FileKinds.Component);
+ fileKind: FileKinds.Component,
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
}
[Fact]
@@ -1794,7 +1799,8 @@ await RunFormattingTestAsync(
}
""",
- tagHelpers: CreateTagHelpers());
+ tagHelpers: CreateTagHelpers(),
+ skipFlipLineEndingTest: true); // tracked by https://github.com/dotnet/razor/issues/10836
ImmutableArray CreateTagHelpers()
{