File: MetadataAsSource\FormattingRule.cs
Web Access
Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features)
// 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.

#nullable disable

using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.MetadataAsSource;

internal sealed partial class CSharpMetadataAsSourceService
{
    private sealed class FormattingRule : AbstractMetadataFormattingRule
    {
        protected override AdjustNewLinesOperation GetAdjustNewLinesOperationBetweenMembersAndUsings(SyntaxToken token1, SyntaxToken token2)
        {
            var previousToken = token1;
            var currentToken = token2;

            // We are not between members or usings if the last token wasn't the end of a statement or if the current token
            // is the end of a scope.
            if ((previousToken.Kind() != SyntaxKind.SemicolonToken && previousToken.Kind() != SyntaxKind.CloseBraceToken) ||
                currentToken.Kind() == SyntaxKind.CloseBraceToken)
            {
                return null;
            }

            SyntaxNode previousMember = FormattingRangeHelper.GetEnclosingMember(previousToken);
            SyntaxNode nextMember = FormattingRangeHelper.GetEnclosingMember(currentToken);

            // Is the previous statement an using directive? If so, treat it like a member to add
            // the right number of lines.
            if (previousToken.Kind() == SyntaxKind.SemicolonToken && previousToken.Parent.Kind() == SyntaxKind.UsingDirective)
            {
                previousMember = previousToken.Parent;
            }

            if (previousMember == null || nextMember == null || previousMember == nextMember)
            {
                return null;
            }

            // If we have two members of the same kind, we won't insert a blank line 
            if (previousMember.Kind() == nextMember.Kind())
            {
                return FormattingOperations.CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.ForceLines);
            }

            // Force a blank line between the two nodes by counting the number of lines of
            // trivia and adding one to it.
            var triviaList = token1.TrailingTrivia.Concat(token2.LeadingTrivia);
            return FormattingOperations.CreateAdjustNewLinesOperation(GetNumberOfLines(triviaList) + 1, AdjustNewLinesOption.ForceLines);
        }

        public override void AddAnchorIndentationOperations(List<AnchorIndentationOperation> list, SyntaxNode node, in NextAnchorIndentationOperationAction nextOperation)
        {
            return;
        }

        protected override bool IsNewLine(char c)
            => SyntaxFacts.IsNewLine(c);
    }
}