<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.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion
{
    using CompletionTrigger = Microsoft.CodeAnalysis.Completion.CompletionTrigger;
    using CompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem;

    internal partial class Controller :
        AbstractController<Controller.Session, Model, ICompletionPresenterSession, ICompletionSession>,
        IChainedCommandHandler<TabKeyCommandArgs>,
        IChainedCommandHandler<ToggleCompletionModeCommandArgs>,
        IChainedCommandHandler<TypeCharCommandArgs>,
        IChainedCommandHandler<ReturnKeyCommandArgs>,
        IChainedCommandHandler<InvokeCompletionListCommandArgs>,
        IChainedCommandHandler<CommitUniqueCompletionListItemCommandArgs>,
        IChainedCommandHandler<PageUpKeyCommandArgs>,
        IChainedCommandHandler<PageDownKeyCommandArgs>,
        IChainedCommandHandler<CutCommandArgs>,
        IChainedCommandHandler<PasteCommandArgs>,
        IChainedCommandHandler<BackspaceKeyCommandArgs>,
        IChainedCommandHandler<InsertSnippetCommandArgs>,
        IChainedCommandHandler<SurroundWithCommandArgs>,
        IChainedCommandHandler<AutomaticLineEnderCommandArgs>,
        IChainedCommandHandler<SaveCommandArgs>,
        IChainedCommandHandler<DeleteKeyCommandArgs>,
        IChainedCommandHandler<SelectAllCommandArgs>
    {
        private static readonly object s_controllerPropertyKey = new object();

        private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
        private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
        private readonly ImmutableHashSet<char> _autoBraceCompletionChars;
        private readonly bool _isDebugger;
        private readonly bool _isImmediateWindow;
        private readonly ImmutableHashSet<string> _roles;

        public Controller(
            IThreadingContext threadingContext,
            ITextView textView,
            ITextBuffer subjectBuffer,
            IEditorOperationsFactoryService editorOperationsFactoryService,
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IIntelliSensePresenter<ICompletionPresenterSession, ICompletionSession> presenter,
            IAsynchronousOperationListener asyncListener,
            ImmutableHashSet<char> autoBraceCompletionChars,
            bool isDebugger,
            bool isImmediateWindow)
            : base(threadingContext, textView, subjectBuffer, presenter, asyncListener, null, "Completion")
        {
            _editorOperationsFactoryService = editorOperationsFactoryService;
            _undoHistoryRegistry = undoHistoryRegistry;
            _autoBraceCompletionChars = autoBraceCompletionChars;
            _isDebugger = isDebugger;
            _isImmediateWindow = isImmediateWindow;
            _roles = textView.Roles.ToImmutableHashSet();
        }

        internal static Controller GetInstance(
            IThreadingContext threadingContext,
            ITextView textView,
            ITextBuffer subjectBuffer,
            IEditorOperationsFactoryService editorOperationsFactoryService,
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IIntelliSensePresenter<ICompletionPresenterSession, ICompletionSession> presenter,
            IAsynchronousOperationListener asyncListener,
            ImmutableHashSet<char> autoBraceCompletionChars)
        {
            var debuggerTextView = textView as IDebuggerTextView;
            var isDebugger = debuggerTextView != null;
            var isImmediateWindow = isDebugger && debuggerTextView.IsImmediateWindow;

            return textView.GetOrCreatePerSubjectBufferProperty(subjectBuffer, s_controllerPropertyKey,
                (v, b) => new Controller(
                    threadingContext,
                    textView, subjectBuffer, editorOperationsFactoryService, undoHistoryRegistry, 
                    presenter, asyncListener, autoBraceCompletionChars, isDebugger, isImmediateWindow));
        }

        private SnapshotPoint GetCaretPointInViewBuffer()
        {
            AssertIsForeground();
            return this.TextView.Caret.Position.BufferPosition;
        }

        private SnapshotPoint GetCaretPointInSubjectBuffer()
        {
            AssertIsForeground();
            return this.TextView.BufferGraph.MapUpOrDownToBuffer(this.TextView.Caret.Position.BufferPosition, this.SubjectBuffer).GetValueOrDefault();
        }

        private bool ShouldBlockForCompletionItems()
        {
            var service = GetCompletionService();
            var options = GetOptions();
            if (service == null || options == null)
            {
                return true;
            }

            return options.GetOption(CompletionOptions.BlockForCompletionItems, service.Language);
        }

        private Model WaitForModel()
        {
            this.AssertIsForeground();

            var shouldBlock = ShouldBlockForCompletionItems();
            var model = sessionOpt.WaitForModel_DoNotCallDirectly(shouldBlock);
            if (model == null && !shouldBlock)
            {
                // We didn't get a model back, and we're a language that doesn't want to block
                // when this happens.  Essentially, the user typed something like a commit 
                // character before we got any results back.  In this case, because we're not
                // willing to block, we just stop everything that we're doing and return to 
                // the non-active state.
                DismissSessionIfActive();
            }

            return model;
        }

        internal override void OnModelUpdated(Model modelOpt)
        {
            AssertIsForeground();
            if (modelOpt == null)
            {
                this.DismissSessionIfActive();
            }
            else
            {
                var selectedItem = modelOpt.SelectedItemOpt;
                var viewSpan = selectedItem == null ? (ViewTextSpan?)null : modelOpt.GetViewBufferSpan(selectedItem.Span);
                var triggerSpan = viewSpan == null 
                    ? null
                    : modelOpt.GetCurrentSpanInSnapshot(viewSpan.Value, this.TextView.TextSnapshot)
                              .CreateTrackingSpan(SpanTrackingMode.EdgeInclusive);

                sessionOpt.PresenterSession.PresentItems(
                    triggerSpan, modelOpt.FilteredItems, selectedItem,
                    modelOpt.SuggestionModeItem, modelOpt.UseSuggestionMode,
                    modelOpt.IsSoftSelection, modelOpt.CompletionItemFilters, modelOpt.FilterText);
            }
        }

        private bool StartNewModelComputation(
            CompletionService completionService,
            CompletionTrigger trigger)<commit_msg>fix 'Queue empty' exception with scrolling in the break point conditi… (#28597)<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.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion
{
    using CompletionTrigger = Microsoft.CodeAnalysis.Completion.CompletionTrigger;
    using CompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem;

    internal partial class Controller :
        AbstractController<Controller.Session, Model, ICompletionPresenterSession, ICompletionSession>,
        IChainedCommandHandler<TabKeyCommandArgs>,
        IChainedCommandHandler<ToggleCompletionModeCommandArgs>,
        IChainedCommandHandler<TypeCharCommandArgs>,
        IChainedCommandHandler<ReturnKeyCommandArgs>,
        IChainedCommandHandler<InvokeCompletionListCommandArgs>,
        IChainedCommandHandler<CommitUniqueCompletionListItemCommandArgs>,
        IChainedCommandHandler<PageUpKeyCommandArgs>,
        IChainedCommandHandler<PageDownKeyCommandArgs>,
        IChainedCommandHandler<CutCommandArgs>,
        IChainedCommandHandler<PasteCommandArgs>,
        IChainedCommandHandler<BackspaceKeyCommandArgs>,
        IChainedCommandHandler<InsertSnippetCommandArgs>,
        IChainedCommandHandler<SurroundWithCommandArgs>,
        IChainedCommandHandler<AutomaticLineEnderCommandArgs>,
        IChainedCommandHandler<SaveCommandArgs>,
        IChainedCommandHandler<DeleteKeyCommandArgs>,
        IChainedCommandHandler<SelectAllCommandArgs>
    {
        private static readonly object s_controllerPropertyKey = new object();

        private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
        private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
        private readonly ImmutableHashSet<char> _autoBraceCompletionChars;
        private readonly bool _isDebugger;
        private readonly bool _isImmediateWindow;
        private readonly ImmutableHashSet<string> _roles;

        public Controller(
            IThreadingContext threadingContext,
            ITextView textView,
            ITextBuffer subjectBuffer,
            IEditorOperationsFactoryService editorOperationsFactoryService,
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IIntelliSensePresenter<ICompletionPresenterSession, ICompletionSession> presenter,
            IAsynchronousOperationListener asyncListener,
            ImmutableHashSet<char> autoBraceCompletionChars,
            bool isDebugger,
            bool isImmediateWindow)
            : base(threadingContext, textView, subjectBuffer, presenter, asyncListener, null, "Completion")
        {
            _editorOperationsFactoryService = editorOperationsFactoryService;
            _undoHistoryRegistry = undoHistoryRegistry;
            _autoBraceCompletionChars = autoBraceCompletionChars;
            _isDebugger = isDebugger;
            _isImmediateWindow = isImmediateWindow;
            _roles = textView.Roles.ToImmutableHashSet();
        }

        internal static Controller GetInstance(
            IThreadingContext threadingContext,
            ITextView textView,
            ITextBuffer subjectBuffer,
            IEditorOperationsFactoryService editorOperationsFactoryService,
            ITextUndoHistoryRegistry undoHistoryRegistry,
            IIntelliSensePresenter<ICompletionPresenterSession, ICompletionSession> presenter,
            IAsynchronousOperationListener asyncListener,
            ImmutableHashSet<char> autoBraceCompletionChars)
        {
            var debuggerTextView = textView as IDebuggerTextView;
            var isDebugger = debuggerTextView != null;
            var isImmediateWindow = isDebugger && debuggerTextView.IsImmediateWindow;

            return textView.GetOrCreatePerSubjectBufferProperty(subjectBuffer, s_controllerPropertyKey,
                (v, b) => new Controller(
                    threadingContext,
                    textView, subjectBuffer, editorOperationsFactoryService, undoHistoryRegistry, 
                    presenter, asyncListener, autoBraceCompletionChars, isDebugger, isImmediateWindow));
        }

        private SnapshotPoint GetCaretPointInViewBuffer()
        {
            AssertIsForeground();
            return this.TextView.Caret.Position.BufferPosition;
        }

        private SnapshotPoint GetCaretPointInSubjectBuffer()
        {
            AssertIsForeground();
            return this.TextView.BufferGraph.MapUpOrDownToBuffer(this.TextView.Caret.Position.BufferPosition, this.SubjectBuffer).GetValueOrDefault();
        }

        private bool ShouldBlockForCompletionItems()
        {
            var service = GetCompletionService();
            var options = GetOptions();
            if (service == null || options == null)
            {
                return true;
            }

            return options.GetOption(CompletionOptions.BlockForCompletionItems, service.Language);
        }

        private Model WaitForModel()
        {
            this.AssertIsForeground();

            var shouldBlock = ShouldBlockForCompletionItems();
            var model = sessionOpt.WaitForModel_DoNotCallDirectly(shouldBlock);
            if (model == null && !shouldBlock)
            {
                // We didn't get a model back, and we're a language that doesn't want to block
                // when this happens.  Essentially, the user typed something like a commit
                // character before we got any results back.  In this case, because we're not
                // willing to block, we just stop everything that we're doing and return to
                // the non-active state.
                DismissSessionIfActive();
            }

            return model;
        }

        internal override void OnModelUpdated(Model modelOpt)
        {
            AssertIsForeground();
            if (modelOpt == null)
            {
                this.DismissSessionIfActive();
            }
            else
            {
                var selectedItem = modelOpt.SelectedItemOpt;

                // set viewSpan = null if the selectedItem is not from the completion list
                // All items from the completion list have .Document set to current document 
                // in CompletionService.GetCompletionsAndSetItemDocumentAsync
                // https://github.com/dotnet/roslyn/issues/23891
                var viewSpan = selectedItem == null || selectedItem.Document == null
                    ? (ViewTextSpan?)null
                    : modelOpt.GetViewBufferSpan(selectedItem.Span);

                var triggerSpan = viewSpan == null
                    ? null
                    : modelOpt.GetCurrentSpanInSnapshot(viewSpan.Value, this.TextView.TextSnapshot)
                              .CreateTrackingSpan(SpanTrackingMode.EdgeInclusive);

                sessionOpt.PresenterSession.PresentItems(
                    triggerSpan, modelOpt.FilteredItems, selectedItem,
                    modelOpt.SuggestionModeItem, modelOpt.UseSuggestionMode,
                    modelOpt.IsSoftSelection, modelOpt.CompletionItemFilters, modelOpt.FilterText);
            }
        }

        private bool StartNewModelComputation(
            CompletionService completionService,
            CompletionTrigger trigger)
{'fraction_non_alphanumeric': 0.05834829443447038, 'fraction_numerical': 0.0008976660682226212, 'mean_word_length': 2.7259913999044434, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 53, 'https://': 1, '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': '6348677', 'n_tokens_mistral': 3622, 'n_tokens_neox': 3533, 'n_words': 751}