Add async modifier on await completion#48352
Conversation
65354d1 to
d60bef3
Compare
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
|
Pinging @genlu for review. |
| var method = syntaxContext.TargetToken.GetAncestor(node => node.IsAsyncSupportingFunctionSyntax()); | ||
| if (method is not null && !method.GetModifiers().Any(SyntaxKind.AsyncKeyword)) | ||
| { | ||
| context.AddItem(CommonCompletionItem.Create("await", string.Empty, CompletionItemRules.Default, inlineDescription: "Make container async")); |
There was a problem hiding this comment.
This might end up conflicting with the item provided by keyword recommender, and one would get deduplicated: since they have seem to have identical full display text (prefix + text + suffix), this will be decided by the order of providers being called.
There was a problem hiding this comment.
Hiding the keyword might be the behavior we want, if so, we should figure out a way to make it explicit.
Otherwise, we need to show them both and give one higher priority . Before we get to the detail on how to implement this, let's figure out which approach we'd like to take.
In reply to: 517718403 [](ancestors = 517718403)
There was a problem hiding this comment.
I don't think we have reached a conclusion on this yet. Current behavior relies on the implementation detail of completion service which is fragile. One way to resolve the interaction issue between two providers that provide "await" item is to fold the keyword provider into this one.
@CyrusNajmabadi thoughts?
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers | ||
| { | ||
| [ExportCompletionProvider(nameof(AwaitCompletionProvider), LanguageNames.CSharp)] |
There was a problem hiding this comment.
I think this would be valuable in VB too. Any plan to add VB support in this PR?
There was a problem hiding this comment.
👍 would def want VB here.
There was a problem hiding this comment.
Are you planning to add VB support in this PR?
There was a problem hiding this comment.
question still remains. but i'm ok with no vb support initially if you'd prefer to punt on that for now.
There was a problem hiding this comment.
@CyrusNajmabadi I'll likely do that in a separate PR :(
src/Features/CSharp/Portable/Completion/CompletionProviders/AwaitCompletionProvider.cs
Outdated
Show resolved
Hide resolved
| { | ||
| } | ||
|
|
||
| internal override ImmutableHashSet<char> TriggerCharacters => CompletionUtilities.CommonTriggerCharactersWithArgumentList; |
There was a problem hiding this comment.
@dibarbet @allisonchou is this the proper TriggerCharacters to use?
|
|
||
| // MethodDeclarationSyntax, LocalFunctionStatementSyntax, AnonymousMethodExpressionSyntax, ParenthesizedLambdaExpressionSyntax, SimpleLambdaExpressionSyntax. | ||
|
|
||
| var newDeclaration = AddAsyncModifier(declaration, SyntaxGenerator.GetGenerator(document)); |
There was a problem hiding this comment.
Does this work in debugging scenarios? e.g. EnC, watch window, etc
|
FYI @JoeRobich @333fred This is a new completion provider that make changes outside of current span, I guess it might need some additional work in OmniSharp to enable it in VS Code? |
|
Could you please added some tests as well? Thanks! |
There was a problem hiding this comment.
Done with pass. Thanks for the contribution :)
In general, I like the approach of creating a separate provider. One of the major question I have is about dealing with item of await keyword and item from this provider. @CyrusNajmabadi have you discussed this with @Youssef1313 already?
|
Hi @Youssef1313, any update on this PR? Please let me know if there's anything I can do to help moving this forward. Thanks! :) |
@genlu Thanks for pinging. I might take some time to be able to work on this again. I'm okay if you (or any other external contributor) would like to take this over and continue the work. |
8423322 to
f1df660
Compare
|
@genlu I'm working on this again now. I uploaded a GIF with what I currently have. Can you review? Sorry for the delay. |
|
Current test failures are being fixed in #54240 @CyrusNajmabadi Can you take another look? Thanks! |
|
Will do. Can you remind me in Monday though? |
Ping @CyrusNajmabadi |
|
Ping @CyrusNajmabadi |
|
|
||
| return; | ||
|
|
||
| static CompletionItem GetCompletionItem(bool shouldMakeContainerAsync) |
There was a problem hiding this comment.
this helper method seems pointless. inline?
| var documentWithAsyncModifier = document.WithSyntaxRoot(root.ReplaceNode(declaration, AddAsyncModifier(declaration))); | ||
| using var _ = ArrayBuilder<TextChange>.GetInstance(out var builder); | ||
|
|
||
| builder.AddRange(await documentWithAsyncModifier.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false)); |
There was a problem hiding this comment.
this part is actually a bit terrifying. tehre is no invariant that GetTextChanges returns good edits. Instead of going this route, i would instead either:
- just literally hardcode in the logic for determining the span where
asyncshould go. - use AddAsyncModifier, then directly check the new declaration for the
asynctoken and figure out the span from taht
Either of those will give a nice narrow text edit that we can depend on.
This is a blocker for this PR currently.
There was a problem hiding this comment.
Note: This was following what's currently done in another completion provider:
I'll try with either of the approaches you mentioned.
tehre is no invariant that GetTextChanges returns good edits
I'm curious what "good edits" mean?
There was a problem hiding this comment.
I'm curious what "good edits" mean?
So if you added async , you'd ideally get an edit like 'async ' was added at position 15. But there's no guarantee of that. it might literally say: i added the entire contents of the file at position 0.
| return CompletionChange.Create(CodeAnalysis.Completion.Utilities.Collapse(newText, builder.ToImmutableArray())); | ||
| } | ||
|
|
||
| private static SyntaxNode AddAsyncModifier(SyntaxNode declaration) |
There was a problem hiding this comment.
since we're manually adding the async modifier anyways, it's fairly trivial for us to instead just determine the text-edit for where the async modifier should go directly. please switch to that. thanks!
CyrusNajmabadi
left a comment
There was a problem hiding this comment.
definitely some necesxsary changes to make :)
|
@CyrusNajmabadi This is ready for another look. |
|
Ping @CyrusNajmabadi |
|
Thanks! really looking forward to this :) |
Fixes #45368
(Outdated)TODO: