From 4e9856fe35297f958f95ed076c6c7a0c8f0372ce Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Thu, 23 Oct 2025 06:54:05 -0700 Subject: [PATCH] Reduce the range walked for formatting content validation Previously, this validation pass would walk over the whole content of the original and changed texts. This change modifies it instead to walk over the affected ranges in the original and changed texts based on the given set of changes. --- .../Extensions/SourceTextExtensions.cs | 28 +++++++++++++++++-- .../Passes/FormattingContentValidationPass.cs | 3 +- 2 files changed, 27 insertions(+), 4 deletions(-) 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 d8799cc88f6..692e4cfa06f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs @@ -60,8 +60,32 @@ public static string GetSubTextString(this SourceText text, TextSpan span) return new string(charBuffer, 0, span.Length); } - public static bool NonWhitespaceContentEquals(this SourceText text, SourceText other) - => NonWhitespaceContentEquals(text, other, 0, text.Length, 0, other.Length); + public static bool NonWhitespaceContentEquals(this SourceText text, ImmutableArray changes) + { + if (changes.IsEmpty) + { + return true; + } + + // Determine the affected spans in the original and changed source texts + var firstChangeSpan = changes[0].Span; + var textStart = firstChangeSpan.Start; + var textEnd = firstChangeSpan.End; + + for (var i = 1; i < changes.Length; i++) + { + var changeSpan = changes[i].Span; + + textStart = Math.Min(textStart, changeSpan.Start); + textEnd = Math.Max(textEnd, changeSpan.End); + } + + var changedText = text.WithChanges(changes); + var changedStart = textStart; + var changedEnd = textEnd + (changedText.Length - text.Length); + + return text.NonWhitespaceContentEquals(changedText, textStart, textEnd, changedStart, changedEnd); + } public static bool NonWhitespaceContentEquals( this SourceText text, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/FormattingContentValidationPass.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/FormattingContentValidationPass.cs index 1d88e41669f..cc9377744f7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/FormattingContentValidationPass.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/FormattingContentValidationPass.cs @@ -23,9 +23,8 @@ internal sealed class FormattingContentValidationPass(ILoggerFactory loggerFacto public Task IsValidAsync(FormattingContext context, ImmutableArray changes, CancellationToken cancellationToken) { var text = context.SourceText; - var changedText = text.WithChanges(changes); - if (!text.NonWhitespaceContentEquals(changedText)) + if (!text.NonWhitespaceContentEquals(changes)) { // Looks like we removed some non-whitespace content as part of formatting. Oops. // Discard this formatting result.