Skip to content

Make the IDocumentNavigationSerivice entirely async.#59784

Merged
CyrusNajmabadi merged 13 commits intodotnet:mainfrom
CyrusNajmabadi:asyncNavigation
Feb 27, 2022
Merged

Make the IDocumentNavigationSerivice entirely async.#59784
CyrusNajmabadi merged 13 commits intodotnet:mainfrom
CyrusNajmabadi:asyncNavigation

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Feb 25, 2022

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.

@CyrusNajmabadi CyrusNajmabadi requested review from a team as code owners February 25, 2022 22:36
@CyrusNajmabadi CyrusNajmabadi requested a review from a team February 25, 2022 22:36
@ghost ghost added the Area-IDE label Feb 25, 2022
@@ -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 =>
Copy link
Copy Markdown
Contributor Author

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; }
Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

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.

{
var navigationService = workspace.Services.GetService<IDocumentNavigationService>();
navigationService.TryNavigateToPosition(workspace, _documentId, _position, cancellationToken);
var threadingService = workspace.Services.GetService<IWorkspaceThreadingServiceProvider>();
Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

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; }
}
Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

@jasonmalinowski jasonmalinowski left a 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.

/// </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);
Copy link
Copy Markdown
Member

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?

{
var navigationService = workspace.Services.GetService<IDocumentNavigationService>();
navigationService.TryNavigateToPosition(workspace, _documentId, _position, cancellationToken);
var threadingService = workspace.Services.GetService<IWorkspaceThreadingServiceProvider>();
Copy link
Copy Markdown
Member

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.ProvidedLineNumber = lineNumber

Return CanNavigateToLineAndOffsetReturnValue
Return If(CanNavigateToLineAndOffsetReturnValue, SpecializedTasks.True, SpecializedTasks.False)
Copy link
Copy Markdown
Member

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't find one :)

}

var updatedSolution = operations.OfType<ApplyChangesOperation>().FirstOrDefault()?.ChangedSolution ?? oldSolution;
TryNavigateToLocationOrStartRenameSession(workspace, oldSolution, updatedSolution, cancellationToken);
Copy link
Copy Markdown
Member

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?

Comment on lines 376 to 381
// 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
Copy link
Copy Markdown
Member

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh that's terrifying.

Copy link
Copy Markdown
Contributor Author

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).

@CyrusNajmabadi CyrusNajmabadi merged commit 7b723b7 into dotnet:main Feb 27, 2022
@ghost ghost added this to the Next milestone Feb 27, 2022
@RikkiGibson RikkiGibson modified the milestones: Next, 17.2.P2 Mar 1, 2022
@CyrusNajmabadi CyrusNajmabadi deleted the asyncNavigation branch March 2, 2022 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants