-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Extract factory interface for AbstractSnippetExpansionClient #71752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| nextCommandHandler(); | ||
| } | ||
|
|
||
| protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) |
There was a problem hiding this comment.
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
| editorOptionsService) | ||
| End Sub | ||
|
|
||
| Public Shared Function GetSnippetExpansionClient( |
There was a problem hiding this comment.
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
| 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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
| IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory, | ||
| IVsEditorAdaptersFactoryService editorAdaptersFactoryService, | ||
| [ImportMany] IEnumerable<Lazy<ArgumentProvider, OrderableLanguageMetadata>> argumentProviders, | ||
| EditorOptionsService editorOptionsService) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider primary constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Switched to primary constructor
src/VisualStudio/CSharp/Impl/Snippets/CSharpSnippetExpansionClientFactory.cs
Outdated
Show resolved
Hide resolved
| if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) | ||
| { | ||
| expansionClient = CreateSnippetExpansionClient(textView, subjectBuffer); | ||
| textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a GetOrCreateSingleton method for this exact pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetOrCreateSingleton doesn't support a non-capturing caller, so I kept the pattern we were already using.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the problem? I don't care if this would allocate a lambda -- the allocation cost here is unmeasurable...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up keeping this one not because I think the allocation cost would be a problem, but because the old code used the current pattern and I can't be sure the allocation cost wouldn't be a problem.
|
|
||
| public AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer) | ||
| { | ||
| if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be possible to add some threading asserts here? it's not a big deal, it just makes me feel less oogy about doing weird stuff with proeprty bags on random threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Added assertion
|
|
||
| internal interface ISnippetExpansionClientFactory : ILanguageService | ||
| { | ||
| AbstractSnippetExpansionClient GetSnippetExpansionClient(ITextView textView, ITextBuffer subjectBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for the future would prefer if this exposed a particular interface. I don't love interfaces exposing abstract-reified types like this. But it's def not blocking, and i don't mind this corner of the LS working this way.
There was a problem hiding this comment.
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
src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb
Outdated
Show resolved
Hide resolved
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. lots of duplication between the C# and VB factories. would love this to move down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ The duplication does not appear to be avoidable, so for now left this one as-is.
Moving it down would add a large number of parameters to the base class, and would not simplify either of the derived type constructors. The current form makes it easier to see if any specific implementation no longer needs its parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we were going to unify this further, the trick would be to get rid of the derivations of AbstractSnippetExpansionClient, and instead move any of the different behaviors there into a language service with the appropriate methods...but one step at a time seems reasonable here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would help tremendously for testing. I'll see how viable that is next.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Now refactored in the latest commit
| _signatureHelpControllerProvider = signatureHelpControllerProvider | ||
| _editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory | ||
| _editorAdaptersFactoryService = editorAdaptersFactoryService | ||
| _argumentProviders = argumentProviders.ToImmutableArray() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same. this is duplicated with teh C# version. Could move into the abstract base (including with a primary cosntructor :D). I would really like to see that in this pr :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Refactored to reduce duplication
src/VisualStudio/VisualBasic/Impl/Snippets/VisualBasicSnippetExpansionClientFactory.vb
Outdated
Show resolved
Hide resolved
|
Signing off with the strong ask about moving the shared field code to the base class. I'm ok with that happening in a quick followup PR though if you would prefer to get this in and unblcokign you. |
| { | ||
| return new CSharpSnippetExpansionClient( | ||
| _threadingContext, | ||
| Guids.CSharpLanguageServiceId, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Fixed now
| 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we were going to unify this further, the trick would be to get rid of the derivations of AbstractSnippetExpansionClient, and instead move any of the different behaviors there into a language service with the appropriate methods...but one step at a time seems reasonable here.
| 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we can't just pick out the one that derives from AbstractSnippetCommandHandler and filter with MEF metadata? This feels pretty clunky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Fixed by using an existing helper method
| End Function | ||
| End Class | ||
|
|
||
| <ExportLanguageService(GetType(ISnippetExpansionClientFactory), LanguageNames.VisualBasic, ServiceLayer.Test)> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to do a single export for both languages, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Also leaving this one for #71752 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Only one ExportLanguageService attribute can be applied to a type
Prerequisite to #71731