-
Notifications
You must be signed in to change notification settings - Fork 416
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
Use CompletionService in IntellisenseService #840
Use CompletionService in IntellisenseService #840
Conversation
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.
Nice! Exciting change!
I never opened up the floodgates with CompletionService here because it's not really good enough for completions with multiple text edits (like override completion), or completions that need the commit character in order to complete properly. Personally, I'd like us to figure out override completion a little better before we merge this (to get closer to user expectations), but this should go along ways toward relieving some pain.
// as the display text. | ||
var response = new AutoCompleteResponse() | ||
{ | ||
CompletionText = item.DisplayText, |
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 probably isn't good enough for override completion. Completions on override will just be wrong until we can properly support CompletionService because the completion is multi-line, moves the caret, and may add usings above.
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.
Completion on partial will also be broken.
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.
FYI that this is handled by calling when before an item is committed. http://source.roslyn.io/#Microsoft.CodeAnalysis.Features/Completion/CompletionService.cs,bfe3e3a9f66443fb.
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.
To support completion properly we need a new api similar to what LSP provides with additionalTextEdits
?
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.
Right, but we'll want to be more of a "resolve" API, so we don't have to go computing this for every completion item.
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.
actually overrides and partials won't even reach that specific line because they'd branch out here since these providers encode symbols. So the formatting/presentation of i.e. symbol information will be consistent with the rest of the experience, but yeah ultimately the DisplayText
will be used for completion.
From what I experimented, even the simple DisplayText
at the moment isn't that bad. It actually, in case of overrides, has the following format https://github.com/dotnet/roslyn/blob/614299ff83da9959fa07131c6d0ffbc58873b6ae/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs#L21. So you get to see the full signature, and that's what can be inserted into the code even using the current object/endpoint model we have (of course things like missing usings would have to be resolved manually separately by the user)
It's definitely sub par experience compared to VS but at the same time maybe it's better than not having anything?
But of course, we could also just disable the complex providers like override/partial from participating in the old intellisense endpoint and only add them once we have a new one
|
||
public static async Task<IEnumerable<ISymbol>> GetCompletionSymbols(this CompletionItem completionItem, IEnumerable<ISymbol> recommendedSymbols, Document document) | ||
{ | ||
// for SymbolCompletionProvider, use the logic of extracting information from recommended symbols |
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.
Why? Isn't call GetSymbols(...)
good enough below for all cases?
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 kind of hate that we pre-compute recommendedSymbols (which is essentially like calling the CompletionService twice) just to handle this special case.
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.
unfortunately since this change dotnet/roslyn#15688, the SymbolCompletionProvider
doesn't store encoded symbols in the properties of the completion item anymore, so just calling GetSymbols()
results in an empty array. Instead, the only thing I could think of was that they are fetched using Recommender
. I am sure you'd know more background behind this change and if there is a better way to do it?
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.
Ah yes, I'd forgotten about that. Computing all symbol IDs was simply too expensive.
public static async Task<IEnumerable<ISymbol>> GetCompletionSymbols(this CompletionItem completionItem, IEnumerable<ISymbol> recommendedSymbols, Document document) | ||
{ | ||
// for SymbolCompletionProvider, use the logic of extracting information from recommended symbols | ||
if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") |
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.
It might be good to throw an exception if the type Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider
doesn't exist. That way, we aren't searching around for the reason why completion starts failing if this internal type's name changes.
static CompletionItemExtensions() | ||
{ | ||
var symbolCompletionItemType = typeof(CompletionItem).GetTypeInfo().Assembly.GetType("Microsoft.CodeAnalysis.Completion.Providers.SymbolCompletionItem"); | ||
_getSymbolsAsync = symbolCompletionItemType.GetMethod("GetSymbolsAsync", BindingFlags.Public | BindingFlags.Static); |
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've got some extension methods for this sort of thing (used by MetadataHelper
) that throw exceptions nicely when they fail. I'd recommend using those to ensure we can easily spot failures if internal API names change.
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.
yes good point 👍
thanks, I agree that in order to properly benefit from all the power of |
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.
Since there are complications with partials and overrides, perhaps we can hide those behind a flag that must be turned on in omnisharp.json
?
It's a little more work to remove them from the output, however that lets us keep a nice default for user expectations, but also offer something a little more bleeding edge.
// as the display text. | ||
var response = new AutoCompleteResponse() | ||
{ | ||
CompletionText = item.DisplayText, |
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.
To support completion properly we need a new api similar to what LSP provides with additionalTextEdits
?
The failures on *Nix look real. |
use async suffix on GetCompletionSymbolsAsync move semantic model
a6b9794
to
70c6c11
Compare
a1507e6
to
5c8d067
Compare
Yes it was actually caused by this https://github.com/dotnet/corefx/issues/15825#issuecomment-277722247 "bug" ("behavior"?) of CoreFX - default US culture-based sort behavior is different on Windows and *nix. It should be fine now. |
96b3033
to
5643a01
Compare
if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") | ||
{ | ||
var symbols = recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); | ||
return symbols ?? Enumerable.Empty<ISymbol>(); |
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 don't think Where(...)
or Distinct(...)
will ever return null.
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.
you are right 😊
FWIW, I've never noticed that regex. It existed before I was on the project, so it's presence is a mystery. |
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.
Let's do this. We might want to revisit the experience around completion items that insert methods (e.g. override, partial), but this is definitely an improvement!
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 right. Merging... 😄 |
awesome! 🐣☀️ |
Hello - sorry to bother but a cluster of issues all point to this. I don't get intellisense for C# object initializers in VSCode and it seems this has been a feature for years, right? I'm fully up to date, I think; I don't know how to check the version of OmniSharp. My question is: where do I go for help on this? |
I have to +1 @lukepuplett as it seems I'm experiencing the same thing. Trying to get intellisense for class properties in its initializer is sending me straight to the Process namespace (halfway through the full .NET namespace list) instead of sending me to the top of the list (where the properties are). I opened a bug report in VSCode here but maybe it's related to this instead? microsoft/vscode#128963 |
At the moment, the
CompletionService
is only used for keywords, everything else is coming fromRecommender
.This PR introduces relying on
CompletionService
for all completions.The symbols are still processed the same way as before, so none of the existing features are broken, but extra features available via
CompletionService
also show up in intellisense now (as we process all of its providers).This will close a lot of open bugs via a relatively risk-free change.
I will push some tests into this soon but here are some of the examples of new features that are introduced via this PR:
Attribute completion without
Attribute
Cref completion
Object initializer members completion
Named parameters completion
Override support
Note: because of this Regex in omnisharp-vscode, where brackets are removed, it appears a little broken. This change would need to be done in omnisharp-vscode.