From 68b70a2fd00835528f39ef7b50a5ffc9aa9998b2 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 18 Jan 2024 09:24:42 -0600 Subject: [PATCH 1/5] Extract helper interface ISnippetExpansionClientFactory --- .../CSharpSnippetExpansionClientFactory.cs | 65 +++++++++++++++++++ .../Impl/Snippets/SnippetCommandHandler.cs | 53 +++++---------- .../Snippets/AbstractSnippetCommandHandler.cs | 28 +++----- .../AbstractSnippetExpansionClientFactory.cs | 24 +++++++ .../ISnippetExpansionClientFactory.cs | 14 ++++ .../CSharpSnippetExpansionClientTests.vb | 44 +++---------- .../Core/Test/Snippets/SnippetTestState.vb | 16 ++--- .../VisualBasicSnippetExpansionClientTests.vb | 44 +++---------- .../Impl/Snippets/SnippetCommandHandler.vb | 39 +++++------ .../Snippets/SnippetCompletionProvider.vb | 45 +++---------- .../Impl/Snippets/SnippetExpansionClient.vb | 29 --------- ...isualBasicSnippetExpansionClientFactory.vb | 65 +++++++++++++++++++ 12 files changed, 241 insertions(+), 225 deletions(-) create mode 100644 src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs create mode 100644 src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs create mode 100644 src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs create mode 100644 src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb diff --git a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs new file mode 100644 index 0000000000000..441712889e01c --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs @@ -0,0 +1,65 @@ +// 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; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.Commanding; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets; + +[ExportLanguageService(typeof(ISnippetExpansionClientFactory), LanguageNames.CSharp)] +[Shared] +internal sealed class CSharpSnippetExpansionClientFactory : AbstractSnippetExpansionClientFactory +{ + private readonly IThreadingContext _threadingContext; + private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider; + private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory; + private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; + private readonly ImmutableArray> _argumentProviders; + private readonly EditorOptionsService _editorOptionsService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpSnippetExpansionClientFactory( + IThreadingContext threadingContext, + SignatureHelpControllerProvider signatureHelpControllerProvider, + IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, + IVsEditorAdaptersFactoryService editorAdaptersFactoryService, + [ImportMany] IEnumerable> argumentProviders, + EditorOptionsService editorOptionsService) + { + _threadingContext = threadingContext; + _signatureHelpControllerProvider = signatureHelpControllerProvider; + _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory; + _editorAdaptersFactoryService = editorAdaptersFactoryService; + _argumentProviders = argumentProviders.ToImmutableArray(); + _editorOptionsService = editorOptionsService; + } + + protected override AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) + { + return new SnippetExpansionClient( + _threadingContext, + Guids.CSharpLanguageServiceId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService); + } +} diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index 3b4ac8be43bbb..7640638e1ca6d 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -5,21 +5,15 @@ #nullable disable using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; @@ -27,7 +21,6 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Editor.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; @@ -45,21 +38,27 @@ internal sealed class SnippetCommandHandler : ICommandHandler, IChainedCommandHandler { - private readonly ImmutableArray> _argumentProviders; + private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; + private readonly Lazy _expansionClientFactory; [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] public SnippetCommandHandler( IThreadingContext threadingContext, - SignatureHelpControllerProvider signatureHelpControllerProvider, - IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, IVsEditorAdaptersFactoryService editorAdaptersFactoryService, SVsServiceProvider serviceProvider, - [ImportMany] IEnumerable> argumentProviders, - EditorOptionsService editorOptionsService) - : base(threadingContext, signatureHelpControllerProvider, editorCommandHandlerServiceFactory, editorAdaptersFactoryService, editorOptionsService, serviceProvider) + EditorOptionsService editorOptionsService, + Lazy workspace) + : base(threadingContext, editorOptionsService, serviceProvider) { - _argumentProviders = argumentProviders.ToImmutableArray(); + _editorAdaptersFactoryService = editorAdaptersFactoryService; + _expansionClientFactory = new Lazy( + () => + { + return workspace.Value.Services + .GetLanguageServices(LanguageNames.CSharp) + .GetRequiredService(); + }); } public bool ExecuteCommand(SurroundWithCommandArgs args, CommandExecutionContext context) @@ -115,26 +114,8 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, nextCommandHandler(); } - protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) - { - if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) - { - expansionClient = new SnippetExpansionClient( - ThreadingContext, - Guids.CSharpLanguageServiceId, - textView, - subjectBuffer, - SignatureHelpControllerProvider, - EditorCommandHandlerServiceFactory, - EditorAdaptersFactoryService, - _argumentProviders, - EditorOptionsService); - - textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); - } - - return expansionClient; - } + protected override ISnippetExpansionClientFactory GetSnippetExpansionClientFactory() + => _expansionClientFactory.Value; protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false) { @@ -144,8 +125,8 @@ protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer sub } expansionManager.InvokeInsertionUI( - EditorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClient(textView, subjectBuffer), + _editorAdaptersFactoryService.GetViewAdapter(textView), + GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer), Guids.CSharpLanguageServiceId, bstrTypes: surroundWith ? ["SurroundsWith"] : ["Expansion", "SurroundsWith"], iCountTypes: surroundWith ? 1 : 2, diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs index c2ca6270624a9..ac4085fa5f5cf 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs @@ -7,9 +7,7 @@ using System; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; @@ -17,7 +15,6 @@ using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; -using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -38,31 +35,22 @@ internal abstract class AbstractSnippetCommandHandler : ICommandHandler, IChainedCommandHandler { - protected readonly SignatureHelpControllerProvider SignatureHelpControllerProvider; - protected readonly IEditorCommandHandlerServiceFactory EditorCommandHandlerServiceFactory; - protected readonly IVsEditorAdaptersFactoryService EditorAdaptersFactoryService; - protected readonly EditorOptionsService EditorOptionsService; - protected readonly SVsServiceProvider ServiceProvider; + private readonly EditorOptionsService _editorOptionsService; + private readonly SVsServiceProvider _serviceProvider; public string DisplayName => FeaturesResources.Snippets; public AbstractSnippetCommandHandler( IThreadingContext threadingContext, - SignatureHelpControllerProvider signatureHelpControllerProvider, - IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, - IVsEditorAdaptersFactoryService editorAdaptersFactoryService, EditorOptionsService editorOptionsService, SVsServiceProvider serviceProvider) : base(threadingContext) { - SignatureHelpControllerProvider = signatureHelpControllerProvider; - EditorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory; - EditorAdaptersFactoryService = editorAdaptersFactoryService; - EditorOptionsService = editorOptionsService; - ServiceProvider = serviceProvider; + _editorOptionsService = editorOptionsService; + _serviceProvider = serviceProvider; } - protected abstract AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); + protected abstract ISnippetExpansionClientFactory GetSnippetExpansionClientFactory(); protected abstract bool IsSnippetExpansionContext(Document document, int startPosition, CancellationToken cancellationToken); protected abstract bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false); @@ -299,12 +287,12 @@ protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuff return false; } - return GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(span.Value.Start, span.Value.End, cancellationToken); + return GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(span.Value.Start, span.Value.End, cancellationToken); } protected bool TryGetExpansionManager(out IVsExpansionManager expansionManager) { - var textManager = (IVsTextManager2)ServiceProvider.GetService(typeof(SVsTextManager)); + var textManager = (IVsTextManager2)_serviceProvider.GetService(typeof(SVsTextManager)); if (textManager == null) { expansionManager = null; @@ -323,7 +311,7 @@ protected bool AreSnippetsEnabled(EditorCommandArgs args) return false; } - return EditorOptionsService.GlobalOptions.GetOption(SnippetsOptionsStorage.Snippets) && + return _editorOptionsService.GlobalOptions.GetOption(SnippetsOptionsStorage.Snippets) && // TODO (https://github.com/dotnet/roslyn/issues/5107): enable in interactive !(Workspace.TryGetWorkspace(args.SubjectBuffer.AsTextContainer(), out var workspace) && workspace.Kind == WorkspaceKind.Interactive); } diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs new file mode 100644 index 0000000000000..7173a935b8fb4 --- /dev/null +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs @@ -0,0 +1,24 @@ +// 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 Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; + +internal abstract class AbstractSnippetExpansionClientFactory : ISnippetExpansionClientFactory +{ + protected abstract AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); + + public AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) + { + if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) + { + expansionClient = CreateSnippetExpansionClient(textView, subjectBuffer); + textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); + } + + return expansionClient; + } +} diff --git a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs new file mode 100644 index 0000000000000..df826b00d4fde --- /dev/null +++ b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs @@ -0,0 +1,14 @@ +// 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 Microsoft.CodeAnalysis.Host; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; + +internal interface ISnippetExpansionClientFactory : ILanguageService +{ + AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); +} diff --git a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb index a9654193c0246..7e71764e08ffa 100644 --- a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb @@ -2,20 +2,14 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport -Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.CSharp.Formatting -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities -Imports Microsoft.VisualStudio.LanguageServices.CSharp.Snippets +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Projection Imports Roslyn.Test.Utilities @@ -321,16 +315,8 @@ using G= H.I; editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, tabSize) editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, tabSize) - Dim snippetExpansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.CSharpLanguageServiceId, - document.GetTextView(), - textBuffer, - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - editorAdaptersFactoryService:=Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - editorOptionsService) + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient(document.GetTextView(), textBuffer) SnippetExpansionClientTestsHelper.TestFormattingAndCaretPosition(snippetExpansionClient, document, expectedResult, tabSize * 3) End Using @@ -345,16 +331,10 @@ using G= H.I; {subjectBufferDocument}, options:=ProjectionBufferOptions.WritableLiteralSpans) - Dim snippetExpansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.CSharpLanguageServiceId, + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient( surfaceBufferDocument.GetTextView(), - subjectBufferDocument.GetTextBuffer(), - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - editorAdaptersFactoryService:=Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - workspace.GetService(Of EditorOptionsService)()) + subjectBufferDocument.GetTextBuffer()) SnippetExpansionClientTestsHelper.TestProjectionBuffer(snippetExpansionClient, surfaceBufferDocument, expectedSurfaceBuffer) End Using @@ -388,16 +368,10 @@ using G= H.I; Next Using workspace = EditorTestWorkspace.CreateCSharp(originalCode) - Dim expansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.VisualBasicDebuggerLanguageId, + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( workspace.Documents.Single().GetTextView(), - workspace.Documents.Single().GetTextBuffer(), - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - editorAdaptersFactoryService:=Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - workspace.GetService(Of EditorOptionsService)()) + workspace.Documents.Single().GetTextBuffer()) Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() Dim addImportOptions = New AddImportPlacementOptions() With diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index 744ce08193d6f..7b4f8fb80cdbb 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -8,8 +8,6 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp -Imports Microsoft.CodeAnalysis.Editor.Shared.Options Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense @@ -24,10 +22,8 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Editor.Commanding Imports Microsoft.VisualStudio.TextManager.Interop Imports Moq -Imports MSXML Imports Roslyn.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets @@ -55,20 +51,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets SnippetCommandHandler = If(languageName = LanguageNames.CSharp, DirectCast(New CSharp.Snippets.SnippetCommandHandler( Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Workspace.ExportProvider.GetExportedValue(Of SignatureHelpControllerProvider)(), - Workspace.ExportProvider.GetExportedValue(Of IEditorCommandHandlerServiceFactory)(), Workspace.ExportProvider.GetExportedValue(Of IVsEditorAdaptersFactoryService)(), mockSVsServiceProvider.Object, - Workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)(), - editorOptionsService), AbstractSnippetCommandHandler), + editorOptionsService, + Workspace.ExportProvider.GetExport(Of VisualStudioWorkspace)), AbstractSnippetCommandHandler), New VisualBasic.Snippets.SnippetCommandHandler( Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Workspace.ExportProvider.GetExportedValue(Of SignatureHelpControllerProvider)(), - Workspace.ExportProvider.GetExportedValue(Of IEditorCommandHandlerServiceFactory)(), Workspace.ExportProvider.GetExportedValue(Of IVsEditorAdaptersFactoryService)(), mockSVsServiceProvider.Object, - Workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)(), - editorOptionsService)) + editorOptionsService, + Workspace.ExportProvider.GetExport(Of VisualStudioWorkspace))) SnippetExpansionClient = New MockSnippetExpansionClient( Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), diff --git a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb index c62c9483098db..0e6bca1c4aee6 100644 --- a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb @@ -2,20 +2,14 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport -Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Formatting -Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Projection Imports Roslyn.Test.Utilities @@ -362,16 +356,8 @@ End Class editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, tabSize) editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, tabSize) - Dim snippetExpansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.CSharpLanguageServiceId, - document.GetTextView(), - textBuffer, - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - optionsService) + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient(document.GetTextView(), textBuffer) SnippetExpansionClientTestsHelper.TestFormattingAndCaretPosition(snippetExpansionClient, document, expectedResult, tabSize * 3) End Using @@ -406,16 +392,10 @@ End Class Next Using workspace = EditorTestWorkspace.Create(workspaceXml) - Dim expansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.VisualBasicDebuggerLanguageId, + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( workspace.Documents.Single().GetTextView(), - workspace.Documents.Single().GetTextBuffer(), - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - workspace.GetService(Of EditorOptionsService)()) + workspace.Documents.Single().GetTextBuffer()) Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() @@ -448,16 +428,10 @@ End Class {subjectBufferDocument}, options:=ProjectionBufferOptions.WritableLiteralSpans) - Dim snippetExpansionClient = New SnippetExpansionClient( - workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Guids.CSharpLanguageServiceId, + Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient( surfaceBufferDocument.GetTextView(), - subjectBufferDocument.GetTextBuffer(), - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - Nothing, - workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(), - workspace.GetService(Of EditorOptionsService)()) + subjectBufferDocument.GetTextBuffer()) SnippetExpansionClientTestsHelper.TestProjectionBuffer(snippetExpansionClient, surfaceBufferDocument, expectedSurfaceBuffer) End Using diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb index 362c5d40db877..7546f9248dea9 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb @@ -2,17 +2,13 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.ComponentModel.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities -Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.Text @@ -24,7 +20,6 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Editor.Commanding Imports Microsoft.VisualStudio.TextManager.Interop Imports Microsoft.VisualStudio.Utilities @@ -38,20 +33,25 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Friend NotInheritable Class SnippetCommandHandler Inherits AbstractSnippetCommandHandler - Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) + Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService + Private ReadOnly _expansionClientFactory As Lazy(Of ISnippetExpansionClientFactory) Public Sub New( threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, serviceProvider As SVsServiceProvider, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) - MyBase.New(threadingContext, signatureHelpControllerProvider, editorCommandHandlerServiceFactory, editorAdaptersFactoryService, editorOptionsService, serviceProvider) - _argumentProviders = argumentProviders.ToImmutableArray() + editorOptionsService As EditorOptionsService, + workspace As Lazy(Of VisualStudioWorkspace)) + MyBase.New(threadingContext, editorOptionsService, serviceProvider) + _editorAdaptersFactoryService = editorAdaptersFactoryService + _expansionClientFactory = New Lazy(Of ISnippetExpansionClientFactory)( + Function() + Return workspace.Value.Services _ + .GetLanguageServices(LanguageNames.VisualBasic) _ + .GetRequiredService(Of ISnippetExpansionClientFactory)() + End Function) End Sub Protected Overrides Function IsSnippetExpansionContext(document As Document, startPosition As Integer, cancellationToken As CancellationToken) As Boolean @@ -62,15 +62,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Not syntaxTree.FindTokenOnRightOfPosition(startPosition, cancellationToken).HasAncestor(Of XmlElementSyntax)() End Function - Protected Overrides Function GetSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient - Return SnippetExpansionClient.GetSnippetExpansionClient(ThreadingContext, - textView, - subjectBuffer, - SignatureHelpControllerProvider, - EditorCommandHandlerServiceFactory, - EditorAdaptersFactoryService, - _argumentProviders, - EditorOptionsService) + Protected Overrides Function GetSnippetExpansionClientFactory() As ISnippetExpansionClientFactory + Return _expansionClientFactory.Value End Function Protected Overrides Function TryInvokeInsertionUI(textView As ITextView, subjectBuffer As ITextBuffer, Optional surroundWith As Boolean = False) As Boolean @@ -82,8 +75,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets End If expansionManager.InvokeInsertionUI( - EditorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClient(textView, subjectBuffer), + _editorAdaptersFactoryService.GetViewAdapter(textView), + GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer), Guids.VisualBasicDebuggerLanguageId, bstrTypes:=Nothing, iCountTypes:=0, diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb index 31a6f0e902c2e..18f9136f3727c 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb @@ -7,23 +7,18 @@ Imports System.ComponentModel.Composition Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Editor -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.Snippets Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.CodeAnalysis.VisualBasic.Extensions Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery -Imports Microsoft.VisualStudio.Editor +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Editor.Commanding Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets @@ -31,29 +26,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Inherits LSPCompletionProvider Implements ICustomCommitCompletionProvider - Private ReadOnly _threadingContext As IThreadingContext - Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider - Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory - Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService - Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) - Private ReadOnly _editorOptionsService As EditorOptionsService + Private ReadOnly _expansionClientFactory As Lazy(Of ISnippetExpansionClientFactory) - Public Sub New( - threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) - - _threadingContext = threadingContext - _signatureHelpControllerProvider = signatureHelpControllerProvider - _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory - _editorAdaptersFactoryService = editorAdaptersFactoryService - _argumentProviders = argumentProviders.ToImmutableArray() - _editorOptionsService = editorOptionsService + Public Sub New(workspace As Lazy(Of VisualStudioWorkspace)) + _expansionClientFactory = New Lazy(Of ISnippetExpansionClientFactory)( + Function() + Return workspace.Value.Services _ + .GetLanguageServices(LanguageNames.VisualBasic) _ + .GetRequiredService(Of ISnippetExpansionClientFactory)() + End Function) End Sub Friend Overrides ReadOnly Property Language As String @@ -123,15 +106,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets subjectBuffer As ITextBuffer, triggerSnapshot As ITextSnapshot, commitChar As Char?) Implements ICustomCommitCompletionProvider.Commit - Dim snippetClient = SnippetExpansionClient.GetSnippetExpansionClient( - _threadingContext, - textView, - subjectBuffer, - _signatureHelpControllerProvider, - _editorCommandHandlerServiceFactory, - _editorAdaptersFactoryService, - _argumentProviders, - _editorOptionsService) + Dim snippetClient = _expansionClientFactory.Value.GetSnippetExpansionClient(textView, subjectBuffer) Dim trackingSpan = triggerSnapshot.CreateTrackingSpan(completionItem.Span.ToSpan(), SpanTrackingMode.EdgeInclusive) Dim currentSpan = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot) diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb index ad062410bd692..69f9585159d37 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb @@ -49,35 +49,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets editorOptionsService) End Sub - Public Shared Function GetSnippetExpansionClient( - threadingContext As IThreadingContext, - textView As ITextView, - subjectBuffer As ITextBuffer, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) As AbstractSnippetExpansionClient - - Dim expansionClient As AbstractSnippetExpansionClient = Nothing - - If Not textView.Properties.TryGetProperty(GetType(AbstractSnippetExpansionClient), expansionClient) Then - expansionClient = New SnippetExpansionClient( - threadingContext, - Guids.VisualBasicDebuggerLanguageId, - textView, - subjectBuffer, - signatureHelpControllerProvider, - editorCommandHandlerServiceFactory, - editorAdaptersFactoryService, - argumentProviders, - editorOptionsService) - textView.Properties.AddProperty(GetType(AbstractSnippetExpansionClient), expansionClient) - End If - - Return expansionClient - End Function - Protected Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan() As ITrackingSpan Dim endSpanInSurfaceBuffer(1) As VsTextSpan If ExpansionSession.GetEndSpan(endSpanInSurfaceBuffer) <> VSConstants.S_OK Then diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb new file mode 100644 index 0000000000000..02dece651fc40 --- /dev/null +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb @@ -0,0 +1,65 @@ +' 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. + +Imports System.Collections.Immutable +Imports System.Composition +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Completion +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.VisualStudio.Editor +Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +Imports Microsoft.VisualStudio.Text +Imports Microsoft.VisualStudio.Text.Editor +Imports Microsoft.VisualStudio.Text.Editor.Commanding + +Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets + + + <[Shared]> + Friend NotInheritable Class VisualBasicSnippetExpansionClientFactory + Inherits AbstractSnippetExpansionClientFactory + + Private ReadOnly _threadingContext As IThreadingContext + Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider + Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory + Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService + Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) + Private ReadOnly _editorOptionsService As EditorOptionsService + + + + Public Sub New( + threadingContext As IThreadingContext, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), + editorOptionsService As EditorOptionsService) + + _threadingContext = threadingContext + _signatureHelpControllerProvider = signatureHelpControllerProvider + _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory + _editorAdaptersFactoryService = editorAdaptersFactoryService + _argumentProviders = argumentProviders.ToImmutableArray() + _editorOptionsService = editorOptionsService + End Sub + + Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient + Return New SnippetExpansionClient( + _threadingContext, + Guids.VisualBasicDebuggerLanguageId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService) + End Function + End Class + +End Namespace From fc0cda01fe244189c18ed9416a6863aefb314cf1 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 22 Jan 2024 11:34:21 -0600 Subject: [PATCH 2/5] Simplify dependencies in AbstractSnippetCommandHandler --- .../OverrideCompletionProviderTests.cs | 12 +- .../ICustomCommitCompletionProvider.cs | 4 +- .../AsyncCompletion/CommitManager.cs | 2 +- .../AbstractCompletionProviderTests.cs | 3 +- .../TestUtilities2/Intellisense/TestState.vb | 2 +- .../Impl/Snippets/SnippetCommandHandler.cs | 31 ++- .../Snippets/AbstractSnippetCommandHandler.cs | 15 +- .../CSharpSnippetExpansionClientTests.vb | 6 +- .../Core/Test/Snippets/SnippetTestState.vb | 196 ++++++++++++++---- .../VisualBasicSnippetExpansionClientTests.vb | 6 +- .../Impl/Snippets/SnippetCommandHandler.vb | 30 +-- .../Snippets/SnippetCompletionProvider.vb | 14 +- 12 files changed, 204 insertions(+), 117 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 36a12b89f69f1..45d25f05dbd13 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -2490,8 +2490,8 @@ public override void set_Bar(int bay, int value) if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { - var textView = testWorkspace.GetTestDocument(documentId)!.GetTextView(); - customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); + var textView = testDocument.GetTextView(); + customCommitCompletionProvider.Commit(completionItem, document, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); var actualCodeAfterCommit = textView.TextBuffer.CurrentSnapshot.AsText().ToString(); var caretPosition = textView.Caret.Position.BufferPosition.Position; MarkupTestFile.GetPosition(csharpFileAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); @@ -2747,8 +2747,8 @@ public override bool Equals(object obj) if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { - var textView = testWorkspace.GetTestDocument(documentId)!.GetTextView(); - customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); + var textView = testDocument.GetTextView(); + customCommitCompletionProvider.Commit(completionItem, document, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); var actualCodeAfterCommit = textView.TextBuffer.CurrentSnapshot.AsText().ToString(); var caretPosition = textView.Caret.Position.BufferPosition.Position; MarkupTestFile.GetPosition(csharpFileAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); @@ -2803,8 +2803,8 @@ public override bool Equals(object obj) if (service.GetProvider(completionItem, document.Project) is ICustomCommitCompletionProvider customCommitCompletionProvider) { - var textView = testWorkspace.GetTestDocument(documentId)!.GetTextView(); - customCommitCompletionProvider.Commit(completionItem, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); + var textView = testDocument.GetTextView(); + customCommitCompletionProvider.Commit(completionItem, document, textView, textView.TextBuffer, textView.TextSnapshot, '\t'); var actualCodeAfterCommit = textView.TextBuffer.CurrentSnapshot.AsText().ToString(); var caretPosition = textView.Caret.Position.BufferPosition.Position; MarkupTestFile.GetPosition(csharpFileAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); diff --git a/src/EditorFeatures/Core/Extensibility/Completion/ICustomCommitCompletionProvider.cs b/src/EditorFeatures/Core/Extensibility/Completion/ICustomCommitCompletionProvider.cs index f9839e39bd277..9711a7b613d43 100644 --- a/src/EditorFeatures/Core/Extensibility/Completion/ICustomCommitCompletionProvider.cs +++ b/src/EditorFeatures/Core/Extensibility/Completion/ICustomCommitCompletionProvider.cs @@ -2,8 +2,6 @@ // 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 Microsoft.CodeAnalysis.Completion; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -16,6 +14,6 @@ namespace Microsoft.CodeAnalysis.Editor /// internal interface ICustomCommitCompletionProvider { - void Commit(CompletionItem completionItem, ITextView textView, ITextBuffer subjectBuffer, ITextSnapshot triggerSnapshot, char? commitChar); + void Commit(CompletionItem completionItem, Document document, ITextView textView, ITextBuffer subjectBuffer, ITextSnapshot triggerSnapshot, char? commitChar); } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs index 0c8f84d08feb8..0bdf181116093 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs @@ -243,7 +243,7 @@ private AsyncCompletionData.CommitResult Commit( var provider = completionService.GetProvider(roslynItem, document.Project); if (provider is ICustomCommitCompletionProvider customCommitProvider) { - customCommitProvider.Commit(roslynItem, view, subjectBuffer, triggerSnapshot, commitCharacter); + customCommitProvider.Commit(roslynItem, document, view, subjectBuffer, triggerSnapshot, commitCharacter); return new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.None); } diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 9182640df9684..20388311b53bf 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -541,10 +541,11 @@ private void VerifyCustomCommitWorker( // textview is created lazily, so need to access it before making // changes to document, so the cursor position is tracked correctly. + var document = workspace.CurrentSolution.GetRequiredDocument(workspaceFixture.Target.CurrentDocument.Id); var textView = workspaceFixture.Target.CurrentDocument.GetTextView(); var textBuffer = workspaceFixture.Target.CurrentDocument.GetTextBuffer(); - customCommitCompletionProvider.Commit(completionItem, textView, textBuffer, textView.TextSnapshot, commitChar); + customCommitCompletionProvider.Commit(completionItem, document, textView, textBuffer, textView.TextSnapshot, commitChar); var actualCodeAfterCommit = textBuffer.CurrentSnapshot.AsText().ToString(); var caretPosition = textView.Caret.Position.BufferPosition.Position; diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb index 073d3e22b342d..9a550da860a3b 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -373,7 +373,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Public Async Function AssertCompletionItemsContainAll(ParamArray displayText As String()) As Task Await WaitForAsynchronousOperationsAsync() Dim items = GetCompletionItems() - Assert.True(displayText.All(Function(v) items.Any(Function(i) i.DisplayText = v))) + Assert.All(displayText, Sub(v) Assert.Contains(v, items.Select(Function(i) i.DisplayText))) End Function Public Async Function AssertCompletionItemsContain(displayText As String, displayTextSuffix As String) As Task diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index 7640638e1ca6d..8f9e79f0f584d 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -6,22 +6,23 @@ using System; using System.ComponentModel.Composition; -using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets @@ -39,26 +40,17 @@ internal sealed class SnippetCommandHandler : IChainedCommandHandler { private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; - private readonly Lazy _expansionClientFactory; [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public SnippetCommandHandler( IThreadingContext threadingContext, IVsEditorAdaptersFactoryService editorAdaptersFactoryService, - SVsServiceProvider serviceProvider, - EditorOptionsService editorOptionsService, - Lazy workspace) - : base(threadingContext, editorOptionsService, serviceProvider) + IVsService textManager, + EditorOptionsService editorOptionsService) + : base(threadingContext, editorOptionsService, textManager) { _editorAdaptersFactoryService = editorAdaptersFactoryService; - _expansionClientFactory = new Lazy( - () => - { - return workspace.Value.Services - .GetLanguageServices(LanguageNames.CSharp) - .GetRequiredService(); - }); } public bool ExecuteCommand(SurroundWithCommandArgs args, CommandExecutionContext context) @@ -114,9 +106,6 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, nextCommandHandler(); } - protected override ISnippetExpansionClientFactory GetSnippetExpansionClientFactory() - => _expansionClientFactory.Value; - protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false) { if (!TryGetExpansionManager(out var expansionManager)) @@ -124,9 +113,13 @@ protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer sub return false; } + var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return false; + expansionManager.InvokeInsertionUI( _editorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer), + GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer), Guids.CSharpLanguageServiceId, bstrTypes: surroundWith ? ["SurroundsWith"] : ["Expansion", "SurroundsWith"], iCountTypes: surroundWith ? 1 : 2, diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs index ac4085fa5f5cf..9d4f0b9f7eb14 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Snippets; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; @@ -36,21 +35,23 @@ internal abstract class AbstractSnippetCommandHandler : IChainedCommandHandler { private readonly EditorOptionsService _editorOptionsService; - private readonly SVsServiceProvider _serviceProvider; + private readonly IVsService _textManager; public string DisplayName => FeaturesResources.Snippets; public AbstractSnippetCommandHandler( IThreadingContext threadingContext, EditorOptionsService editorOptionsService, - SVsServiceProvider serviceProvider) + IVsService textManager) : base(threadingContext) { _editorOptionsService = editorOptionsService; - _serviceProvider = serviceProvider; + _textManager = textManager; } - protected abstract ISnippetExpansionClientFactory GetSnippetExpansionClientFactory(); + protected ISnippetExpansionClientFactory GetSnippetExpansionClientFactory(Document document) + => document.GetRequiredLanguageService(); + protected abstract bool IsSnippetExpansionContext(Document document, int startPosition, CancellationToken cancellationToken); protected abstract bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false); @@ -287,12 +288,12 @@ protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuff return false; } - return GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(span.Value.Start, span.Value.End, cancellationToken); + return GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(span.Value.Start, span.Value.End, cancellationToken); } protected bool TryGetExpansionManager(out IVsExpansionManager expansionManager) { - var textManager = (IVsTextManager2)_serviceProvider.GetService(typeof(SVsTextManager)); + var textManager = ThreadingContext.JoinableTaskFactory.Run(() => _textManager.GetValueOrNullAsync(CancellationToken.None)); if (textManager == null) { expansionManager = null; diff --git a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb index 7e71764e08ffa..1c7fc8fb71791 100644 --- a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb @@ -305,7 +305,7 @@ using G= H.I; } } - Using workspace = EditorTestWorkspace.Create(workspaceXml, openDocuments:=False) + Using workspace = EditorTestWorkspace.Create(workspaceXml, openDocuments:=False, composition:=VisualStudioTestCompositions.LanguageServices) Dim document = workspace.Documents.Single() Dim textBuffer = document.GetTextBuffer() Dim editorOptionsService = workspace.GetService(Of EditorOptionsService)() @@ -323,7 +323,7 @@ using G= H.I; End Sub Public Sub TestProjectionFormatting(workspaceXmlWithSubjectBufferDocument As XElement, surfaceBufferDocumentXml As XElement, expectedSurfaceBuffer As XElement) - Using workspace = EditorTestWorkspace.Create(workspaceXmlWithSubjectBufferDocument) + Using workspace = EditorTestWorkspace.Create(workspaceXmlWithSubjectBufferDocument, composition:=VisualStudioTestCompositions.LanguageServices) Dim subjectBufferDocument = workspace.Documents.Single() Dim surfaceBufferDocument = workspace.CreateProjectionBufferDocument( @@ -367,7 +367,7 @@ using G= H.I; ) Next - Using workspace = EditorTestWorkspace.CreateCSharp(originalCode) + Using workspace = EditorTestWorkspace.CreateCSharp(originalCode, composition:=VisualStudioTestCompositions.LanguageServices) Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( workspace.Documents.Single().GetTextView(), diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index 7b4f8fb80cdbb..865c3d1a290c0 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -3,11 +3,13 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense @@ -16,14 +18,13 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Snippets +Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Editor Imports Microsoft.VisualStudio.Language.Intellisense Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets -Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.TextManager.Interop -Imports Moq +Imports Microsoft.VisualStudio.Text.Editor.Commanding Imports Roslyn.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets @@ -34,44 +35,65 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets ' Remove the default completion presenters to prevent them from conflicting with the test one ' that we are adding. MyBase.New(workspaceElement, - extraExportedTypes:={GetType(TestSignatureHelpPresenter), GetType(IntelliSenseTestState), GetType(MockCompletionPresenterProvider), GetType(StubVsEditorAdaptersFactoryService)}.Concat(If(extraParts, {})).ToList(), + extraExportedTypes:=AugmentExtraTypesForSnippetTests(extraParts), workspaceKind:=workspaceKind, - excludedTypes:={GetType(IIntelliSensePresenter(Of ISignatureHelpPresenterSession, ISignatureHelpSession)), GetType(FormatCommandHandler)}.Concat(If(excludedTypes, {})).ToList(), + excludedTypes:=AugmentExcludedTypesForSnippetTests(excludedTypes), includeFormatCommandHandler:=False) Workspace.GlobalOptions.SetGlobalOption(SnippetsOptionsStorage.Snippets, True) - Dim mockSVsServiceProvider = New Mock(Of SVsServiceProvider)(MockBehavior.Strict) - mockSVsServiceProvider.Setup(Function(s) s.GetService(GetType(SVsTextManager))).Returns(Nothing) + Dim snippetCommandHandler As ICommandHandler + If languageName = LanguageNames.CSharp Then + snippetCommandHandler = Workspace.ExportProvider.GetExportedValues(Of ICommandHandler)().Single( + Function(commandHandler) + Return TryCast(commandHandler, CSharp.Snippets.SnippetCommandHandler) IsNot Nothing + End Function) + Else + snippetCommandHandler = Workspace.ExportProvider.GetExportedValues(Of ICommandHandler)().Single( + Function(commandHandler) + Return TryCast(commandHandler, VisualBasic.Snippets.SnippetCommandHandler) IsNot Nothing + End Function) + End If + + Me.SnippetCommandHandler = DirectCast(snippetCommandHandler, AbstractSnippetCommandHandler) - Dim globalOptions = Workspace.GetService(Of IGlobalOptionService) Dim editorOptionsService = Workspace.GetService(Of EditorOptionsService)() - Dim indentationManager = Workspace.GetService(Of IIndentationManagerService)() - - SnippetCommandHandler = If(languageName = LanguageNames.CSharp, - DirectCast(New CSharp.Snippets.SnippetCommandHandler( - Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Workspace.ExportProvider.GetExportedValue(Of IVsEditorAdaptersFactoryService)(), - mockSVsServiceProvider.Object, - editorOptionsService, - Workspace.ExportProvider.GetExport(Of VisualStudioWorkspace)), AbstractSnippetCommandHandler), - New VisualBasic.Snippets.SnippetCommandHandler( - Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - Workspace.ExportProvider.GetExportedValue(Of IVsEditorAdaptersFactoryService)(), - mockSVsServiceProvider.Object, - editorOptionsService, - Workspace.ExportProvider.GetExport(Of VisualStudioWorkspace))) - - SnippetExpansionClient = New MockSnippetExpansionClient( - Workspace.ExportProvider.GetExportedValue(Of IThreadingContext), - startActiveSession, - If(languageName Is LanguageNames.CSharp, Guids.CSharpLanguageServiceId, Guids.VisualBasicLanguageServiceId), - TextView, - SubjectBuffer, - editorOptionsService) - TextView.Properties.AddProperty(GetType(AbstractSnippetExpansionClient), SnippetExpansionClient) + Dim snippetExpansionClientFactory = Workspace.Services.GetLanguageServices(languageName).GetRequiredService(Of ISnippetExpansionClientFactory)() + SnippetExpansionClient = CType(snippetExpansionClientFactory.GetSnippetExpansionClient(TextView, SubjectBuffer), MockSnippetExpansionClient) + + If startActiveSession Then + SnippetExpansionClient.TryHandleTabReturnValue = True + SnippetExpansionClient.TryHandleBackTabReturnValue = True + SnippetExpansionClient.TryHandleEscapeReturnValue = True + SnippetExpansionClient.TryHandleReturnReturnValue = True + End If End Sub + Private Shared Function AugmentExtraTypesForSnippetTests(extraParts As IEnumerable(Of Type)) As IEnumerable(Of Type) + Return If(extraParts, Type.EmptyTypes).Concat( + { + GetType(TestSignatureHelpPresenter), + GetType(IntelliSenseTestState), + GetType(MockCompletionPresenterProvider), + GetType(StubVsEditorAdaptersFactoryService), + GetType(CSharp.Snippets.SnippetCommandHandler), + GetType(MockCSharpSnippetExpansionClientFactory), + GetType(VisualBasic.Snippets.SnippetCommandHandler), + GetType(MockVisualBasicSnippetExpansionClientFactory), + GetType(MockServiceProvider), + GetType(StubVsServiceExporter(Of )), + GetType(StubVsServiceExporter(Of ,)) + }) + End Function + + Private Shared Function AugmentExcludedTypesForSnippetTests(excludedTypes As IEnumerable(Of Type)) As IEnumerable(Of Type) + Return If(excludedTypes, Type.EmptyTypes).Concat( + { + GetType(IIntelliSensePresenter(Of ISignatureHelpPresenterSession, ISignatureHelpSession)), + GetType(FormatCommandHandler) + }) + End Function + Public ReadOnly SnippetCommandHandler As AbstractSnippetCommandHandler Public Property SnippetExpansionClient As MockSnippetExpansionClient @@ -141,31 +163,117 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Sub End Class + + <[Shared]> + + Friend Class MockCSharpSnippetExpansionClientFactory + Inherits AbstractSnippetExpansionClientFactory + + Private ReadOnly _threadingContext As IThreadingContext + Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider + Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory + Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService + Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) + Private ReadOnly _editorOptionsService As EditorOptionsService + + + + Public Sub New( + threadingContext As IThreadingContext, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), + editorOptionsService As EditorOptionsService) + + _threadingContext = threadingContext + _signatureHelpControllerProvider = signatureHelpControllerProvider + _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory + _editorAdaptersFactoryService = editorAdaptersFactoryService + _argumentProviders = argumentProviders.ToImmutableArray() + _editorOptionsService = editorOptionsService + End Sub + + Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient + Return New MockSnippetExpansionClient( + _threadingContext, + Guids.CSharpLanguageServiceId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService) + End Function + End Class + + + <[Shared]> + + Friend Class MockVisualBasicSnippetExpansionClientFactory + Inherits AbstractSnippetExpansionClientFactory + + Private ReadOnly _threadingContext As IThreadingContext + Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider + Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory + Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService + Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) + Private ReadOnly _editorOptionsService As EditorOptionsService + + + + Public Sub New( + threadingContext As IThreadingContext, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), + editorOptionsService As EditorOptionsService) + + _threadingContext = threadingContext + _signatureHelpControllerProvider = signatureHelpControllerProvider + _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory + _editorAdaptersFactoryService = editorAdaptersFactoryService + _argumentProviders = argumentProviders.ToImmutableArray() + _editorOptionsService = editorOptionsService + End Sub + + Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient + Return New MockSnippetExpansionClient( + _threadingContext, + Guids.VisualBasicDebuggerLanguageId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService) + End Function + End Class + Friend Class MockSnippetExpansionClient Inherits AbstractSnippetExpansionClient Public Sub New(threadingContext As IThreadingContext, - startActiveSession As Boolean, languageServiceGuid As Guid, textView As ITextView, subjectBuffer As ITextBuffer, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), editorOptionsService As EditorOptionsService) MyBase.New(threadingContext, languageServiceGuid, textView, subjectBuffer, - signatureHelpControllerProvider:=Nothing, - editorCommandHandlerServiceFactory:=Nothing, - Nothing, - ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)).Empty, + signatureHelpControllerProvider, + editorCommandHandlerServiceFactory, + editorAdaptersFactoryService, + argumentProviders, editorOptionsService) - - If startActiveSession Then - TryHandleTabReturnValue = True - TryHandleBackTabReturnValue = True - TryHandleEscapeReturnValue = True - TryHandleReturnReturnValue = True - End If End Sub Public Property TryHandleReturnCalled As Boolean diff --git a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb index 0e6bca1c4aee6..c978548a7ec00 100644 --- a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb @@ -346,7 +346,7 @@ End Class End Sub End Class - Using workspace = EditorTestWorkspace.Create(workspaceXml, openDocuments:=False) + Using workspace = EditorTestWorkspace.Create(workspaceXml, openDocuments:=False, composition:=VisualStudioTestCompositions.LanguageServices) Dim document = workspace.Documents.Single() Dim optionsService = workspace.GetService(Of EditorOptionsService)() Dim textBuffer = document.GetTextBuffer() @@ -391,7 +391,7 @@ End Class ) Next - Using workspace = EditorTestWorkspace.Create(workspaceXml) + Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( workspace.Documents.Single().GetTextView(), @@ -420,7 +420,7 @@ End Class End Function Public Sub TestFormatting(workspaceXmlWithSubjectBufferDocument As XElement, surfaceBufferDocumentXml As XElement, expectedSurfaceBuffer As XElement) - Using workspace = EditorTestWorkspace.Create(workspaceXmlWithSubjectBufferDocument) + Using workspace = EditorTestWorkspace.Create(workspaceXmlWithSubjectBufferDocument, composition:=VisualStudioTestCompositions.LanguageServices) Dim subjectBufferDocument = workspace.Documents.Single() Dim surfaceBufferDocument = workspace.CreateProjectionBufferDocument( diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb index 7546f9248dea9..adfa5ece3f079 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb @@ -3,12 +3,12 @@ ' See the LICENSE file in the project root for more information. Imports System.ComponentModel.Composition -Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.Text @@ -17,7 +17,6 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.VisualStudio.Editor Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets -Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.TextManager.Interop @@ -34,24 +33,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Inherits AbstractSnippetCommandHandler Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService - Private ReadOnly _expansionClientFactory As Lazy(Of ISnippetExpansionClientFactory) - + Public Sub New( threadingContext As IThreadingContext, editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - serviceProvider As SVsServiceProvider, - editorOptionsService As EditorOptionsService, - workspace As Lazy(Of VisualStudioWorkspace)) - MyBase.New(threadingContext, editorOptionsService, serviceProvider) + textManager As IVsService(Of SVsTextManager, IVsTextManager2), + editorOptionsService As EditorOptionsService) + MyBase.New(threadingContext, editorOptionsService, textManager) _editorAdaptersFactoryService = editorAdaptersFactoryService - _expansionClientFactory = New Lazy(Of ISnippetExpansionClientFactory)( - Function() - Return workspace.Value.Services _ - .GetLanguageServices(LanguageNames.VisualBasic) _ - .GetRequiredService(Of ISnippetExpansionClientFactory)() - End Function) End Sub Protected Overrides Function IsSnippetExpansionContext(document As Document, startPosition As Integer, cancellationToken As CancellationToken) As Boolean @@ -62,10 +53,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Not syntaxTree.FindTokenOnRightOfPosition(startPosition, cancellationToken).HasAncestor(Of XmlElementSyntax)() End Function - Protected Overrides Function GetSnippetExpansionClientFactory() As ISnippetExpansionClientFactory - Return _expansionClientFactory.Value - End Function - Protected Overrides Function TryInvokeInsertionUI(textView As ITextView, subjectBuffer As ITextBuffer, Optional surroundWith As Boolean = False) As Boolean Debug.Assert(Not surroundWith) @@ -74,9 +61,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Return False End If + Dim document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() + If document Is Nothing Then + Return False + End If + expansionManager.InvokeInsertionUI( _editorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClientFactory().GetSnippetExpansionClient(textView, subjectBuffer), + GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer), Guids.VisualBasicDebuggerLanguageId, bstrTypes:=Nothing, iCountTypes:=0, diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb index 18f9136f3727c..ad474d2591e5d 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb @@ -26,17 +26,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Inherits LSPCompletionProvider Implements ICustomCommitCompletionProvider - Private ReadOnly _expansionClientFactory As Lazy(Of ISnippetExpansionClientFactory) - - Public Sub New(workspace As Lazy(Of VisualStudioWorkspace)) - _expansionClientFactory = New Lazy(Of ISnippetExpansionClientFactory)( - Function() - Return workspace.Value.Services _ - .GetLanguageServices(LanguageNames.VisualBasic) _ - .GetRequiredService(Of ISnippetExpansionClientFactory)() - End Function) + Public Sub New() End Sub Friend Overrides ReadOnly Property Language As String @@ -102,11 +94,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = ImmutableHashSet(Of Char).Empty Public Sub Commit(completionItem As CompletionItem, + document As Document, textView As ITextView, subjectBuffer As ITextBuffer, triggerSnapshot As ITextSnapshot, commitChar As Char?) Implements ICustomCommitCompletionProvider.Commit - Dim snippetClient = _expansionClientFactory.Value.GetSnippetExpansionClient(textView, subjectBuffer) + Dim expansionClientFactory = document.GetRequiredLanguageService(Of ISnippetExpansionClientFactory)() + Dim snippetClient = expansionClientFactory.GetSnippetExpansionClient(textView, subjectBuffer) Dim trackingSpan = triggerSnapshot.CreateTrackingSpan(completionItem.Span.ToSpan(), SpanTrackingMode.EdgeInclusive) Dim currentSpan = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot) From 1e298dcebaed0302ba719dd164ecb1efefb3b801 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Tue, 23 Jan 2024 14:29:24 -0600 Subject: [PATCH 3/5] Updates based on code review --- ...ent.cs => CSharpSnippetExpansionClient.cs} | 4 +- .../CSharpSnippetExpansionClientFactory.cs | 43 ++++++++----------- .../AbstractSnippetExpansionClientFactory.cs | 8 +++- .../Core/Test/Snippets/SnippetTestState.vb | 26 +++++------ ...b => VisualBasicSnippetExpansionClient.vb} | 2 +- ...isualBasicSnippetExpansionClientFactory.vb | 3 +- 6 files changed, 43 insertions(+), 43 deletions(-) rename src/VisualStudio/CSharp/Impl/Snippets/{SnippetExpansionClient.cs => CSharpSnippetExpansionClient.cs} (98%) rename src/VisualStudio/VisualBasic/Impl/Snippets/{SnippetExpansionClient.vb => VisualBasicSnippetExpansionClient.vb} (99%) diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs similarity index 98% rename from src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs rename to src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs index e31f7dea9d69d..948727c4f7d3c 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs @@ -34,9 +34,9 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets { - internal sealed partial class SnippetExpansionClient : AbstractSnippetExpansionClient + internal sealed partial class CSharpSnippetExpansionClient : AbstractSnippetExpansionClient { - public SnippetExpansionClient( + public CSharpSnippetExpansionClient( IThreadingContext threadingContext, Guid languageServiceGuid, ITextView textView, diff --git a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs index 441712889e01c..de31ceeb02845 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs @@ -22,36 +22,27 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets; [ExportLanguageService(typeof(ISnippetExpansionClientFactory), LanguageNames.CSharp)] [Shared] -internal sealed class CSharpSnippetExpansionClientFactory : AbstractSnippetExpansionClientFactory +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpSnippetExpansionClientFactory( + IThreadingContext threadingContext, + SignatureHelpControllerProvider signatureHelpControllerProvider, + IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, + IVsEditorAdaptersFactoryService editorAdaptersFactoryService, + [ImportMany] IEnumerable> argumentProviders, + EditorOptionsService editorOptionsService) + : AbstractSnippetExpansionClientFactory(threadingContext) { - private readonly IThreadingContext _threadingContext; - private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider; - private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory; - private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; - private readonly ImmutableArray> _argumentProviders; - private readonly EditorOptionsService _editorOptionsService; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpSnippetExpansionClientFactory( - IThreadingContext threadingContext, - SignatureHelpControllerProvider signatureHelpControllerProvider, - IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, - IVsEditorAdaptersFactoryService editorAdaptersFactoryService, - [ImportMany] IEnumerable> argumentProviders, - EditorOptionsService editorOptionsService) - { - _threadingContext = threadingContext; - _signatureHelpControllerProvider = signatureHelpControllerProvider; - _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory; - _editorAdaptersFactoryService = editorAdaptersFactoryService; - _argumentProviders = argumentProviders.ToImmutableArray(); - _editorOptionsService = editorOptionsService; - } + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider = signatureHelpControllerProvider; + private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory; + private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService = editorAdaptersFactoryService; + private readonly ImmutableArray> _argumentProviders = argumentProviders.ToImmutableArray(); + private readonly EditorOptionsService _editorOptionsService = editorOptionsService; protected override AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) { - return new SnippetExpansionClient( + return new CSharpSnippetExpansionClient( _threadingContext, Guids.CSharpLanguageServiceId, textView, diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs index 7173a935b8fb4..a0feabf4da463 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs @@ -2,17 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; -internal abstract class AbstractSnippetExpansionClientFactory : ISnippetExpansionClientFactory +internal abstract class AbstractSnippetExpansionClientFactory(IThreadingContext threadingContext) : ISnippetExpansionClientFactory { + private readonly IThreadingContext _threadingContext = threadingContext; + protected abstract AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); public AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) { + Contract.ThrowIfFalse(_threadingContext.JoinableTaskContext.IsOnMainThread); + if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) { expansionClient = CreateSnippetExpansionClient(textView, subjectBuffer); diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index 865c3d1a290c0..b589954234ad0 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -179,12 +179,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Public Sub New( - threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) + threadingContext As IThreadingContext, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), + editorOptionsService As EditorOptionsService) + MyBase.New(threadingContext) _threadingContext = threadingContext _signatureHelpControllerProvider = signatureHelpControllerProvider @@ -224,12 +225,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Public Sub New( - threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) + threadingContext As IThreadingContext, + signatureHelpControllerProvider As SignatureHelpControllerProvider, + editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, + editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, + argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), + editorOptionsService As EditorOptionsService) + MyBase.New(threadingContext) _threadingContext = threadingContext _signatureHelpControllerProvider = signatureHelpControllerProvider diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb similarity index 99% rename from src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb rename to src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb index 69f9585159d37..0476db2ef9e05 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetExpansionClient.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb @@ -25,7 +25,7 @@ Imports Microsoft.VisualStudio.Text.Editor.Commanding Imports VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets - Friend NotInheritable Class SnippetExpansionClient + Friend NotInheritable Class VisualBasicSnippetExpansionClient Inherits AbstractSnippetExpansionClient Public Sub New( diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb index 02dece651fc40..3421c9945f336 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb @@ -39,6 +39,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), editorOptionsService As EditorOptionsService) + MyBase.New(threadingContext) _threadingContext = threadingContext _signatureHelpControllerProvider = signatureHelpControllerProvider @@ -49,7 +50,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets End Sub Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient - Return New SnippetExpansionClient( + Return New VisualBasicSnippetExpansionClient( _threadingContext, Guids.VisualBasicDebuggerLanguageId, textView, From 89ff16257adbaa7d6a9c4d081dc675f24fdd5ab4 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 24 Jan 2024 11:01:55 -0600 Subject: [PATCH 4/5] Updates based on code review --- .../Core/Test/Snippets/SnippetTestState.vb | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index b589954234ad0..0b6356759422f 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -42,18 +42,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Workspace.GlobalOptions.SetGlobalOption(SnippetsOptionsStorage.Snippets, True) - Dim snippetCommandHandler As ICommandHandler - If languageName = LanguageNames.CSharp Then - snippetCommandHandler = Workspace.ExportProvider.GetExportedValues(Of ICommandHandler)().Single( - Function(commandHandler) - Return TryCast(commandHandler, CSharp.Snippets.SnippetCommandHandler) IsNot Nothing - End Function) - Else - snippetCommandHandler = Workspace.ExportProvider.GetExportedValues(Of ICommandHandler)().Single( - Function(commandHandler) - Return TryCast(commandHandler, VisualBasic.Snippets.SnippetCommandHandler) IsNot Nothing - End Function) - End If + Dim contentType = If(languageName = LanguageNames.CSharp, ContentTypeNames.CSharpContentType, ContentTypeNames.VisualBasicContentType) + Dim name = If(languageName = LanguageNames.CSharp, "CSharp Snippets", "VB Snippets") + Dim snippetCommandHandler = Workspace.GetService(Of ICommandHandler)(contentType, name) Me.SnippetCommandHandler = DirectCast(snippetCommandHandler, AbstractSnippetCommandHandler) @@ -197,15 +188,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient Return New MockSnippetExpansionClient( - _threadingContext, - Guids.CSharpLanguageServiceId, - textView, - subjectBuffer, - _signatureHelpControllerProvider, - _editorCommandHandlerServiceFactory, - _editorAdaptersFactoryService, - _argumentProviders, - _editorOptionsService) + _threadingContext, + Guids.CSharpLanguageServiceId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService) End Function End Class @@ -243,15 +234,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient Return New MockSnippetExpansionClient( - _threadingContext, - Guids.VisualBasicDebuggerLanguageId, - textView, - subjectBuffer, - _signatureHelpControllerProvider, - _editorCommandHandlerServiceFactory, - _editorAdaptersFactoryService, - _argumentProviders, - _editorOptionsService) + _threadingContext, + Guids.VisualBasicDebuggerLanguageId, + textView, + subjectBuffer, + _signatureHelpControllerProvider, + _editorCommandHandlerServiceFactory, + _editorAdaptersFactoryService, + _argumentProviders, + _editorOptionsService) End Function End Class From 5a9d9c4d7315338469e697369d1e0c62aa243e2c Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 24 Jan 2024 13:43:22 -0600 Subject: [PATCH 5/5] Refactor expansion handler to avoid language-specific derived implementations --- .../OverrideCompletionProviderTests.cs | 1 - .../AbstractCompletionProviderTests.cs | 4 - ...> CSharpSnippetExpansionLanguageHelper.cs} | 59 +++------ .../Impl/Snippets/SnippetCommandHandler.cs | 5 +- .../Snippets/AbstractSnippetCommandHandler.cs | 68 +++++++--- .../AbstractSnippetExpansionClientFactory.cs | 30 ----- .../AbstractSnippetExpansionLanguageHelper.cs | 69 ++++++++++ .../ISnippetExpansionClientFactory.cs | 6 +- .../ISnippetExpansionLanguageHelper.cs | 27 ++++ ...ionClient.cs => SnippetExpansionClient.cs} | 70 ++++------ .../SnippetExpansionClientFactory.cs} | 39 ++++-- ...actSnippetFunction.IVsExpansionFunction.cs | 2 - .../AbstractSnippetFunction.cs | 5 +- .../SnippetFunctionClassName.cs | 2 +- .../SnippetFunctionGenerateSwitchCases.cs | 2 +- .../SnippetFunctionSimpleTypeName.cs | 2 +- .../CSharpSnippetExpansionClientTests.vb | 20 ++- .../SnippetExpansionClientTestsHelper.vb | 5 +- .../Core/Test/Snippets/SnippetTestState.vb | 123 +++++++++--------- .../VisualBasicSnippetExpansionClientTests.vb | 17 ++- .../Impl/Snippets/SnippetCommandHandler.vb | 2 +- .../Snippets/SnippetCompletionProvider.vb | 4 +- ...isualBasicSnippetExpansionClientFactory.vb | 66 ---------- ...ualBasicSnippetExpansionLanguageHelper.vb} | 110 +++++++--------- 24 files changed, 369 insertions(+), 369 deletions(-) rename src/VisualStudio/CSharp/Impl/Snippets/{CSharpSnippetExpansionClient.cs => CSharpSnippetExpansionLanguageHelper.cs} (73%) delete mode 100644 src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs create mode 100644 src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs create mode 100644 src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs rename src/VisualStudio/Core/Def/Snippets/{AbstractSnippetExpansionClient.cs => SnippetExpansionClient.cs} (95%) rename src/VisualStudio/{CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs => Core/Def/Snippets/SnippetExpansionClientFactory.cs} (59%) delete mode 100644 src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb rename src/VisualStudio/VisualBasic/Impl/Snippets/{VisualBasicSnippetExpansionClient.vb => VisualBasicSnippetExpansionLanguageHelper.vb} (78%) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 45d25f05dbd13..02fe8aa17cc07 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; -using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 20388311b53bf..544d6dd3f804e 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -14,16 +14,12 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.InteractiveWindow; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; diff --git a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs similarity index 73% rename from src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs rename to src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs index 948727c4f7d3c..e4424fea36c34 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClient.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionLanguageHelper.cs @@ -4,74 +4,55 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; +using System.Composition; using System.Linq; using System.Threading; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; +using Microsoft.VisualStudio.LanguageServices.Snippets; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Editor.Commanding; using Microsoft.VisualStudio.TextManager.Interop; -using MSXML; using Roslyn.Utilities; using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets { - internal sealed partial class CSharpSnippetExpansionClient : AbstractSnippetExpansionClient + [ExportLanguageService(typeof(ISnippetExpansionLanguageHelper), LanguageNames.CSharp)] + [Shared] + internal class CSharpSnippetExpansionLanguageHelper : AbstractSnippetExpansionLanguageHelper { - public CSharpSnippetExpansionClient( - IThreadingContext threadingContext, - Guid languageServiceGuid, - ITextView textView, - ITextBuffer subjectBuffer, - SignatureHelpControllerProvider signatureHelpControllerProvider, - IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, - IVsEditorAdaptersFactoryService editorAdaptersFactoryService, - ImmutableArray> argumentProviders, - EditorOptionsService editorOptionsService) - : base( - threadingContext, - languageServiceGuid, - textView, - subjectBuffer, - signatureHelpControllerProvider, - editorCommandHandlerServiceFactory, - editorAdaptersFactoryService, - argumentProviders, - editorOptionsService) + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpSnippetExpansionLanguageHelper() { } + public override Guid LanguageServiceGuid => Guids.CSharpLanguageServiceId; + public override string FallbackDefaultLiteral => "default"; + /// The tracking span of the inserted "/**/" if there is an $end$ location, null /// otherwise. - protected override ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan() + public override ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer) { - RoslynDebug.AssertNotNull(ExpansionSession); + RoslynDebug.AssertNotNull(expansionSession); var endSpanInSurfaceBuffer = new VsTextSpan[1]; - if (ExpansionSession.GetEndSpan(endSpanInSurfaceBuffer) != VSConstants.S_OK) + if (expansionSession.GetEndSpan(endSpanInSurfaceBuffer) != VSConstants.S_OK) { return null; } - if (!TryGetSubjectBufferSpan(endSpanInSurfaceBuffer[0], out var subjectBufferEndSpan)) + if (!TryGetSubjectBufferSpan(textView, subjectBuffer, endSpanInSurfaceBuffer[0], out var subjectBufferEndSpan)) { return null; } @@ -79,15 +60,13 @@ public CSharpSnippetExpansionClient( var endPosition = subjectBufferEndSpan.Start.Position; var commentString = "/**/"; - SubjectBuffer.Insert(endPosition, commentString); + subjectBuffer.Insert(endPosition, commentString); var commentSpan = new Span(endPosition, commentString.Length); - return SubjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive); + return subjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive); } - protected override string FallbackDefaultLiteral => "default"; - - internal override Document AddImports( + public override Document AddImports( Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, @@ -131,7 +110,7 @@ internal override Document AddImports( return formattedDocument; } - private static IList GetUsingDirectivesToAdd( + private static List GetUsingDirectivesToAdd( SyntaxNode contextLocation, XElement snippetNode, XElement importsNode) { var namespaceXmlName = XName.Get("Namespace", snippetNode.Name.NamespaceName); diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index 8f9e79f0f584d..62d64c8962b3a 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -92,8 +92,7 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, { AssertIsForeground(); if (args.TypedChar == ';' - && AreSnippetsEnabled(args) - && args.TextView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient snippetExpansionClient) + && AreSnippetsEnabledWithClient(args, out var snippetExpansionClient) && snippetExpansionClient.IsFullMethodCallSnippet) { // Commit the snippet. Leave the caret in place, but clear the selection. Subsequent handlers in the @@ -119,7 +118,7 @@ protected override bool TryInvokeInsertionUI(ITextView textView, ITextBuffer sub expansionManager.InvokeInsertionUI( _editorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer), + GetSnippetExpansionClientFactory(document).GetOrCreateSnippetExpansionClient(document, textView, subjectBuffer), Guids.CSharpLanguageServiceId, bstrTypes: surroundWith ? ["SurroundsWith"] : ["Expansion", "SurroundsWith"], iCountTypes: surroundWith ? 1 : 2, diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs index 9d4f0b9f7eb14..a64930f9c0132 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetCommandHandler.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -50,7 +51,7 @@ public AbstractSnippetCommandHandler( } protected ISnippetExpansionClientFactory GetSnippetExpansionClientFactory(Document document) - => document.GetRequiredLanguageService(); + => document.Project.Services.SolutionServices.GetRequiredService(); protected abstract bool IsSnippetExpansionContext(Document document, int startPosition, CancellationToken cancellationToken); protected abstract bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false); @@ -61,15 +62,15 @@ protected virtual bool TryInvokeSnippetPickerOnQuestionMark(ITextView textView, public bool ExecuteCommand(TabKeyCommandArgs args, CommandExecutionContext context) { AssertIsForeground(); - if (!AreSnippetsEnabled(args)) + if (AreSnippetsEnabledWithClient(args, out var snippetExpansionClient) + && snippetExpansionClient.TryHandleTab()) { - return false; + return true; } - if (args.TextView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient snippetExpansionClient) && - snippetExpansionClient.TryHandleTab()) + if (!AreSnippetsEnabled(args)) { - return true; + return false; } // Insert snippet/show picker only if we don't have a selection: the user probably wants to indent instead @@ -114,8 +115,7 @@ public CommandState GetCommandState(AutomaticLineEnderCommandArgs args, Func(); + snippetExpansionClient = expansionClientFactory?.TryGetSnippetExpansionClient(args.TextView); + return snippetExpansionClient is not null; } } } diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs deleted file mode 100644 index a0feabf4da463..0000000000000 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClientFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; - -internal abstract class AbstractSnippetExpansionClientFactory(IThreadingContext threadingContext) : ISnippetExpansionClientFactory -{ - private readonly IThreadingContext _threadingContext = threadingContext; - - protected abstract AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); - - public AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) - { - Contract.ThrowIfFalse(_threadingContext.JoinableTaskContext.IsOnMainThread); - - if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) - { - expansionClient = CreateSnippetExpansionClient(textView, subjectBuffer); - textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); - } - - return expansionClient; - } -} diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs new file mode 100644 index 0000000000000..c4aa716835af8 --- /dev/null +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionLanguageHelper.cs @@ -0,0 +1,69 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Xml.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; +using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; +using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; + +namespace Microsoft.VisualStudio.LanguageServices.Snippets; + +internal abstract class AbstractSnippetExpansionLanguageHelper + : ISnippetExpansionLanguageHelper +{ + public abstract Guid LanguageServiceGuid { get; } + public abstract string FallbackDefaultLiteral { get; } + + public abstract Document AddImports(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); + public abstract ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer); + + public bool TryGetSubjectBufferSpan(ITextView textView, ITextBuffer subjectBuffer, VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan) + { + var snapshotSpan = textView.TextSnapshot.GetSpan(surfaceBufferTextSpan); + var subjectBufferSpanCollection = textView.BufferGraph.MapDownToBuffer(snapshotSpan, SpanTrackingMode.EdgeExclusive, subjectBuffer); + + // Bail if a snippet span does not map down to exactly one subject buffer span. + if (subjectBufferSpanCollection.Count == 1) + { + subjectBufferSpan = subjectBufferSpanCollection.Single(); + return true; + } + + subjectBufferSpan = default; + return false; + } + + protected static bool TryAddImportsToContainedDocument(Document document, IEnumerable memberImportsNamespaces) + { + var containedDocument = ContainedDocument.TryGetContainedDocument(document.Id); + if (containedDocument == null) + { + return false; + } + + if (containedDocument.ContainedLanguageHost is IVsContainedLanguageHostInternal containedLanguageHost) + { + foreach (var importClause in memberImportsNamespaces) + { + if (containedLanguageHost.InsertImportsDirective(importClause) != VSConstants.S_OK) + { + return false; + } + } + } + + return true; + } +} diff --git a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs index df826b00d4fde..1535c164db0f6 100644 --- a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs +++ b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionClientFactory.cs @@ -2,13 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; -internal interface ISnippetExpansionClientFactory : ILanguageService +internal interface ISnippetExpansionClientFactory : IWorkspaceService { - AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); + SnippetExpansionClient? TryGetSnippetExpansionClient(ITextView textView); + SnippetExpansionClient GetOrCreateSnippetExpansionClient(Document document, ITextView textView, ITextBuffer subjectBuffer); } diff --git a/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs new file mode 100644 index 0000000000000..cdd3bde889e44 --- /dev/null +++ b/src/VisualStudio/Core/Def/Snippets/ISnippetExpansionLanguageHelper.cs @@ -0,0 +1,27 @@ +// 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; +using System.Threading; +using System.Xml.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.TextManager.Interop; +using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; + +namespace Microsoft.VisualStudio.LanguageServices.Snippets; + +internal interface ISnippetExpansionLanguageHelper : ILanguageService +{ + Guid LanguageServiceGuid { get; } + string FallbackDefaultLiteral { get; } + + bool TryGetSubjectBufferSpan(ITextView textView, ITextBuffer subjectBuffer, VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan); + ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(IVsExpansionSession expansionSession, ITextView textView, ITextBuffer subjectBuffer); + Document AddImports(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); +} diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs similarity index 95% rename from src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs rename to src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs index 63452122e8668..ad248417ca2ba 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs @@ -34,7 +34,7 @@ using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; +using Microsoft.VisualStudio.LanguageServices.Snippets; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; @@ -47,7 +47,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets { - internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinitizedObject, IVsExpansionClient + internal class SnippetExpansionClient : ForegroundThreadAffinitizedObject, IVsExpansionClient { /// /// The name of a snippet field created for caret placement in Full Method Call snippet sessions when the @@ -60,12 +60,12 @@ internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinit /// private static readonly string s_fullMethodCallDescriptionSentinel = Guid.NewGuid().ToString("N"); + private readonly ISnippetExpansionLanguageHelper _languageHelper; private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider; private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory; - protected readonly IVsEditorAdaptersFactoryService EditorAdaptersFactoryService; - protected readonly Guid LanguageServiceGuid; - protected readonly ITextView TextView; - protected readonly ITextBuffer SubjectBuffer; + private readonly IVsEditorAdaptersFactoryService EditorAdaptersFactoryService; + private readonly ITextView TextView; + private readonly ITextBuffer SubjectBuffer; internal readonly EditorOptionsService EditorOptionsService; private readonly ImmutableArray> _allArgumentProviders; @@ -87,9 +87,9 @@ internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinit // Writes to this state only occur on the main thread. private readonly State _state = new(); - public AbstractSnippetExpansionClient( + public SnippetExpansionClient( IThreadingContext threadingContext, - Guid languageServiceGuid, + ISnippetExpansionLanguageHelper languageHelper, ITextView textView, ITextBuffer subjectBuffer, SignatureHelpControllerProvider signatureHelpControllerProvider, @@ -99,7 +99,7 @@ public AbstractSnippetExpansionClient( EditorOptionsService editorOptionsService) : base(threadingContext) { - LanguageServiceGuid = languageServiceGuid; + _languageHelper = languageHelper; TextView = textView; SubjectBuffer = subjectBuffer; _signatureHelpControllerProvider = signatureHelpControllerProvider; @@ -154,9 +154,6 @@ public int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldNam return VSConstants.E_INVALIDARG; } } - protected abstract ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(); - internal abstract Document AddImports(Document document, AddImportPlacementOptions addImportOptions, SyntaxFormattingOptions formattingOptions, int position, XElement snippetNode, CancellationToken cancellationToken); - protected abstract string FallbackDefaultLiteral { get; } public int FormatSpan(IVsTextLines pBuffer, VsTextSpan[] tsInSurfaceBuffer) { @@ -217,7 +214,7 @@ public int FormatSpan(IVsTextLines pBuffer, VsTextSpan[] tsInSurfaceBuffer) fullSnippetSpan[0].iStartIndex == tsInSurfaceBuffer[0].iStartIndex && fullSnippetSpan[0].iEndLine == tsInSurfaceBuffer[0].iEndLine && fullSnippetSpan[0].iEndIndex == tsInSurfaceBuffer[0].iEndIndex; - var endPositionTrackingSpan = isFullSnippetFormat ? InsertEmptyCommentAndGetEndPositionTrackingSpan() : null; + var endPositionTrackingSpan = isFullSnippetFormat ? _languageHelper.InsertEmptyCommentAndGetEndPositionTrackingSpan(ExpansionSession, TextView, SubjectBuffer) : null; var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(SubjectBuffer.CurrentSnapshot, snippetTrackingSpan.GetSpan(SubjectBuffer.CurrentSnapshot)); @@ -340,7 +337,7 @@ private static bool SetEndPositionIfNoneSpecified(IVsExpansionSession pSession) return true; } - protected static bool TryGetSnippetNode(IVsExpansionSession pSession, [NotNullWhen(true)] out XElement? snippetNode) + private static bool TryGetSnippetNode(IVsExpansionSession pSession, [NotNullWhen(true)] out XElement? snippetNode) { IXMLDOMNode? xmlNode = null; snippetNode = null; @@ -521,7 +518,7 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end return true; } - if (expansion.InsertExpansion(textSpan, textSpan, this, LanguageServiceGuid, out _state._expansionSession) == VSConstants.S_OK) + if (expansion.InsertExpansion(textSpan, textSpan, this, _languageHelper.LanguageServiceGuid, out _state._expansionSession) == VSConstants.S_OK) { // This expansion is not derived from a symbol, so make sure the state isn't tracking any symbol // information @@ -559,7 +556,7 @@ private bool TryInsertArgumentCompletionSnippet(SnapshotSpan triggerSpan, Snapsh var doc = (DOMDocument)new DOMDocumentClass(); if (doc.loadXML(snippet.ToString(SaveOptions.OmitDuplicateNamespaces))) { - if (expansion.InsertSpecificExpansion(doc, textSpan, this, LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) + if (expansion.InsertSpecificExpansion(doc, textSpan, this, _languageHelper.LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) { Debug.Assert(_state._expansionSession != null); _state._methodNameForInsertFullMethodCall = methodSymbols.First().Name; @@ -585,7 +582,7 @@ private bool TryInsertArgumentCompletionSnippet(SnapshotSpan triggerSpan, Snapsh return false; // Local function - static void EnsureRegisteredForModelUpdatedEvents(AbstractSnippetExpansionClient client, Controller controller) + static void EnsureRegisteredForModelUpdatedEvents(SnippetExpansionClient client, Controller controller) { // Access to _registeredForSignatureHelpEvents is synchronized on the main thread client.ThreadingContext.ThrowIfNotOnUIThread(); @@ -915,7 +912,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell } // If we still have no value, fill in the default - value ??= FallbackDefaultLiteral; + value ??= _languageHelper.FallbackDefaultLiteral; newArguments = newArguments.SetItem(parameter.Name, value); } @@ -924,7 +921,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell var doc = (DOMDocument)new DOMDocumentClass(); if (doc.loadXML(snippet.ToString(SaveOptions.OmitDuplicateNamespaces))) { - if (expansion.InsertSpecificExpansion(doc, adjustedTextSpan, this, LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) + if (expansion.InsertSpecificExpansion(doc, adjustedTextSpan, this, _languageHelper.LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) { Debug.Assert(_state._expansionSession != null); _state._methodNameForInsertFullMethodCall = method.Name; @@ -1014,7 +1011,7 @@ public int OnItemChosen(string pszTitle, string pszPath) _earlyEndExpansionHappened = false; - hr = expansion.InsertNamedExpansion(pszTitle, pszPath, textSpan, this, LanguageServiceGuid, fShowDisambiguationUI: 0, pSession: out _state._expansionSession); + hr = expansion.InsertNamedExpansion(pszTitle, pszPath, textSpan, this, _languageHelper.LanguageServiceGuid, fShowDisambiguationUI: 0, pSession: out _state._expansionSession); if (_earlyEndExpansionHappened) { @@ -1068,7 +1065,7 @@ private void AddReferencesAndImports( var addImportOptions = SubjectBuffer.GetAddImportPlacementOptions(EditorOptionsService, languageServices, documentWithImports.AllowImportsInHiddenRegions()); var formattingOptions = SubjectBuffer.GetSyntaxFormattingOptions(EditorOptionsService, languageServices, explicitFormat: false); - documentWithImports = AddImports(documentWithImports, addImportOptions, formattingOptions, position, snippetNode, cancellationToken); + documentWithImports = _languageHelper.AddImports(documentWithImports, addImportOptions, formattingOptions, position, snippetNode, cancellationToken); AddReferences(documentWithImports.Project, snippetNode); } @@ -1117,28 +1114,6 @@ private static void AddReferences(Project originalProject, XElement snippetNode) } } - protected static bool TryAddImportsToContainedDocument(Document document, IEnumerable memberImportsNamespaces) - { - var containedDocument = ContainedDocument.TryGetContainedDocument(document.Id); - if (containedDocument == null) - { - return false; - } - - if (containedDocument.ContainedLanguageHost is IVsContainedLanguageHostInternal containedLanguageHost) - { - foreach (var importClause in memberImportsNamespaces) - { - if (containedLanguageHost.InsertImportsDirective(importClause) != VSConstants.S_OK) - { - return false; - } - } - } - - return true; - } - internal bool TryGetSubjectBufferSpan(VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan) { var snapshotSpan = TextView.TextSnapshot.GetSpan(surfaceBufferTextSpan); @@ -1210,5 +1185,14 @@ public void Clear() _arguments = _arguments.Clear(); } } + + internal TestAccessor GetTestAccessor() + => new TestAccessor(this); + + internal readonly struct TestAccessor(SnippetExpansionClient instance) + { + internal ISnippetExpansionLanguageHelper LanguageHelper + => instance._languageHelper; + } } } diff --git a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs similarity index 59% rename from src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs rename to src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs index de31ceeb02845..7877a1ab0bfc6 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetExpansionClientFactory.cs @@ -12,26 +12,28 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; +using Microsoft.VisualStudio.LanguageServices.Snippets; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; +using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets; +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; -[ExportLanguageService(typeof(ISnippetExpansionClientFactory), LanguageNames.CSharp)] +[ExportWorkspaceService(typeof(ISnippetExpansionClientFactory))] [Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class CSharpSnippetExpansionClientFactory( +internal class SnippetExpansionClientFactory( IThreadingContext threadingContext, SignatureHelpControllerProvider signatureHelpControllerProvider, IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, IVsEditorAdaptersFactoryService editorAdaptersFactoryService, [ImportMany] IEnumerable> argumentProviders, EditorOptionsService editorOptionsService) - : AbstractSnippetExpansionClientFactory(threadingContext) + : ISnippetExpansionClientFactory { private readonly IThreadingContext _threadingContext = threadingContext; private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider = signatureHelpControllerProvider; @@ -40,11 +42,32 @@ internal sealed class CSharpSnippetExpansionClientFactory( private readonly ImmutableArray> _argumentProviders = argumentProviders.ToImmutableArray(); private readonly EditorOptionsService _editorOptionsService = editorOptionsService; - protected override AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) + public SnippetExpansionClient? TryGetSnippetExpansionClient(ITextView textView) { - return new CSharpSnippetExpansionClient( + Contract.ThrowIfFalse(_threadingContext.JoinableTaskContext.IsOnMainThread); + + _ = textView.Properties.TryGetProperty(typeof(SnippetExpansionClient), out SnippetExpansionClient? expansionClient); + return expansionClient; + } + + public SnippetExpansionClient GetOrCreateSnippetExpansionClient(Document document, ITextView textView, ITextBuffer subjectBuffer) + { + Contract.ThrowIfFalse(_threadingContext.JoinableTaskContext.IsOnMainThread); + + if (!textView.Properties.TryGetProperty(typeof(SnippetExpansionClient), out SnippetExpansionClient? expansionClient)) + { + expansionClient = CreateSnippetExpansionClient(document, textView, subjectBuffer); + textView.Properties.AddProperty(typeof(SnippetExpansionClient), expansionClient); + } + + return expansionClient!; + } + + protected virtual SnippetExpansionClient CreateSnippetExpansionClient(Document document, ITextView textView, ITextBuffer subjectBuffer) + { + return new SnippetExpansionClient( _threadingContext, - Guids.CSharpLanguageServiceId, + document.GetRequiredLanguageService(), textView, subjectBuffer, _signatureHelpControllerProvider, diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs index 7d48c0a353b7a..46a7d2482e939 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.IVsExpansionFunction.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using System.Threading; -using Microsoft.VisualStudio; using Microsoft.VisualStudio.TextManager.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets @@ -42,7 +41,6 @@ int IVsExpansionFunction.GetListText(int index, out string text) int IVsExpansionFunction.ReleaseFunction() { - snippetExpansionClient = null; return VSConstants.S_OK; } } diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.cs index 2118db6f96f98..2d50c8b8a1337 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/AbstractSnippetFunction.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets { @@ -20,9 +19,9 @@ internal abstract partial class AbstractSnippetFunction : IVsExpansionFunction private readonly ITextBuffer _subjectBuffer; private readonly IThreadingContext _threadingContext; - protected AbstractSnippetExpansionClient snippetExpansionClient; + protected readonly SnippetExpansionClient snippetExpansionClient; - public AbstractSnippetFunction(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, IThreadingContext threadingContext) + public AbstractSnippetFunction(SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, IThreadingContext threadingContext) { this.snippetExpansionClient = snippetExpansionClient; _subjectBuffer = subjectBuffer; diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionClassName.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionClassName.cs index d0c4c1630cf65..4c663af8f424f 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionClassName.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionClassName.cs @@ -18,7 +18,7 @@ internal class SnippetFunctionClassName : AbstractSnippetFunction { protected readonly string FieldName; - public SnippetFunctionClassName(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, IThreadingContext threadingContext) + public SnippetFunctionClassName(SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, IThreadingContext threadingContext) : base(snippetExpansionClient, subjectBuffer, threadingContext) { this.FieldName = fieldName; diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs index 1eebf36c44091..eb145163e2d6e 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs @@ -22,7 +22,7 @@ internal class SnippetFunctionGenerateSwitchCases : AbstractSnippetFunction protected readonly string SwitchExpressionField; public SnippetFunctionGenerateSwitchCases( - AbstractSnippetExpansionClient snippetExpansionClient, + SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string caseGenerationLocationField, string switchExpressionField, diff --git a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs index 4c5f2db8b61a7..6ae22d3545ab6 100644 --- a/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs +++ b/src/VisualStudio/Core/Def/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs @@ -20,7 +20,7 @@ internal class SnippetFunctionSimpleTypeName : AbstractSnippetFunction private readonly string _fullyQualifiedName; public SnippetFunctionSimpleTypeName( - AbstractSnippetExpansionClient snippetExpansionClient, + SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, string fullyQualifiedName, diff --git a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb index 1c7fc8fb71791..17ff5c571085e 100644 --- a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.CSharp.Formatting Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Projection @@ -315,8 +316,11 @@ using G= H.I; editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, tabSize) editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, tabSize) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient(document.GetTextView(), textBuffer) + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient( + textBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(), + document.GetTextView(), + textBuffer) SnippetExpansionClientTestsHelper.TestFormattingAndCaretPosition(snippetExpansionClient, document, expectedResult, tabSize * 3) End Using @@ -331,8 +335,9 @@ using G= H.I; {subjectBufferDocument}, options:=ProjectionBufferOptions.WritableLiteralSpans) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient( + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient( + subjectBufferDocument.GetTextBuffer().AsTextContainer().GetOpenDocumentInCurrentContext(), surfaceBufferDocument.GetTextView(), subjectBufferDocument.GetTextBuffer()) @@ -368,8 +373,9 @@ using G= H.I; Next Using workspace = EditorTestWorkspace.CreateCSharp(originalCode, composition:=VisualStudioTestCompositions.LanguageServices) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim expansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient( + workspace.Documents.Single().GetTextBuffer().AsTextContainer().GetOpenDocumentInCurrentContext(), workspace.Documents.Single().GetTextView(), workspace.Documents.Single().GetTextBuffer()) @@ -381,7 +387,7 @@ using G= H.I; Dim formattingOptions = CSharpSyntaxFormattingOptions.Default - Dim updatedDocument = expansionClient.AddImports( + Dim updatedDocument = expansionClient.GetTestAccessor().LanguageHelper.AddImports( document, addImportOptions, formattingOptions, diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetExpansionClientTestsHelper.vb b/src/VisualStudio/Core/Test/Snippets/SnippetExpansionClientTestsHelper.vb index 12cf195eb36a8..2b35604d72376 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetExpansionClientTestsHelper.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetExpansionClientTestsHelper.vb @@ -3,14 +3,13 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.TextManager.Interop Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Friend Class SnippetExpansionClientTestsHelper - Public Shared Sub TestProjectionBuffer(snippetExpansionClient As AbstractSnippetExpansionClient, + Public Shared Sub TestProjectionBuffer(snippetExpansionClient As SnippetExpansionClient, surfaceBufferDocument As EditorTestHostDocument, expectedSurfaceBuffer As XElement) @@ -48,7 +47,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Sub Friend Shared Sub TestFormattingAndCaretPosition( - snippetExpansionClient As AbstractSnippetExpansionClient, + snippetExpansionClient As SnippetExpansionClient, document As EditorTestHostDocument, expectedResult As XElement, expectedVirtualSpacing As Integer) diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index 0b6356759422f..dc52a84921156 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -17,14 +17,18 @@ Imports Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.Snippets +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Editor Imports Microsoft.VisualStudio.Language.Intellisense Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +Imports Microsoft.VisualStudio.LanguageServices.Snippets Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Editor.Commanding +Imports Microsoft.VisualStudio.TextManager.Interop Imports Roslyn.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets @@ -49,8 +53,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Me.SnippetCommandHandler = DirectCast(snippetCommandHandler, AbstractSnippetCommandHandler) Dim editorOptionsService = Workspace.GetService(Of EditorOptionsService)() - Dim snippetExpansionClientFactory = Workspace.Services.GetLanguageServices(languageName).GetRequiredService(Of ISnippetExpansionClientFactory)() - SnippetExpansionClient = CType(snippetExpansionClientFactory.GetSnippetExpansionClient(TextView, SubjectBuffer), MockSnippetExpansionClient) + Dim snippetExpansionClientFactory = Workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + SnippetExpansionClient = CType(snippetExpansionClientFactory.GetOrCreateSnippetExpansionClient(SubjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(), TextView, SubjectBuffer), MockSnippetExpansionClient) If startActiveSession Then SnippetExpansionClient.TryHandleTabReturnValue = True @@ -68,9 +72,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets GetType(MockCompletionPresenterProvider), GetType(StubVsEditorAdaptersFactoryService), GetType(CSharp.Snippets.SnippetCommandHandler), - GetType(MockCSharpSnippetExpansionClientFactory), GetType(VisualBasic.Snippets.SnippetCommandHandler), - GetType(MockVisualBasicSnippetExpansionClientFactory), + GetType(MockCSharpSnippetLanguageHelper), + GetType(MockVisualBasicSnippetLanguageHelper), + GetType(MockSnippetExpansionClientFactory), GetType(MockServiceProvider), GetType(StubVsServiceExporter(Of )), GetType(StubVsServiceExporter(Of ,)) @@ -154,11 +159,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Sub End Class - + <[Shared]> - Friend Class MockCSharpSnippetExpansionClientFactory - Inherits AbstractSnippetExpansionClientFactory + Friend Class MockSnippetExpansionClientFactory + Inherits SnippetExpansionClientFactory Private ReadOnly _threadingContext As IThreadingContext Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider @@ -176,7 +181,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), editorOptionsService As EditorOptionsService) - MyBase.New(threadingContext) + MyBase.New( + threadingContext, + signatureHelpControllerProvider, + editorCommandHandlerServiceFactory, + editorAdaptersFactoryService, + argumentProviders.ToImmutableArray(), + editorOptionsService) _threadingContext = threadingContext _signatureHelpControllerProvider = signatureHelpControllerProvider @@ -186,10 +197,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets _editorOptionsService = editorOptionsService End Sub - Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient + Protected Overrides Function CreateSnippetExpansionClient(document As Document, textView As ITextView, subjectBuffer As ITextBuffer) As SnippetExpansionClient Return New MockSnippetExpansionClient( _threadingContext, - Guids.CSharpLanguageServiceId, + document.GetRequiredLanguageService(Of ISnippetExpansionLanguageHelper)(), textView, subjectBuffer, _signatureHelpControllerProvider, @@ -200,57 +211,61 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Function End Class - + <[Shared]> - Friend Class MockVisualBasicSnippetExpansionClientFactory - Inherits AbstractSnippetExpansionClientFactory + Friend NotInheritable Class MockCSharpSnippetLanguageHelper + Inherits MockSnippetLanguageHelper - Private ReadOnly _threadingContext As IThreadingContext - Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider - Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory - Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService - Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) - Private ReadOnly _editorOptionsService As EditorOptionsService + + + Public Sub New() + MyBase.New(Guids.CSharpLanguageServiceId) + End Sub + End Class + + + <[Shared]> + + Friend NotInheritable Class MockVisualBasicSnippetLanguageHelper + Inherits MockSnippetLanguageHelper - Public Sub New( - threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) - MyBase.New(threadingContext) + Public Sub New() + MyBase.New(Guids.VisualBasicDebuggerLanguageId) + End Sub + End Class - _threadingContext = threadingContext - _signatureHelpControllerProvider = signatureHelpControllerProvider - _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory - _editorAdaptersFactoryService = editorAdaptersFactoryService - _argumentProviders = argumentProviders.ToImmutableArray() - _editorOptionsService = editorOptionsService + Friend MustInherit Class MockSnippetLanguageHelper + Inherits AbstractSnippetExpansionLanguageHelper + + Protected Sub New(languageServiceGuid As Guid) + Me.LanguageServiceGuid = languageServiceGuid End Sub - Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient - Return New MockSnippetExpansionClient( - _threadingContext, - Guids.VisualBasicDebuggerLanguageId, - textView, - subjectBuffer, - _signatureHelpControllerProvider, - _editorCommandHandlerServiceFactory, - _editorAdaptersFactoryService, - _argumentProviders, - _editorOptionsService) + Public Overrides ReadOnly Property LanguageServiceGuid As Guid + + Public Overrides ReadOnly Property FallbackDefaultLiteral As String + Get + Throw New NotImplementedException() + End Get + End Property + + Public Overrides Function AddImports(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document + Return document + End Function + + Public Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan(expansionSession As IVsExpansionSession, textView As ITextView, subjectBuffer As ITextBuffer) As ITrackingSpan + Throw New NotImplementedException() End Function End Class Friend Class MockSnippetExpansionClient - Inherits AbstractSnippetExpansionClient + Inherits SnippetExpansionClient Public Sub New(threadingContext As IThreadingContext, - languageServiceGuid As Guid, + languageHelper As ISnippetExpansionLanguageHelper, textView As ITextView, subjectBuffer As ITextBuffer, signatureHelpControllerProvider As SignatureHelpControllerProvider, @@ -259,7 +274,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), editorOptionsService As EditorOptionsService) MyBase.New(threadingContext, - languageServiceGuid, + languageHelper, textView, subjectBuffer, signatureHelpControllerProvider, @@ -311,20 +326,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets InsertExpansionSpan = New Span(startPosition, endPosition - startPosition) Return TryInsertExpansionReturnValue End Function - - Protected Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan() As ITrackingSpan - Throw New NotImplementedException() - End Function - - Protected Overrides ReadOnly Property FallbackDefaultLiteral As String - Get - Throw New NotImplementedException() - End Get - End Property - - Friend Overrides Function AddImports(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document - Return document - End Function End Class End Class End Namespace diff --git a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb index c978548a7ec00..752282bc42a08 100644 --- a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Formatting Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets Imports Microsoft.VisualStudio.Text.Editor @@ -356,8 +357,8 @@ End Class editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, tabSize) editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, tabSize) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient(document.GetTextView(), textBuffer) + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient(textBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(), document.GetTextView(), textBuffer) SnippetExpansionClientTestsHelper.TestFormattingAndCaretPosition(snippetExpansionClient, document, expectedResult, tabSize * 3) End Using @@ -392,8 +393,9 @@ End Class Next Using workspace = EditorTestWorkspace.Create(workspaceXml, composition:=VisualStudioTestCompositions.LanguageServices) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim expansionClient = expansionClientFactory.GetSnippetExpansionClient( + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim expansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient( + workspace.Documents.Single().GetTextBuffer().AsTextContainer().GetOpenDocumentInCurrentContext(), workspace.Documents.Single().GetTextView(), workspace.Documents.Single().GetTextBuffer()) @@ -406,7 +408,7 @@ End Class Dim formattingOptions = VisualBasicSyntaxFormattingOptions.Default - Dim updatedDocument = expansionClient.AddImports( + Dim updatedDocument = expansionClient.GetTestAccessor().LanguageHelper.AddImports( document, addImportOptions, formattingOptions, @@ -428,8 +430,9 @@ End Class {subjectBufferDocument}, options:=ProjectionBufferOptions.WritableLiteralSpans) - Dim expansionClientFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(Of ISnippetExpansionClientFactory)() - Dim snippetExpansionClient = expansionClientFactory.GetSnippetExpansionClient( + Dim expansionClientFactory = workspace.Services.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetExpansionClient = expansionClientFactory.GetOrCreateSnippetExpansionClient( + subjectBufferDocument.GetTextBuffer().AsTextContainer().GetOpenDocumentInCurrentContext(), surfaceBufferDocument.GetTextView(), subjectBufferDocument.GetTextBuffer()) diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb index adfa5ece3f079..57f71b1a2c1c4 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCommandHandler.vb @@ -68,7 +68,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets expansionManager.InvokeInsertionUI( _editorAdaptersFactoryService.GetViewAdapter(textView), - GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer), + GetSnippetExpansionClientFactory(document).GetOrCreateSnippetExpansionClient(document, textView, subjectBuffer), Guids.VisualBasicDebuggerLanguageId, bstrTypes:=Nothing, iCountTypes:=0, diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb index ad474d2591e5d..b035a0d8dea3e 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb @@ -99,8 +99,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets subjectBuffer As ITextBuffer, triggerSnapshot As ITextSnapshot, commitChar As Char?) Implements ICustomCommitCompletionProvider.Commit - Dim expansionClientFactory = document.GetRequiredLanguageService(Of ISnippetExpansionClientFactory)() - Dim snippetClient = expansionClientFactory.GetSnippetExpansionClient(textView, subjectBuffer) + Dim expansionClientFactory = document.Project.Services.SolutionServices.GetRequiredService(Of ISnippetExpansionClientFactory)() + Dim snippetClient = expansionClientFactory.GetOrCreateSnippetExpansionClient(document, textView, subjectBuffer) Dim trackingSpan = triggerSnapshot.CreateTrackingSpan(completionItem.Span.ToSpan(), SpanTrackingMode.EdgeInclusive) Dim currentSpan = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot) diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb deleted file mode 100644 index 3421c9945f336..0000000000000 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb +++ /dev/null @@ -1,66 +0,0 @@ -' 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. - -Imports System.Collections.Immutable -Imports System.Composition -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp -Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.VisualStudio.Editor -Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets -Imports Microsoft.VisualStudio.Text -Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Editor.Commanding - -Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets - - - <[Shared]> - Friend NotInheritable Class VisualBasicSnippetExpansionClientFactory - Inherits AbstractSnippetExpansionClientFactory - - Private ReadOnly _threadingContext As IThreadingContext - Private ReadOnly _signatureHelpControllerProvider As SignatureHelpControllerProvider - Private ReadOnly _editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory - Private ReadOnly _editorAdaptersFactoryService As IVsEditorAdaptersFactoryService - Private ReadOnly _argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)) - Private ReadOnly _editorOptionsService As EditorOptionsService - - - - Public Sub New( - threadingContext As IThreadingContext, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As IEnumerable(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) - MyBase.New(threadingContext) - - _threadingContext = threadingContext - _signatureHelpControllerProvider = signatureHelpControllerProvider - _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory - _editorAdaptersFactoryService = editorAdaptersFactoryService - _argumentProviders = argumentProviders.ToImmutableArray() - _editorOptionsService = editorOptionsService - End Sub - - Protected Overrides Function CreateSnippetExpansionClient(textView As ITextView, subjectBuffer As ITextBuffer) As AbstractSnippetExpansionClient - Return New VisualBasicSnippetExpansionClient( - _threadingContext, - Guids.VisualBasicDebuggerLanguageId, - textView, - subjectBuffer, - _signatureHelpControllerProvider, - _editorCommandHandlerServiceFactory, - _editorAdaptersFactoryService, - _argumentProviders, - _editorOptionsService) - End Function - End Class - -End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb similarity index 78% rename from src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb rename to src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb index 0476db2ef9e05..01edd5338e9f2 100644 --- a/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClient.vb +++ b/src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionLanguageHelper.vb @@ -2,87 +2,47 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable +Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.AddImport -Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.Extensions Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Extensions Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.VisualStudio.Editor -Imports Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +Imports Microsoft.VisualStudio.LanguageServices.Snippets Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Editor.Commanding +Imports Microsoft.VisualStudio.TextManager.Interop Imports VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets - Friend NotInheritable Class VisualBasicSnippetExpansionClient - Inherits AbstractSnippetExpansionClient - - Public Sub New( - threadingContext As IThreadingContext, - languageServiceId As Guid, - textView As ITextView, - subjectBuffer As ITextBuffer, - signatureHelpControllerProvider As SignatureHelpControllerProvider, - editorCommandHandlerServiceFactory As IEditorCommandHandlerServiceFactory, - editorAdaptersFactoryService As IVsEditorAdaptersFactoryService, - argumentProviders As ImmutableArray(Of Lazy(Of ArgumentProvider, OrderableLanguageMetadata)), - editorOptionsService As EditorOptionsService) - MyBase.New(threadingContext, - languageServiceId, - textView, - subjectBuffer, - signatureHelpControllerProvider, - editorCommandHandlerServiceFactory, - editorAdaptersFactoryService, - argumentProviders, - editorOptionsService) + + <[Shared]> + Friend NotInheritable Class VisualBasicSnippetExpansionLanguageHelper + Inherits AbstractSnippetExpansionLanguageHelper + + + + Public Sub New() End Sub - Protected Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan() As ITrackingSpan - Dim endSpanInSurfaceBuffer(1) As VsTextSpan - If ExpansionSession.GetEndSpan(endSpanInSurfaceBuffer) <> VSConstants.S_OK Then - Return Nothing - End If - - Dim endSpan As SnapshotSpan = Nothing - If Not TryGetSubjectBufferSpan(endSpanInSurfaceBuffer(0), endSpan) Then - Return Nothing - End If + Public Overrides ReadOnly Property LanguageServiceGuid As Guid + Get + Return Guids.VisualBasicDebuggerLanguageId + End Get + End Property - Dim endPositionLine = SubjectBuffer.CurrentSnapshot.GetLineFromPosition(endSpan.Start.Position) - Dim endLineText = endPositionLine.GetText() + Public Overrides ReadOnly Property FallbackDefaultLiteral As String + Get + Return "Nothing" + End Get + End Property - If endLineText.Trim() = String.Empty Then - Dim commentString = "'" - SubjectBuffer.Insert(endSpan.Start.Position, commentString) - - Dim commentSpan = New Span(endSpan.Start.Position, commentString.Length) - Return SubjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive) - End If - - Return Nothing - End Function - - Protected Overrides ReadOnly Property FallbackDefaultLiteral As String = "Nothing" - - Friend Overrides Function AddImports( - document As Document, - addImportOptions As AddImportPlacementOptions, - formattingOptions As SyntaxFormattingOptions, - position As Integer, - snippetNode As XElement, - cancellationToken As CancellationToken) As Document + Public Overrides Function AddImports(document As Document, addImportOptions As AddImportPlacementOptions, formattingOptions As SyntaxFormattingOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document Dim importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)) If importsNode Is Nothing OrElse Not importsNode.HasElements() Then @@ -113,6 +73,31 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Return formattedDocument End Function + Public Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan(expansionSession As IVsExpansionSession, textView As ITextView, subjectBuffer As ITextBuffer) As ITrackingSpan + Dim endSpanInSurfaceBuffer(1) As VsTextSpan + If expansionSession.GetEndSpan(endSpanInSurfaceBuffer) <> VSConstants.S_OK Then + Return Nothing + End If + + Dim endSpan As SnapshotSpan = Nothing + If Not TryGetSubjectBufferSpan(textView, subjectBuffer, endSpanInSurfaceBuffer(0), endSpan) Then + Return Nothing + End If + + Dim endPositionLine = subjectBuffer.CurrentSnapshot.GetLineFromPosition(endSpan.Start.Position) + Dim endLineText = endPositionLine.GetText() + + If endLineText.Trim() = String.Empty Then + Dim commentString = "'" + subjectBuffer.Insert(endSpan.Start.Position, commentString) + + Dim commentSpan = New Span(endSpan.Start.Position, commentString.Length) + Return subjectBuffer.CurrentSnapshot.CreateTrackingSpan(commentSpan, SpanTrackingMode.EdgeExclusive) + End If + + Return Nothing + End Function + Private Shared Function GetImportsStatementsToAdd(document As Document, snippetNode As XElement, importsNode As XElement, cancellationToken As CancellationToken) As IList(Of ImportsStatementSyntax) Dim root = document.GetSyntaxRootSynchronously(cancellationToken) Dim localImportsClauses = CType(root, CompilationUnitSyntax).Imports.SelectMany(Function(x) x.ImportsClauses) @@ -217,4 +202,3 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets End Function End Class End Namespace -