|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.Formatting;
internal static class SnippetFormatter
{
public static bool TryGetSnippetWithAdjustedIndentation(FormattingContext formattingContext, string snippetText, int hostDocumentIndex, [NotNullWhen(true)] out string? newSnippetText)
{
newSnippetText = null;
if (!formattingContext.TryGetFormattingSpan(hostDocumentIndex, out var formattingSpan))
{
return false;
}
// Take the amount of indentation razor and html are adding, then remove the amount of C# indentation that is 'hidden'.
// This should give us the desired base indentation that must be applied to each line.
var razorAndHtmlContributionsToIndentation = formattingSpan.RazorIndentationLevel + formattingSpan.HtmlIndentationLevel;
var amountToAddToCSharpIndentation = razorAndHtmlContributionsToIndentation - formattingSpan.MinCSharpIndentLevel;
var snippetSourceText = SourceText.From(snippetText);
using var indentationChanges = new PooledArrayBuilder<TextChange>();
// Adjust each line, skipping the first since it must start at the snippet keyword.
foreach (var line in snippetSourceText.Lines.Skip(1))
{
var lineText = snippetSourceText.GetSubText(line.Span);
if (lineText.Length == 0)
{
// We just have an empty line, nothing to do.
continue;
}
// Get the indentation of the line in the C# document based on what options the C# document was generated with.
var csharpLineIndentationSize = line.GetIndentationSize(formattingContext.Options.TabSize);
var csharpIndentationLevel = csharpLineIndentationSize / formattingContext.Options.TabSize;
// Get the new indentation level based on the context in the razor document.
var newIndentationLevel = csharpIndentationLevel + amountToAddToCSharpIndentation;
var newIndentationString = formattingContext.GetIndentationLevelString(newIndentationLevel);
// Replace the current indentation with the new indentation.
var spanToReplace = new TextSpan(line.Start, line.GetFirstNonWhitespaceOffset() ?? line.Span.End);
var textChange = new TextChange(spanToReplace, newIndentationString);
indentationChanges.Add(textChange);
}
var newSnippetSourceText = snippetSourceText.WithChanges(indentationChanges.ToImmutable());
newSnippetText = newSnippetSourceText.ToString();
return true;
}
}
|