Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,6 +14,6 @@ namespace Microsoft.CodeAnalysis.Editor
/// </summary>
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slight waryness as i believe we support completion in non-Document cases. However, it's likely we don't support Custom completion there, so this is likely fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the callers already have a Document in scope. This is an internal interface that could be adjusted in the future if we need to support a new scenario.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➡️ Left this one as-is

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpSnippetExpansionClientFactory(
IThreadingContext threadingContext,
SignatureHelpControllerProvider signatureHelpControllerProvider,
IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
[ImportMany] IEnumerable<Lazy<ArgumentProvider, OrderableLanguageMetadata>> argumentProviders,
EditorOptionsService editorOptionsService)
: AbstractSnippetExpansionClientFactory(threadingContext)
{
private readonly IThreadingContext _threadingContext = threadingContext;
private readonly SignatureHelpControllerProvider _signatureHelpControllerProvider = signatureHelpControllerProvider;
private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService = editorAdaptersFactoryService;
private readonly ImmutableArray<Lazy<ArgumentProvider, OrderableLanguageMetadata>> _argumentProviders = argumentProviders.ToImmutableArray();
private readonly EditorOptionsService _editorOptionsService = editorOptionsService;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just get rid of these and use the constructor parameters? It'd definitely clean this type up nicely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➡️ For me, this change is blocked on insufficient resolution to #70419


protected override AbstractSnippetExpansionClient CreateSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer)
{
return new CSharpSnippetExpansionClient(
_threadingContext,
Guids.CSharpLanguageServiceId,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does anything ever pass in a different constant for the this? Or should this just be set directly in CSharpSnippetExpansionClient.cs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➡️ In light of #71752 (comment), leaving this for a follow-up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➡️ Fixed now

textView,
subjectBuffer,
_signatureHelpControllerProvider,
_editorCommandHandlerServiceFactory,
_editorAdaptersFactoryService,
_argumentProviders,
_editorOptionsService);
}
}
50 changes: 12 additions & 38 deletions src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
#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;
Expand All @@ -24,11 +19,10 @@
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;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;

namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets
Expand All @@ -45,21 +39,18 @@ internal sealed class SnippetCommandHandler :
ICommandHandler<SurroundWithCommandArgs>,
IChainedCommandHandler<TypeCharCommandArgs>
{
private readonly ImmutableArray<Lazy<ArgumentProvider, OrderableLanguageMetadata>> _argumentProviders;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;

[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,
SignatureHelpControllerProvider signatureHelpControllerProvider,
IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
SVsServiceProvider serviceProvider,
[ImportMany] IEnumerable<Lazy<ArgumentProvider, OrderableLanguageMetadata>> argumentProviders,
IVsService<SVsTextManager, IVsTextManager2> textManager,
EditorOptionsService editorOptionsService)
: base(threadingContext, signatureHelpControllerProvider, editorCommandHandlerServiceFactory, editorAdaptersFactoryService, editorOptionsService, serviceProvider)
: base(threadingContext, editorOptionsService, textManager)
{
_argumentProviders = argumentProviders.ToImmutableArray();
_editorAdaptersFactoryService = editorAdaptersFactoryService;
}

public bool ExecuteCommand(SurroundWithCommandArgs args, CommandExecutionContext context)
Expand Down Expand Up @@ -115,37 +106,20 @@ public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler,
nextCommandHandler();
}

protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 This pull request decouples this factory method

{
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 bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false)
{
if (!TryGetExpansionManager(out var expansionManager))
{
return false;
}

var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
return false;

expansionManager.InvokeInsertionUI(
EditorAdaptersFactoryService.GetViewAdapter(textView),
GetSnippetExpansionClient(textView, subjectBuffer),
_editorAdaptersFactoryService.GetViewAdapter(textView),
GetSnippetExpansionClientFactory(document).GetSnippetExpansionClient(textView, subjectBuffer),
Guids.CSharpLanguageServiceId,
bstrTypes: surroundWith ? ["SurroundsWith"] : ["Expansion", "SurroundsWith"],
iCountTypes: surroundWith ? 1 : 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,14 @@
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;
using Microsoft.CodeAnalysis.Shared.Extensions;
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;
using Microsoft.VisualStudio.Text.Editor.Commanding;
Expand All @@ -38,31 +34,24 @@ internal abstract class AbstractSnippetCommandHandler :
ICommandHandler<InsertSnippetCommandArgs>,
IChainedCommandHandler<AutomaticLineEnderCommandArgs>
{
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 IVsService<IVsTextManager2> _textManager;

public string DisplayName => FeaturesResources.Snippets;

public AbstractSnippetCommandHandler(
IThreadingContext threadingContext,
SignatureHelpControllerProvider signatureHelpControllerProvider,
IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
EditorOptionsService editorOptionsService,
SVsServiceProvider serviceProvider)
IVsService<IVsTextManager2> textManager)
: base(threadingContext)
{
SignatureHelpControllerProvider = signatureHelpControllerProvider;
EditorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory;
EditorAdaptersFactoryService = editorAdaptersFactoryService;
EditorOptionsService = editorOptionsService;
ServiceProvider = serviceProvider;
_editorOptionsService = editorOptionsService;
_textManager = textManager;
}

protected abstract AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer);
protected ISnippetExpansionClientFactory GetSnippetExpansionClientFactory(Document document)
=> document.GetRequiredLanguageService<ISnippetExpansionClientFactory>();

protected abstract bool IsSnippetExpansionContext(Document document, int startPosition, CancellationToken cancellationToken);
protected abstract bool TryInvokeInsertionUI(ITextView textView, ITextBuffer subjectBuffer, bool surroundWith = false);

Expand Down Expand Up @@ -299,12 +288,12 @@ protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuff
return false;
}

return 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;
Expand All @@ -323,7 +312,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);
}
Expand Down
Loading