display progress while fixing and display a count summary on exit

Sample output:

[~/src/repos/dart/sdk/pkg/analyzer] (master) $ dart ../dartdev/bin/dartdev.dart fix

*** The `fix` command is provisional and subject to change or removal in future releases. ***

Computing fixes in analyzer...         43.8s
Applying fixes...                      15.5s
Fixed 359 files.



Fixes: https://github.com/dart-lang/sdk/issues/43569

Change-Id: Ief3c9edf578f74413352cdd0a8d84996b1de05f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166302
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 945b709..7cd14e0 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -12,7 +12,6 @@
 import '../core.dart';
 import '../events.dart';
 import '../sdk.dart';
-import '../utils.dart';
 import 'analyze_impl.dart';
 
 class FixCommand extends DartdevCommand<int> {
@@ -22,6 +21,13 @@
   FixCommand() : super(cmdName, 'Fix Dart source code.', hidden: true);
 
   @override
+  UsageEvent createUsageEvent(int exitCode) => FixUsageEvent(
+        usagePath,
+        exitCode: exitCode,
+        args: argResults.arguments,
+      );
+
+  @override
   FutureOr<int> runImpl() async {
     log.stdout('\n*** The `fix` command is provisional and subject to change '
         'or removal in future releases. ***\n');
@@ -69,27 +75,28 @@
     if (edits.isEmpty) {
       log.stdout('Nothing to fix!');
     } else {
-      // todo (pq): consider a summary if more than `n` fixes are applied
-      //  (look at `dartfmt`)
-      log.stdout('Applying fixes to:');
-      for (var edit in edits) {
-        var file = File(edit.file);
-        log.stdout('  ${relativePath(file.path, dir)}');
-        var code = file.existsSync() ? file.readAsStringSync() : '';
-        code = SourceEdit.applySequence(code, edit.edits);
-        file.writeAsStringSync(code);
+      progress = log.progress('Applying fixes');
+      var fileCount = await _applyFixes(edits);
+      progress.finish(showTiming: true);
+      if (fileCount > 0) {
+        log.stdout('Fixed $fileCount files.');
       }
-      log.stdout('Done.');
     }
     return 0;
   }
 
-  @override
-  UsageEvent createUsageEvent(int exitCode) => FixUsageEvent(
-        usagePath,
-        exitCode: exitCode,
-        args: argResults.arguments,
-      );
+  Future<int> _applyFixes(List<SourceFileEdit> edits) async {
+    var files = <String>{};
+    for (var edit in edits) {
+      var fileName = edit.file;
+      files.add(fileName);
+      var file = File(fileName);
+      var code = await file.exists() ? await file.readAsString() : '';
+      code = SourceEdit.applySequence(code, edit.edits);
+      await file.writeAsString(code);
+    }
+    return files.length;
+  }
 }
 
 /// The [UsageEvent] for the fix command.