|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Formatting;
internal abstract class AbstractSyntaxFormatting : ISyntaxFormatting
{
private static readonly Func<TextSpan, bool> s_notEmpty = s => !s.IsEmpty;
public abstract SyntaxFormattingOptions DefaultOptions { get; }
public abstract SyntaxFormattingOptions GetFormattingOptions(IOptionsReader options);
public abstract ImmutableArray<AbstractFormattingRule> GetDefaultFormattingRules();
protected abstract IFormattingResult CreateAggregatedFormattingResult(SyntaxNode node, IList<AbstractFormattingResult> results, TextSpanMutableIntervalTree? formattingSpans = null);
protected abstract AbstractFormattingResult Format(SyntaxNode node, SyntaxFormattingOptions options, ImmutableArray<AbstractFormattingRule> rules, SyntaxToken startToken, SyntaxToken endToken, CancellationToken cancellationToken);
public IFormattingResult GetFormattingResult(SyntaxNode node, IEnumerable<TextSpan>? spans, SyntaxFormattingOptions options, ImmutableArray<AbstractFormattingRule> rules, CancellationToken cancellationToken)
{
IReadOnlyList<TextSpan> spansToFormat;
if (spans == null)
{
spansToFormat = node.FullSpan.IsEmpty ? [] : [node.FullSpan];
}
else
{
spansToFormat = new NormalizedTextSpanCollection(spans.Where(s_notEmpty));
}
if (spansToFormat.Count == 0)
{
return CreateAggregatedFormattingResult(node, results: []);
}
if (rules.IsDefault)
rules = GetDefaultFormattingRules();
List<AbstractFormattingResult>? results = null;
foreach (var (startToken, endToken) in node.ConvertToTokenPairs(spansToFormat))
{
if (node.IsInvalidTokenRange(startToken, endToken))
{
continue;
}
results ??= [];
results.Add(Format(node, options, rules, startToken, endToken, cancellationToken));
}
// quick simple case check
if (results == null)
{
return CreateAggregatedFormattingResult(node, results: []);
}
if (results.Count == 1)
{
return results[0];
}
// more expensive case
return CreateAggregatedFormattingResult(node, results);
}
}
|