From b51c9f68d10028ac693ee7604b084de3655a9cb3 Mon Sep 17 00:00:00 2001 From: Ivan Basov Date: Mon, 15 Apr 2019 10:08:35 -0700 Subject: [PATCH] disable completion for immediate window commands (#32631) --- .../Completion/AsyncCompletionService.cs | 10 +++++ .../AbstractDebuggerIntelliSenseContext.cs | 13 ++---- .../DebuggerIntellisenseFilter.cs | 44 +++++++++++++++---- ...vice`2.IVsImmediateStatementCompletion2.cs | 19 +++++--- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/AsyncCompletionService.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/AsyncCompletionService.cs index fdd8d3275b8..fbcad72bd22 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/AsyncCompletionService.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/AsyncCompletionService.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.BraceCompletion; @@ -26,6 +27,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion internal class AsyncCompletionService : ForegroundThreadAffinitizedObject, IAsyncCompletionService { private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly IFeatureServiceFactory _featureServiceFactory; private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IInlineRenameService _inlineRenameService; private readonly IIntelliSensePresenter _completionPresenter; @@ -45,6 +47,7 @@ internal class AsyncCompletionService : ForegroundThreadAffinitizedObject, IAsyn public AsyncCompletionService( IThreadingContext threadingContext, IEditorOperationsFactoryService editorOperationsFactoryService, + IFeatureServiceFactory featureServiceFactory, ITextUndoHistoryRegistry undoHistoryRegistry, IInlineRenameService inlineRenameService, IAsynchronousOperationListenerProvider listenerProvider, @@ -53,6 +56,7 @@ internal class AsyncCompletionService : ForegroundThreadAffinitizedObject, IAsyn : base(threadingContext) { _editorOperationsFactoryService = editorOperationsFactoryService; + _featureServiceFactory = featureServiceFactory; _undoHistoryRegistry = undoHistoryRegistry; _inlineRenameService = inlineRenameService; _completionPresenter = ExtensionOrderer.Order(completionPresenters).Select(lazy => lazy.Value).FirstOrDefault(); @@ -72,6 +76,12 @@ public bool TryGetController(ITextView textView, ITextBuffer subjectBuffer, out return false; } + if (!_featureServiceFactory.GetOrCreate(textView).IsEnabled(PredefinedEditorFeatureNames.Completion)) + { + controller = null; + return false; + } + var autobraceCompletionCharSet = GetAllAutoBraceCompletionChars(subjectBuffer.ContentType); controller = Controller.GetInstance( ThreadingContext, diff --git a/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs b/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs index 5d4b89cd0c4..12d2dce61a0 100644 --- a/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs +++ b/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs @@ -1,23 +1,16 @@ // 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.Collections.ObjectModel; -using System.Linq; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio; using Microsoft.VisualStudio.ComponentModelHost; -using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Projection; using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Utilities; -using TextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense { @@ -27,7 +20,7 @@ internal abstract class AbstractDebuggerIntelliSenseContext : IDisposable private readonly IContentType _contentType; private readonly IContentType _originalContentType; protected readonly IProjectionBufferFactoryService ProjectionBufferFactoryService; - protected readonly Microsoft.VisualStudio.TextManager.Interop.TextSpan CurrentStatementSpan; + protected readonly TextManager.Interop.TextSpan CurrentStatementSpan; private readonly IVsTextLines _debuggerTextLines; private IProjectionBuffer _projectionBuffer; private DebuggerTextView _debuggerTextView; @@ -49,7 +42,7 @@ private class ImmediateWindowContext IVsTextView vsTextView, IVsTextLines vsDebuggerTextLines, ITextBuffer contextBuffer, - Microsoft.VisualStudio.TextManager.Interop.TextSpan[] currentStatementSpan, + TextManager.Interop.TextSpan[] currentStatementSpan, IComponentModel componentModel, IServiceProvider serviceProvider, IContentType contentType) @@ -93,7 +86,7 @@ private class ImmediateWindowContext protected bool InImmediateWindow { get { return _immediateWindowContext != null; } } - protected ITextBuffer ContextBuffer { get; private set; } + internal ITextBuffer ContextBuffer { get; private set; } public abstract bool CompletionStartsOnQuestionMark { get; } diff --git a/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs b/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs index 065aa22dbf1..b1a1f1add37 100644 --- a/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs +++ b/src/VisualStudio/Core/Def/Implementation/DebuggerIntelliSense/DebuggerIntellisenseFilter.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; @@ -17,26 +18,46 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense { - internal class DebuggerIntelliSenseFilter : AbstractVsTextViewFilter, IDisposable + internal class DebuggerIntelliSenseFilter : AbstractVsTextViewFilter, IDisposable, IFeatureController where TPackage : AbstractPackage where TLanguageService : AbstractLanguageService { private readonly ICommandHandlerServiceFactory _commandFactory; - private readonly IWpfTextView _wpfTextView; + private readonly IFeatureServiceFactory _featureServiceFactory; private AbstractDebuggerIntelliSenseContext _context; private IOleCommandTarget _originalNextCommandFilter; - - internal bool Enabled { get; set; } + private IFeatureDisableToken _completionDisabledToken; public DebuggerIntelliSenseFilter( AbstractLanguageService languageService, IWpfTextView wpfTextView, IVsEditorAdaptersFactoryService adapterFactory, - ICommandHandlerServiceFactory commandFactory) + ICommandHandlerServiceFactory commandFactory, + IFeatureServiceFactory featureServiceFactory) : base(languageService, wpfTextView, adapterFactory, commandFactory) { - _wpfTextView = wpfTextView; _commandFactory = commandFactory; + _featureServiceFactory = featureServiceFactory; + } + + internal void EnableCompletion() + { + if (_completionDisabledToken == null) + { + return; + } + + _completionDisabledToken.Dispose(); + _completionDisabledToken = null; + } + + internal void DisableCompletion() + { + var featureService = _featureServiceFactory.GetOrCreate(WpfTextView); + if (_completionDisabledToken == null) + { + _completionDisabledToken = featureService.Disable(PredefinedEditorFeatureNames.Completion, this); + } } internal void SetNextFilter(IOleCommandTarget nextFilter) @@ -82,7 +103,7 @@ internal void SetCommandHandlers(ITextBuffer buffer) // instead of trying to have our command handlers to work. public override int Exec(ref Guid pguidCmdGroup, uint commandId, uint executeInformation, IntPtr pvaIn, IntPtr pvaOut) { - if (_context == null || !Enabled) + if (_context == null) { return NextCommandTarget.Exec(pguidCmdGroup, commandId, executeInformation, pvaIn, pvaOut); } @@ -187,6 +208,13 @@ internal void SetContentType(bool install) => _context?.SetContentType(install); public void Dispose() - => RemoveContext(); + { + if (_completionDisabledToken != null) + { + _completionDisabledToken.Dispose(); + } + + RemoveContext(); + } } } diff --git a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsImmediateStatementCompletion2.cs b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsImmediateStatementCompletion2.cs index 61984820e43..cc53411da32 100644 --- a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsImmediateStatementCompletion2.cs +++ b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsImmediateStatementCompletion2.cs @@ -8,11 +8,10 @@ using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense; -using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService { @@ -25,9 +24,18 @@ int IVsImmediateStatementCompletion2.EnableStatementCompletion(int enable, int s { if (filters.TryGetValue(textView, out var filter)) { - filter.Enabled = enable != 0; + if (enable != 0) + { + filter.EnableCompletion(); + } + else + { + filter.DisableCompletion(); + } } + // Debugger wants Roslyn to return OK in all cases, + // for example, even if Rolsyn tried to enable the one already enabled. return VSConstants.S_OK; } @@ -45,7 +53,8 @@ int IVsImmediateStatementCompletion2.InstallStatementCompletion(int install, IVs filter = new DebuggerIntelliSenseFilter(this, this.EditorAdaptersFactoryService.GetWpfTextView(textView), this.Package.ComponentModel.GetService(), - this.Package.ComponentModel.GetService()); + this.Package.ComponentModel.GetService(), + this.Package.ComponentModel.GetService()); this.filters[textView] = filter; Marshal.ThrowExceptionForHR(textView.AddCommandFilter(filter, out var nextFilter)); filter.SetNextFilter(nextFilter); @@ -66,7 +75,7 @@ int IVsImmediateStatementCompletion2.InstallStatementCompletion(int install, IVs int IVsImmediateStatementCompletion2.SetCompletionContext(string filePath, IVsTextLines buffer, - Microsoft.VisualStudio.TextManager.Interop.TextSpan[] currentStatementSpan, + TextSpan[] currentStatementSpan, object punkContext, IVsTextView textView) { -- GitLab