-
Notifications
You must be signed in to change notification settings - Fork 229
Fix provisional completion corrupting other requests #11665
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
Changes from all commits
10b9be8
5ed8029
54889c7
cc6e58b
095290c
6273bbe
88eed86
821483b
b9b4597
99637dd
2a7c069
c157286
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Razor.PooledObjects; | ||
| using Microsoft.CodeAnalysis.Razor.Logging; | ||
| using Microsoft.CodeAnalysis.Razor.Protocol; | ||
| using Microsoft.CodeAnalysis.Razor.Protocol.Completion; | ||
| using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; | ||
|
|
@@ -109,7 +110,11 @@ internal partial class RazorCustomMessageTarget | |
| await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); | ||
|
|
||
| var provisionalChange = new VisualStudioTextChange(provisionalTextEdit, virtualDocumentSnapshot.Snapshot); | ||
| UpdateVirtualDocument(provisionalChange, request.ProjectedKind, request.Identifier.Version, hostDocumentUri, virtualDocumentSnapshot.Uri); | ||
| // We update to a negative version number so that if a request comes in for v6, it won't see our modified document. We revert the version back | ||
| // later, don't worry. | ||
| UpdateVirtualDocument(provisionalChange, request.ProjectedKind, -1 * request.Identifier.Version, hostDocumentUri, virtualDocumentSnapshot.Uri); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe a pathological case, but for small versions is there any concern? E.g we're setting this to -1 for v1. Could updates cause some sort of collision there? Should this just be
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So it needs to be less than any other version, so that when something comes in it doesn't think "oh, there is a newer version, I'll cancel." It could be MinValue, but I thought it actually looks nice in the logs that you can see which version caused the provisional update. The only possible conflict would be two provisional completions at the same time but were protected by the UI thread from that. Oh and not to toot my own horn but this situation is impossible to hit in cohosting 😝 |
||
|
|
||
| _logger.LogDebug($"Updated for provisional completion to version -{request.Identifier.Version} of {virtualDocumentSnapshot!.Uri}."); | ||
|
|
||
| // We want the delegation to continue on the captured context because we're currently on the `main` thread and we need to get back to the | ||
| // main thread in order to update the virtual buffer with the reverted text edit. | ||
|
|
@@ -163,6 +168,8 @@ internal partial class RazorCustomMessageTarget | |
| { | ||
| if (provisionalTextEdit is not null) | ||
| { | ||
| _logger.LogDebug($"Reverting the update for provisional completion back to {request.Identifier.Version} of {virtualDocumentSnapshot!.Uri}."); | ||
|
|
||
| var revertedProvisionalTextEdit = BuildRevertedEdit(provisionalTextEdit); | ||
| var revertedProvisionalChange = new VisualStudioTextChange(revertedProvisionalTextEdit, virtualDocumentSnapshot.Snapshot); | ||
| UpdateVirtualDocument(revertedProvisionalChange, request.ProjectedKind, request.Identifier.Version, hostDocumentUri, virtualDocumentSnapshot.Uri); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -294,33 +294,6 @@ protected override void OnAfterRender(bool firstRender) | |
| commitChar: '\t'); | ||
| } | ||
|
|
||
| private async Task VerifyTypeAndCommitCompletionAsync(string input, string output, string search, string[] stringsToType, char? commitChar = null, string? expectedSelectedItemLabel = null) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method just moved down to below all of the actual tests. |
||
| { | ||
| await TestServices.SolutionExplorer.AddFileAsync( | ||
| RazorProjectConstants.BlazorProjectName, | ||
| "Test.razor", | ||
| input, | ||
| open: true, | ||
| ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.WaitForComponentClassificationAsync(ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.PlaceCaretAsync(search, charsOffset: 1, ControlledHangMitigatingCancellationToken); | ||
| foreach (var stringToType in stringsToType) | ||
| { | ||
| TestServices.Input.Send(stringToType); | ||
| } | ||
|
|
||
| if (expectedSelectedItemLabel is not null) | ||
| { | ||
| await CommitCompletionAndVerifyAsync(output, expectedSelectedItemLabel, commitChar); | ||
| } | ||
| else | ||
| { | ||
| await CommitCompletionAndVerifyAsync(output, commitChar); | ||
| } | ||
| } | ||
|
|
||
| [IdeFact] | ||
| public async Task SnippetCompletion_DoesntCommitOnSpace() | ||
| { | ||
|
|
@@ -477,6 +450,78 @@ public enum MyEnum | |
| """); | ||
| } | ||
|
|
||
| [IdeFact, WorkItem("https://github.com/dotnet/razor/issues/11385")] | ||
| public async Task ProvisionalCompletion_DoesntBreakSemanticTokens() | ||
| { | ||
| await TestServices.SolutionExplorer.AddFileAsync( | ||
| RazorProjectConstants.BlazorProjectName, | ||
| "Test.razor", | ||
| """ | ||
| @page "/counter" | ||
|
|
||
| <PageTitle>Counter</PageTitle> | ||
|
|
||
| <h1>Counter</h1> | ||
|
|
||
| <p role="status">Current count: @currentCount</p> | ||
|
|
||
| @DateTime | ||
|
|
||
| <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> | ||
|
|
||
| @code { | ||
| private int currentCount = 0; | ||
|
|
||
| public void IncrementCount() | ||
| { | ||
| currentCount++; | ||
| } | ||
| } | ||
| """, | ||
| open: true, | ||
| ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.WaitForComponentClassificationAsync(ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.PlaceCaretAsync("@DateTime", charsOffset: 1, ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await Task.Delay(500, HangMitigatingCancellationToken); | ||
|
|
||
| TestServices.Input.Send("."); | ||
| TestServices.Input.Send("n"); | ||
|
Comment on lines
+490
to
+491
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Full disclosure: This test on my machine doesn't type fast enough to repro the issue reliably, but it did do it sometimes.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably worth adding a comment on the test that if it's flaky the cause might be a regression in what you fixed. That way future Dave™️ remembers
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I follow. The disco colors detection is now in every test essentially, so this test really just tests provisional completion. If any test causes disco colors, that test will fail so the scenario that caused it will be in the name of the test.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm re-reading my comment, and I think I should expand: This test had flakiness in terms of false-positives (ie, it would sometimes pass) before my code change. After my code change I don't expect it to fail or be flaky. |
||
|
|
||
| await Task.Delay(500, HangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.ValidateNoDiscoColorsAsync(HangMitigatingCancellationToken); | ||
| } | ||
|
|
||
| private async Task VerifyTypeAndCommitCompletionAsync(string input, string output, string search, string[] stringsToType, char? commitChar = null, string? expectedSelectedItemLabel = null) | ||
| { | ||
| await TestServices.SolutionExplorer.AddFileAsync( | ||
| RazorProjectConstants.BlazorProjectName, | ||
| "Test.razor", | ||
| input, | ||
| open: true, | ||
| ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.WaitForComponentClassificationAsync(ControlledHangMitigatingCancellationToken); | ||
|
|
||
| await TestServices.Editor.PlaceCaretAsync(search, charsOffset: 1, ControlledHangMitigatingCancellationToken); | ||
| foreach (var stringToType in stringsToType) | ||
| { | ||
| TestServices.Input.Send(stringToType); | ||
| } | ||
|
|
||
| if (expectedSelectedItemLabel is not null) | ||
| { | ||
| await CommitCompletionAndVerifyAsync(output, expectedSelectedItemLabel, commitChar); | ||
| } | ||
| else | ||
| { | ||
| await CommitCompletionAndVerifyAsync(output, commitChar); | ||
| } | ||
| } | ||
|
|
||
| private async Task CommitCompletionAndVerifyAsync(string expected, char? commitChar = null) | ||
| { | ||
| var session = await TestServices.Editor.WaitForCompletionSessionAsync(HangMitigatingCancellationToken); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.