-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Make the IDocumentNavigationSerivice entirely async. #59784
Conversation
@@ -58,63 +64,65 @@ public void AugmentPeekSession(IPeekSession session, IList<IPeekableItem> peekab | |||
|
|||
_uiThreadOperationExecutor.Execute(EditorFeaturesResources.Peek, EditorFeaturesResources.Loading_Peek_information, allowCancellation: true, showProgress: false, action: context => |
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.
review with whitespace off.
Service = service; | ||
} | ||
|
||
public IWorkspaceThreadingService Service { get; } |
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.
@jasonmalinowski i needed this for teh DocumentNavigationOperation change below. That's a public API we can't pass an IThreadingContext into. INstead, it just gets a WOrkspace, so we need a way to get this from that.
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.
Yeah, this seems reasonable in the sense that I don't have a good alternative here.
@@ -34,7 +35,10 @@ public override void Apply(Workspace workspace, CancellationToken cancellationTo | |||
if (workspace.CanOpenDocuments) | |||
{ | |||
var navigationService = workspace.Services.GetService<IDocumentNavigationService>(); | |||
navigationService.TryNavigateToPosition(workspace, _documentId, _position, cancellationToken); | |||
var threadingService = workspace.Services.GetService<IWorkspaceThreadingServiceProvider>(); |
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 is a new concept @jasonmalinowski . not sure if there's any better way 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.
Yeah, I don't have many better options other than leave the sync method on the IDocumentNavigationService and then inline this, which of course kinda undoes what you're trying to do. So unless @sharwell has a better idea, I'm OK with this in the "I will pinch my nose and sign off because I don't have a better idea".
internal interface IWorkspaceThreadingServiceProvider : IWorkspaceService | ||
{ | ||
IWorkspaceThreadingService Service { get; } | ||
} |
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.
moral equivalent of IWorkspaceThreadingService @jasonmalinowski . However the above one is only available through MEF, where i need it when i only have a workspace available.
src/Tools/ExternalAccess/FSharp/Navigation/FSharpDocumentNavigationService.cs
Outdated
Show resolved
Hide resolved
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.
Some comments but generally seems fine. I don't like the hack you had to do that you flagged but I don't have a better idea.
src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs
Outdated
Show resolved
Hide resolved
src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs
Outdated
Show resolved
Hide resolved
@@ -27,18 +21,13 @@ internal interface IDocumentNavigationService : IWorkspaceService | |||
/// Determines whether it is possible to navigate to the given line/offset in the specified document. | |||
/// </summary> | |||
/// <remarks>Only legal to call on the UI thread.</remarks> | |||
bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, CancellationToken cancellationToken); | |||
Task<bool> CanNavigateToLineAndOffsetAsync(Workspace workspace, DocumentId documentId, int lineNumber, int offset, CancellationToken cancellationToken); |
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's a bit fishy to me we would have added the async methods but left the sync ones too -- was there some reason that still applies? Is this being used via IVT or something?
src/Tools/ExternalAccess/FSharp/Navigation/IFSharpDocumentNavigationService.cs
Outdated
Show resolved
Hide resolved
@@ -34,7 +35,10 @@ public override void Apply(Workspace workspace, CancellationToken cancellationTo | |||
if (workspace.CanOpenDocuments) | |||
{ | |||
var navigationService = workspace.Services.GetService<IDocumentNavigationService>(); | |||
navigationService.TryNavigateToPosition(workspace, _documentId, _position, cancellationToken); | |||
var threadingService = workspace.Services.GetService<IWorkspaceThreadingServiceProvider>(); |
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.
Yeah, I don't have many better options other than leave the sync method on the IDocumentNavigationService and then inline this, which of course kinda undoes what you're trying to do. So unless @sharwell has a better idea, I'm OK with this in the "I will pinch my nose and sign off because I don't have a better idea".
Me.ProvidedDocumentId = documentId | ||
Me.ProvidedLineNumber = lineNumber | ||
|
||
Return CanNavigateToLineAndOffsetReturnValue | ||
Return If(CanNavigateToLineAndOffsetReturnValue, SpecializedTasks.True, SpecializedTasks.False) |
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 don't have a helper for this?
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.
couldn't find one :)
...ore/Portable/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentNavigationServiceWrapper.cs
Show resolved
Hide resolved
src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameService.cs
Outdated
Show resolved
Hide resolved
@@ -184,7 +184,8 @@ internal class CodeActionEditHandlerService : ForegroundThreadAffinitizedObject, | |||
} | |||
|
|||
var updatedSolution = operations.OfType<ApplyChangesOperation>().FirstOrDefault()?.ChangedSolution ?? oldSolution; | |||
TryNavigateToLocationOrStartRenameSession(workspace, oldSolution, updatedSolution, cancellationToken); |
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.
Wait, so if applied is false we do the navigation anyways?
// Mappings for opened razor files are retrieved via the LSP client making a request to the razor server. | ||
// If we wait for the result on the UI thread, we will hit a bug in the LSP client that brings us to a code path | ||
// using ConfigureAwait(true). This deadlocks as it then attempts to return to the UI thread which is already blocked by us. | ||
// Instead, we invoke this in JTF run which will mitigate deadlocks when the ConfigureAwait(true) | ||
// tries to switch back to the main thread in the LSP client. | ||
// Link to LSP client bug for ConfigureAwait(true) - https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1216657 |
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.
Is this comment applicable anymore?
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.
oh that's terrifying.
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 should no longer apply as we're either all async, or our callers need to be in JTF run calls themselves (this PR).
Extracting out from #59759.
This is step one in making navigation saner. Next step is to make the service non-imperative itself. e.g. it can be queried to determine navigatino locations independent of actually navigating to those locations.
In many cases, this asynchrony just pushed up till it reached something already async (yaay).
In other cases this async pushed up until we got to a synchronous location due to an API we implement, but that had an ITHreadingContext. In those cases we can jsut JTF run the async code then.
In the final cases this pushed up to a synchronous location without an IThreadingContext. In those cases, an IThreadingContext was imported and passed in to support this.