Skip to content

Commit

Permalink
Merge pull request #50243 from CyrusNajmabadi/workingProgress
Browse files Browse the repository at this point in the history
Add a working internal progress system for codeactions
  • Loading branch information
msftbot[bot] authored Jan 5, 2021
2 parents a1048ea + f823ad3 commit 7902b3b
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
/// <summary>
/// Base class for all Roslyn light bulb menu items.
/// </summary>
internal abstract partial class SuggestedAction : ForegroundThreadAffinitizedObject, ISuggestedAction, IEquatable<ISuggestedAction>
internal abstract partial class SuggestedAction : ForegroundThreadAffinitizedObject, ISuggestedAction3, IEquatable<ISuggestedAction>
{
protected readonly SuggestedActionsSourceProvider SourceProvider;

Expand Down Expand Up @@ -93,6 +94,21 @@ protected Task<ImmutableArray<CodeActionOperation>> GetPreviewOperationsAsync(Ca
}

public void Invoke(CancellationToken cancellationToken)
{
SourceProvider.WaitIndicator.Wait(CodeAction.Title, CodeAction.Message, allowCancel: true, showProgress: true, action: waitContext =>
{
using var combinedCancellationToken = cancellationToken.CombineWith(waitContext.CancellationToken);
Invoke(waitContext.ProgressTracker, combinedCancellationToken.Token);
});
}

public void Invoke(IUIThreadOperationContext context)
{
using var scope = context.AddScope(allowCancellation: true, CodeAction.Message);
this.Invoke(new UIThreadOperationContextProgressTracker(scope), context.UserCancellationToken);
}

private void Invoke(IProgressTracker progressTracker, CancellationToken cancellationToken)
{
// While we're not technically doing anything async here, we need to let the
// integration test harness know that it should not proceed until all this
Expand All @@ -102,17 +118,9 @@ public void Invoke(CancellationToken cancellationToken)
// to the UI thread as well.
using (SourceProvider.OperationListener.BeginAsyncOperation($"{nameof(SuggestedAction)}.{nameof(Invoke)}"))
{
// WaitIndicator cannot be used with async/await. Even though we call async methods
// later in this call chain, do not await them.
SourceProvider.WaitIndicator.Wait(CodeAction.Title, CodeAction.Message, allowCancel: true, showProgress: true, action: waitContext =>
{
using var combinedCancellationToken = cancellationToken.CombineWith(waitContext.CancellationToken);
InnerInvoke(waitContext.ProgressTracker, combinedCancellationToken.Token);
foreach (var actionCallback in SourceProvider.ActionCallbacks)
{
actionCallback.Value.OnSuggestedActionExecuted(this);
}
});
InnerInvoke(progressTracker, cancellationToken);
foreach (var actionCallback in SourceProvider.ActionCallbacks)
actionCallback.Value.OnSuggestedActionExecuted(this);
}
}

Expand Down Expand Up @@ -212,6 +220,8 @@ public string DisplayText
}
}

public string DisplayTextSuffix => "";

protected async Task<SolutionPreviewResult> GetPreviewResultAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.VisualStudio.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
internal class UIThreadOperationContextProgressTracker : IProgressTracker
{
private readonly IUIThreadOperationScope _scope;

private readonly object _gate = new();

public UIThreadOperationContextProgressTracker(IUIThreadOperationScope scope)
=> _scope = scope;

public string? Description { get => _scope.Description; set => _scope.Description = value; }

public int CompletedItems { get; private set; }

public int TotalItems { get; private set; }

public void AddItems(int count)
{
ProgressInfo progressInfo;
lock (_gate)
{
TotalItems += count;
progressInfo = new ProgressInfo(CompletedItems, TotalItems);
}

_scope.Progress.Report(progressInfo);
}

public void ItemCompleted()
{
ProgressInfo progressInfo;
lock (_gate)
{
CompletedItems++;
progressInfo = new ProgressInfo(CompletedItems, TotalItems);
}

_scope.Progress.Report(progressInfo);
}

public void Clear()
{
lock (_gate)
{
CompletedItems = 0;
TotalItems = 0;
}

_scope.Progress.Report(new ProgressInfo());
}
}
}

0 comments on commit 7902b3b

Please sign in to comment.