Skip to content
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

Merged
merged 13 commits into from
Feb 27, 2022

Conversation

CyrusNajmabadi
Copy link
Member

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

@@ -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
Member 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
Member 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
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.

@@ -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>();
Copy link
Member 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
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
Member 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
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.

@@ -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);
Copy link
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?

@@ -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>();
Copy link
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.ProvidedDocumentId = documentId
Me.ProvidedLineNumber = lineNumber

Return CanNavigateToLineAndOffsetReturnValue
Return If(CanNavigateToLineAndOffsetReturnValue, SpecializedTasks.True, SpecializedTasks.False)
Copy link
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
Member 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 :)

@@ -184,7 +184,8 @@ internal class CodeActionEditHandlerService : ForegroundThreadAffinitizedObject,
}

var updatedSolution = operations.OfType<ApplyChangesOperation>().FirstOrDefault()?.ChangedSolution ?? oldSolution;
TryNavigateToLocationOrStartRenameSession(workspace, oldSolution, updatedSolution, cancellationToken);
Copy link
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
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
Member 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
Member 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