<commit_before>﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Indentation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Utilities;
using VSCommanding = Microsoft.VisualStudio.Commanding;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Formatting.Indentation
{
    internal abstract class AbstractSmartTokenFormatterCommandHandler :
        IChainedCommandHandler<ReturnKeyCommandArgs>
    {
        private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
        private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;

        public string DisplayName => EditorFeaturesResources.Smart_Token_Formatter;

        public AbstractSmartTokenFormatterCommandHandler(
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IEditorOperationsFactoryService editorOperationsFactoryService)
        {
            _undoHistoryRegistry = undoHistoryRegistry;
            _editorOperationsFactoryService = editorOperationsFactoryService;
        }

        protected abstract ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnumerable<AbstractFormattingRule> formattingRules, SyntaxNode root);

        protected abstract bool UseSmartTokenFormatter(SyntaxNode root, TextLine line, IEnumerable<AbstractFormattingRule> formattingRules, OptionSet options, CancellationToken cancellationToken);
        protected abstract bool IsInvalidToken(SyntaxToken token);

        protected abstract IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document, int position);

        /// <returns>True if any change is made.</returns>
        protected bool FormatToken(ITextView view, Document document, SyntaxToken token, IEnumerable<AbstractFormattingRule> formattingRules, CancellationToken cancellationToken)
        {
            var root = document.GetSyntaxRootSynchronously(cancellationToken);
            var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var formatter = CreateSmartTokenFormatter(documentOptions, formattingRules, root);
            var changes = formatter.FormatTokenAsync(document.Project.Solution.Workspace, token, cancellationToken).WaitAndGetResult(cancellationToken);
            if (changes.Count == 0)
            {
                return false;
            }

            using (var transaction = CreateEditTransaction(view, EditorFeaturesResources.Format_Token))
            {
                transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance;

                document.Project.Solution.Workspace.ApplyTextChanges(document.Id, changes, cancellationToken);
                transaction.Complete();
            }

            return true;
        }

        public VSCommanding.CommandState GetCommandState(ReturnKeyCommandArgs args, Func<VSCommanding.CommandState> nextHandler)
        {
            return nextHandler();
        }

        public void ExecuteCommand(ReturnKeyCommandArgs args, Action nextHandler, CommandExecutionContext context)
        {
            var textView = args.TextView;
            var oldCaretPoint = textView.GetCaretPoint(args.SubjectBuffer);

            nextHandler();

            // A feature like completion handled the return key but did not pass it on to the editor.
            var newCaretPoint = textView.GetCaretPoint(args.SubjectBuffer);
            if (textView.Selection.IsEmpty && oldCaretPoint.HasValue && newCaretPoint.HasValue &&
                oldCaretPoint.Value.GetContainingLine().LineNumber == newCaretPoint.Value.GetContainingLine().LineNumber)
            {
                return;
            }

            if (args.SubjectBuffer.CanApplyChangeDocumentToWorkspace())
            {
                ExecuteCommandWorker(args, CancellationToken.None);
            }
        }

        internal void ExecuteCommandWorker(ReturnKeyCommandArgs args, CancellationToken cancellationToken)
        {
            var textView = args.TextView;
            var caretPoint = textView.GetCaretPoint(args.SubjectBuffer);

            if (!caretPoint.HasValue)
            {
                return;
            }

            var currentPosition = caretPoint.Value;
            var document = currentPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
            if (document == null)
            {
                return;
            }

            var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            if (documentOptions.GetOption(FormattingOptions.SmartIndent) != FormattingOptions.IndentStyle.Smart)
            {
                return;
            }

            var formattingRules = this.GetFormattingRules(document, currentPosition.Position);

            // see whether we should use token formatter
            if (TryFormatUsingTokenFormatter(textView, args.SubjectBuffer, document, formattingRules, cancellationToken))
            {
                return;
            }

            // check whether editor would have used smart indenter
            if (EditorHandled(textView) && !RequireReadjustment(textView, args.SubjectBuffer))
            {
                // editor already took care of smart indentation.
                return;
            }

            // check whether we can do it ourselves
            if (!CanHandleOurselves(textView, args.SubjectBuffer))
            {
                return;
            }

            var indentationService = document.GetLanguageService<CodeAnalysis.Indentation.IIndentationService>();<commit_msg>Move using inside<commit_after>﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Utilities;
using VSCommanding = Microsoft.VisualStudio.Commanding;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Formatting.Indentation
{
    // Place this using inside the containing namespace so it takes precedence over
    // the older Editor version with the same name.
    using Microsoft.CodeAnalysis.Indentation;

    internal abstract class AbstractSmartTokenFormatterCommandHandler :
        IChainedCommandHandler<ReturnKeyCommandArgs>
    {
        private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
        private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;

        public string DisplayName => EditorFeaturesResources.Smart_Token_Formatter;

        public AbstractSmartTokenFormatterCommandHandler(
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IEditorOperationsFactoryService editorOperationsFactoryService)
        {
            _undoHistoryRegistry = undoHistoryRegistry;
            _editorOperationsFactoryService = editorOperationsFactoryService;
        }

        protected abstract ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnumerable<AbstractFormattingRule> formattingRules, SyntaxNode root);

        protected abstract bool UseSmartTokenFormatter(SyntaxNode root, TextLine line, IEnumerable<AbstractFormattingRule> formattingRules, OptionSet options, CancellationToken cancellationToken);
        protected abstract bool IsInvalidToken(SyntaxToken token);

        protected abstract IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document, int position);

        /// <returns>True if any change is made.</returns>
        protected bool FormatToken(ITextView view, Document document, SyntaxToken token, IEnumerable<AbstractFormattingRule> formattingRules, CancellationToken cancellationToken)
        {
            var root = document.GetSyntaxRootSynchronously(cancellationToken);
            var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var formatter = CreateSmartTokenFormatter(documentOptions, formattingRules, root);
            var changes = formatter.FormatTokenAsync(document.Project.Solution.Workspace, token, cancellationToken).WaitAndGetResult(cancellationToken);
            if (changes.Count == 0)
            {
                return false;
            }

            using (var transaction = CreateEditTransaction(view, EditorFeaturesResources.Format_Token))
            {
                transaction.MergePolicy = AutomaticCodeChangeMergePolicy.Instance;

                document.Project.Solution.Workspace.ApplyTextChanges(document.Id, changes, cancellationToken);
                transaction.Complete();
            }

            return true;
        }

        public VSCommanding.CommandState GetCommandState(ReturnKeyCommandArgs args, Func<VSCommanding.CommandState> nextHandler)
        {
            return nextHandler();
        }

        public void ExecuteCommand(ReturnKeyCommandArgs args, Action nextHandler, CommandExecutionContext context)
        {
            var textView = args.TextView;
            var oldCaretPoint = textView.GetCaretPoint(args.SubjectBuffer);

            nextHandler();

            // A feature like completion handled the return key but did not pass it on to the editor.
            var newCaretPoint = textView.GetCaretPoint(args.SubjectBuffer);
            if (textView.Selection.IsEmpty && oldCaretPoint.HasValue && newCaretPoint.HasValue &&
                oldCaretPoint.Value.GetContainingLine().LineNumber == newCaretPoint.Value.GetContainingLine().LineNumber)
            {
                return;
            }

            if (args.SubjectBuffer.CanApplyChangeDocumentToWorkspace())
            {
                ExecuteCommandWorker(args, CancellationToken.None);
            }
        }

        internal void ExecuteCommandWorker(ReturnKeyCommandArgs args, CancellationToken cancellationToken)
        {
            var textView = args.TextView;
            var caretPoint = textView.GetCaretPoint(args.SubjectBuffer);

            if (!caretPoint.HasValue)
            {
                return;
            }

            var currentPosition = caretPoint.Value;
            var document = currentPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
            if (document == null)
            {
                return;
            }

            var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            if (documentOptions.GetOption(FormattingOptions.SmartIndent) != FormattingOptions.IndentStyle.Smart)
            {
                return;
            }

            var formattingRules = this.GetFormattingRules(document, currentPosition.Position);

            // see whether we should use token formatter
            if (TryFormatUsingTokenFormatter(textView, args.SubjectBuffer, document, formattingRules, cancellationToken))
            {
                return;
            }

            // check whether editor would have used smart indenter
            if (EditorHandled(textView) && !RequireReadjustment(textView, args.SubjectBuffer))
            {
                // editor already took care of smart indentation.
                return;
            }

            // check whether we can do it ourselves
            if (!CanHandleOurselves(textView, args.SubjectBuffer))
            {
                return;
            }

            var indentationService = document.GetLanguageService<IIndentationService>();
{'fraction_non_alphanumeric': 0.0653076923076923, 'fraction_numerical': 0.00046153846153846153, 'mean_word_length': 2.93850348379279, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, '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': '146224', 'n_tokens_mistral': 2984, 'n_tokens_neox': 2911, 'n_words': 659}