提交 89e9b8b4 编写于 作者: C Cyrus Najmabadi

Properly show progress as we're performing cleanup.

上级 28688494
......@@ -9,9 +9,11 @@
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.Options.OptionServiceFactory;
using VSCommanding = Microsoft.VisualStudio.Commanding;
......@@ -74,7 +76,7 @@ public bool ExecuteCommand(FormatDocumentCommandArgs args, CommandExecutionConte
return false;
}
using (context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Formatting_document))
using (var scope = context.OperationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Formatting_document))
{
var cancellationToken = context.OperationContext.UserCancellationToken;
......@@ -95,7 +97,8 @@ public bool ExecuteCommand(FormatDocumentCommandArgs args, CommandExecutionConte
{
// Code cleanup
var oldDoc = document;
var codeCleanupChanges = GetCodeCleanupAndFormatChangesAsync(document, codeCleanupService, cancellationToken).WaitAndGetResult(cancellationToken);
var codeCleanupChanges = GetCodeCleanupAndFormatChangesAsync(
document, codeCleanupService, scope, cancellationToken).WaitAndGetResult(cancellationToken);
if (codeCleanupChanges != null && codeCleanupChanges.Count() > 0)
{
......@@ -121,9 +124,23 @@ public bool ExecuteCommand(FormatDocumentCommandArgs args, CommandExecutionConte
return true;
}
private async Task<IEnumerable<TextChange>> GetCodeCleanupAndFormatChangesAsync(Document document, ICodeCleanupService codeCleanupService, CancellationToken cancellationToken)
private async Task<IEnumerable<TextChange>> GetCodeCleanupAndFormatChangesAsync(
Document document, ICodeCleanupService codeCleanupService,
IUIThreadOperationScope scope, CancellationToken cancellationToken)
{
var newDoc = await codeCleanupService.CleanupAsync(document, cancellationToken).ConfigureAwait(false);
var progressTracker = new ProgressTracker((desc, completed, total) =>
{
if (desc != null)
{
scope.Description = desc;
if (total != 0)
{
scope.Progress.Report(new ProgressInfo(completed, total));
}
}
});
var newDoc = await codeCleanupService.CleanupAsync(
document, progressTracker, cancellationToken).ConfigureAwait(false);
return await newDoc.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);
}
......
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.OrganizeImports;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.RemoveUnnecessaryImports;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -107,44 +108,69 @@ internal class CSharpCodeCleanupService : ICodeCleanupService
);
}
public async Task<Document> CleanupAsync(Document document, CancellationToken cancellationToken)
public async Task<Document> CleanupAsync(
Document document, IProgressTracker progressTracker, CancellationToken cancellationToken)
{
var docOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
// add one item for the 'Remove Usings', one for 'Sort using' and one item for the
// 'format' actions we'll do last
progressTracker.AddItems(3);
if (_codeFixServiceOpt != null)
{
document = await ApplyCodeFixesAsync(document, docOptions, cancellationToken).ConfigureAwait(false);
document = await ApplyCodeFixesAsync(
document, progressTracker, docOptions, cancellationToken).ConfigureAwait(false);
}
// do the remove usings after code fix, as code fix might remove some code which can results in unused usings.
document = await RemoveSortUsingsAsync(document, docOptions, cancellationToken).ConfigureAwait(false);
document = await RemoveSortUsingsAsync(
document, progressTracker, docOptions, cancellationToken).ConfigureAwait(false);
progressTracker.Description = FeaturesResources.Formatting_document;
var result = await Formatter.FormatAsync(document).ConfigureAwait(false);
progressTracker.ItemCompleted();
return await Formatter.FormatAsync(document).ConfigureAwait(false);
return result;
}
private async Task<Document> RemoveSortUsingsAsync(Document document, DocumentOptionSet docOptions, CancellationToken cancellationToken)
private async Task<Document> RemoveSortUsingsAsync(
Document document, IProgressTracker tracker, DocumentOptionSet docOptions, CancellationToken cancellationToken)
{
// remove usings
if (docOptions.GetOption(CodeCleanupOptions.RemoveUnusedImports))
{
var removeUsingsService = document.GetLanguageService<IRemoveUnnecessaryImportsService>();
if (removeUsingsService != null)
{
tracker.Description = CSharpFeaturesResources.Organize_Usings;
document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false);
}
}
// sort usings
// mark the remove usings command as done.
tracker.ItemCompleted();
if (docOptions.GetOption(CodeCleanupOptions.SortImports))
{
tracker.Description = CSharpFeaturesResources.Organize_Usings;
document = await OrganizeImportsService.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false);
}
// Mark the sort usings command as done.
tracker.ItemCompleted();
return document;
}
private async Task<Document> ApplyCodeFixesAsync(Document document, DocumentOptionSet docOptions, CancellationToken cancellationToken)
private async Task<Document> ApplyCodeFixesAsync(
Document document, IProgressTracker progressTracker,
DocumentOptionSet docOptions, CancellationToken cancellationToken)
{
var diagnosticIDs = GetEnabledDiagnosticIds(docOptions);
// Add a progress item for each diagnostic we're going to try to cleanup.
progressTracker.AddItems(diagnosticIDs.Length);
var fixAllService = document.Project.Solution.Workspace.Services.GetService<IFixAllGetFixesService>();
var dummy = new ProgressTracker();
......@@ -156,24 +182,27 @@ private async Task<Document> ApplyCodeFixesAsync(Document document, DocumentOpti
var textSpan = new TextSpan(0, syntaxTree.Length);
var fixCollection = await _codeFixServiceOpt.GetFixesAsync(document, textSpan, diagnosticId, cancellationToken).ConfigureAwait(false);
if (fixCollection == null)
if (fixCollection != null && fixCollection.Fixes.Length > 0)
{
continue;
}
progressTracker.Description = fixCollection.Fixes[0].Action.Title;
var fixAll = fixCollection.FixAllState;
var solution = await fixAllService.GetFixAllChangedSolutionAsync(
fixAll.CreateFixAllContext(dummy, cancellationToken)).ConfigureAwait(false);
var fixAll = fixCollection.FixAllState;
var solution = await fixAllService.GetFixAllChangedSolutionAsync(
fixAll.CreateFixAllContext(dummy, cancellationToken)).ConfigureAwait(false);
document = solution.GetDocument(document.Id);
}
document = solution.GetDocument(document.Id);
// Mark this progress item as being completed.
progressTracker.ItemCompleted();
}
return document;
}
private IEnumerable<string> GetEnabledDiagnosticIds(DocumentOptionSet docOptions)
private ImmutableArray<string> GetEnabledDiagnosticIds(DocumentOptionSet docOptions)
{
var diagnosticIds = new List<string>();
var diagnosticIds = ArrayBuilder<string>.GetInstance();
foreach (var tuple in _optionDiagnosticsMappings)
{
......@@ -183,7 +212,7 @@ private IEnumerable<string> GetEnabledDiagnosticIds(DocumentOptionSet docOptions
}
}
return diagnosticIds;
return diagnosticIds.ToImmutableAndFree();
}
}
}
......@@ -3,11 +3,12 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Shared.Utilities;
namespace Microsoft.CodeAnalysis.CodeCleanup
{
internal interface ICodeCleanupService : ILanguageService
{
Task<Document> CleanupAsync(Document document, CancellationToken cancellationToken);
Task<Document> CleanupAsync(Document document, IProgressTracker progressTracker, CancellationToken cancellationToken);
}
}
......@@ -1314,6 +1314,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Formatting document.
/// </summary>
internal static string Formatting_document {
get {
return ResourceManager.GetString("Formatting_document", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to from {0}.
/// </summary>
......
......@@ -1376,4 +1376,7 @@ This version used in: {2}</value>
<data name="Convert_to_conditional_expression" xml:space="preserve">
<value>Convert to conditional expression</value>
</data>
<data name="Formatting_document" xml:space="preserve">
<value>Formatting document</value>
</data>
</root>
\ No newline at end of file
......@@ -2,6 +2,7 @@
{
internal interface IProgressTracker
{
string Description { get; set; }
int CompletedItems { get; }
int TotalItems { get; }
......
......@@ -10,21 +10,37 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
/// </summary>
internal class ProgressTracker : IProgressTracker
{
private string _description;
private int _completedItems;
private int _totalItems;
private readonly Action<int, int> _updateActionOpt;
private readonly Action<string, int, int> _updateActionOpt;
public ProgressTracker()
: this(null)
: this(default(Action<string, int, int>))
{
}
public ProgressTracker(Action<int, int> updateActionOpt)
: this((desc, completed, total) => updateActionOpt?.Invoke(completed, total))
{
}
public ProgressTracker(Action<string, int, int> updateActionOpt)
{
_updateActionOpt = updateActionOpt;
}
public string Description
{
get => _description;
set
{
_description = value;
Update();
}
}
public int CompletedItems => _completedItems;
public int TotalItems => _totalItems;
......@@ -45,12 +61,13 @@ public void Clear()
{
_totalItems = 0;
_completedItems = 0;
_description = null;
Update();
}
private void Update()
{
_updateActionOpt?.Invoke(_completedItems, _totalItems);
_updateActionOpt?.Invoke(_description, _completedItems, _totalItems);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册