<commit_before>﻿// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Indentation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Indentation
{
    internal class CSharpSmartTokenFormatter : ISmartTokenFormatter
    {
        private readonly IndentationOptions _options;
        private readonly IEnumerable<AbstractFormattingRule> _formattingRules;

        private readonly CompilationUnitSyntax _root;

        public CSharpSmartTokenFormatter(
            IndentationOptions options,
            IEnumerable<AbstractFormattingRule> formattingRules,
            CompilationUnitSyntax root)
        {
            Contract.ThrowIfNull(formattingRules);
            Contract.ThrowIfNull(root);

            _options = options;
            _formattingRules = formattingRules;

            _root = root;
        }

        public IList<TextChange> FormatRange(
            HostWorkspaceServices services, SyntaxToken startToken, SyntaxToken endToken, CancellationToken cancellationToken)
        {
            Contract.ThrowIfTrue(startToken.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);
            Contract.ThrowIfTrue(endToken.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);

            var smartTokenformattingRules = _formattingRules;
            var common = startToken.GetCommonRoot(endToken);
            RoslynDebug.AssertNotNull(common);

            // if there are errors, do not touch lines
            // Exception 1: In the case of try-catch-finally block, a try block without a catch/finally block is considered incomplete
            //            but we would like to apply line operation in a completed try block even if there is no catch/finally block
            // Exception 2: Similar behavior for do-while
            if (common.ContainsDiagnostics && !CloseBraceOfTryOrDoBlock(endToken))
            {
                smartTokenformattingRules = (new NoLineChangeFormattingRule()).Concat(_formattingRules);
            }

            return Formatter.GetFormattedTextChanges(_root, new[] { TextSpan.FromBounds(startToken.SpanStart, endToken.Span.End) }, services, _options.FormattingOptions, smartTokenformattingRules, cancellationToken);
        }

        private static bool CloseBraceOfTryOrDoBlock(SyntaxToken endToken)
        {
            return endToken.IsKind(SyntaxKind.CloseBraceToken) &&
                endToken.Parent.IsKind(SyntaxKind.Block) &&
                (endToken.Parent.IsParentKind(SyntaxKind.TryStatement) || endToken.Parent.IsParentKind(SyntaxKind.DoStatement));
        }

        public async Task<IList<TextChange>> FormatTokenAsync(
            SyntaxToken token, CancellationToken cancellationToken)
        {
            Contract.ThrowIfTrue(token.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);

            // get previous token
            var previousToken = token.GetPreviousToken(includeZeroWidth: true);
            if (previousToken.Kind() == SyntaxKind.None)
            {
                // no previous token. nothing to format
                return SpecializedCollections.EmptyList<TextChange>();
            }

            // This is a heuristic to prevent brace completion from breaking user expectation/muscle memory in common scenarios (see Devdiv:823958).
            // Formatter uses FindToken on the position, which returns token to left, if there is nothing to the right and returns token to the right
            // if there exists one. If the shape is "{|}", we're including '}' in the formatting range. Avoid doing that to improve verbatim typing
            // in the following special scenarios.  
            var adjustedEndPosition = token.Span.End;
            if (token.IsKind(SyntaxKind.OpenBraceToken) &&
                (token.Parent.IsInitializerForArrayOrCollectionCreationExpression() ||
                    token.Parent is AnonymousObjectCreationExpressionSyntax))
            {<commit_msg>Get C# ISmartTokenFormatter off of HostWorkspaceServices<commit_after>﻿// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Indentation;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Indentation
{
    internal class CSharpSmartTokenFormatter : ISmartTokenFormatter
    {
        private readonly IndentationOptions _options;
        private readonly IEnumerable<AbstractFormattingRule> _formattingRules;

        private readonly CompilationUnitSyntax _root;

        public CSharpSmartTokenFormatter(
            IndentationOptions options,
            IEnumerable<AbstractFormattingRule> formattingRules,
            CompilationUnitSyntax root)
        {
            Contract.ThrowIfNull(formattingRules);
            Contract.ThrowIfNull(root);

            _options = options;
            _formattingRules = formattingRules;

            _root = root;
        }

        public IList<TextChange> FormatRange(
            SyntaxToken startToken, SyntaxToken endToken, CancellationToken cancellationToken)
        {
            Contract.ThrowIfTrue(startToken.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);
            Contract.ThrowIfTrue(endToken.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);

            var smartTokenformattingRules = _formattingRules;
            var common = startToken.GetCommonRoot(endToken);
            RoslynDebug.AssertNotNull(common);

            // if there are errors, do not touch lines
            // Exception 1: In the case of try-catch-finally block, a try block without a catch/finally block is considered incomplete
            //            but we would like to apply line operation in a completed try block even if there is no catch/finally block
            // Exception 2: Similar behavior for do-while
            if (common.ContainsDiagnostics && !CloseBraceOfTryOrDoBlock(endToken))
            {
                smartTokenformattingRules = (new NoLineChangeFormattingRule()).Concat(_formattingRules);
            }

            var formatter = CSharpSyntaxFormatting.Instance;
            var result = formatter.GetFormattingResult(
                _root, new[] { TextSpan.FromBounds(startToken.SpanStart, endToken.Span.End) }, _options.FormattingOptions, smartTokenformattingRules, cancellationToken);
            return result.GetTextChanges();
        }

        private static bool CloseBraceOfTryOrDoBlock(SyntaxToken endToken)
        {
            return endToken.IsKind(SyntaxKind.CloseBraceToken) &&
                endToken.Parent.IsKind(SyntaxKind.Block) &&
                (endToken.Parent.IsParentKind(SyntaxKind.TryStatement) || endToken.Parent.IsParentKind(SyntaxKind.DoStatement));
        }

        public async Task<IList<TextChange>> FormatTokenAsync(
            SyntaxToken token, CancellationToken cancellationToken)
        {
            Contract.ThrowIfTrue(token.Kind() is SyntaxKind.None or SyntaxKind.EndOfFileToken);

            // get previous token
            var previousToken = token.GetPreviousToken(includeZeroWidth: true);
            if (previousToken.Kind() == SyntaxKind.None)
            {
                // no previous token. nothing to format
                return SpecializedCollections.EmptyList<TextChange>();
            }

            // This is a heuristic to prevent brace completion from breaking user expectation/muscle memory in common scenarios (see Devdiv:823958).
            // Formatter uses FindToken on the position, which returns token to left, if there is nothing to the right and returns token to the right
            // if there exists one. If the shape is "{|}", we're including '}' in the formatting range. Avoid doing that to improve verbatim typing
            // in the following special scenarios.  
            var adjustedEndPosition = token.Span.End;
            if (token.IsKind(SyntaxKind.OpenBraceToken) &&
                (token.Parent.IsInitializerForArrayOrCollectionCreationExpression() ||
                    token.Parent is AnonymousObjectCreationExpressionSyntax))
            {
{'fraction_non_alphanumeric': 0.06822591075662858, 'fraction_numerical': 0.0017245095925846087, 'mean_word_length': 2.837468982630273, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5326973', 'n_tokens_mistral': 2254, 'n_tokens_neox': 2184, 'n_words': 627}