Add `--update-files` flag to tool/common_mark_stats.dart
diff --git a/pkgs/markdown/tool/common_mark_stats.dart b/pkgs/markdown/tool/common_mark_stats.dart
index 0820e7a..fb3554a 100644
--- a/pkgs/markdown/tool/common_mark_stats.dart
+++ b/pkgs/markdown/tool/common_mark_stats.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
 import 'dart:collection';
 import 'dart:convert';
 import 'dart:io';
@@ -17,16 +18,38 @@
 String get _currentDir => p
     .dirname((reflect(main) as ClosureMirror).function.location.sourceUri.path);
 
-void main(List<String> args) {
+main(List<String> args) async {
   final parser = new ArgParser()
-    ..addOption('section', help: 'Restrict tests to one section')
-    ..addFlag('raw', defaultsTo: false, help: 'raw JSON format')
-    ..addFlag('verbose', defaultsTo: false, help: 'verbose output');
+    ..addOption('section',
+        help: 'Restrict tests to one section, provided after the option.')
+    ..addFlag('raw',
+        defaultsTo: false, help: 'raw JSON format', negatable: false)
+    ..addFlag('update-files',
+        defaultsTo: false,
+        help: 'Update stats files in $_currentDir',
+        negatable: false)
+    ..addFlag('verbose',
+        defaultsTo: false, help: 'verbose output', negatable: false)
+    ..addFlag('help', defaultsTo: false, negatable: false);
+
   var options = parser.parse(args);
 
-  var specifiedSection = options['section'];
-  var raw = options['raw'];
-  var verbose = options['verbose'];
+  if (options['help']) {
+    print(parser.usage);
+    return;
+  }
+
+  var specifiedSection = options['section'] as String;
+  var raw = options['raw'] as bool;
+  var verbose = options['verbose'] as bool;
+  var updateFiles = options['update-files'] as bool;
+
+  if (updateFiles && (raw || verbose || (specifiedSection != null))) {
+    print('The `update-files` flag must be used by itself');
+    print(parser.usage);
+    exitCode = 64; // unix standard improper usage
+    return;
+  }
 
   var sections = _loadCommonMarkSections();
 
@@ -67,17 +90,12 @@
     }
   });
 
-  if (raw) {
-    var encoder = const JsonEncoder.withIndent(' ', _convert);
-    try {
-      print(encoder.convert(scores));
-    } on JsonUnsupportedObjectError catch (e) {
-      print(e.cause);
-      print(e.unsupportedObject.runtimeType);
-      rethrow;
-    }
-  } else {
-    _printFriendly(scores);
+  if (raw || updateFiles) {
+    _printRaw(scores, updateFiles);
+  }
+
+  if (!raw || updateFiles) {
+    _printFriendly(scores, updateFiles);
   }
 }
 
@@ -93,12 +111,47 @@
   return obj;
 }
 
-void _printFriendly(SplayTreeMap<String, SplayTreeMap<int, bool>> scores) {
+Future _printRaw(scores, bool updateFiles) async {
+  IOSink sink;
+  if (updateFiles) {
+    var path = p.join(_currentDir, 'common_mark_stats.json');
+    print('Updating $path');
+    var file = new File(path);
+    sink = file.openWrite();
+  } else {
+    sink = stdout;
+  }
+
+  var encoder = const JsonEncoder.withIndent(' ', _convert);
+  try {
+    sink.writeln(encoder.convert(scores));
+  } on JsonUnsupportedObjectError catch (e) {
+    stderr.writeln(e.cause);
+    stderr.writeln(e.unsupportedObject.runtimeType);
+    rethrow;
+  }
+
+  await sink.flush();
+  await sink.close();
+}
+
+Future _printFriendly(SplayTreeMap<String, SplayTreeMap<int, bool>> scores,
+    bool updateFiles) async {
   const countWidth = 4;
 
   var totalValid = 0;
   var totalExamples = 0;
 
+  IOSink sink;
+  if (updateFiles) {
+    var path = p.join(_currentDir, 'common_mark_stats.txt');
+    print('Updating $path');
+    var file = new File(path);
+    sink = file.openWrite();
+  } else {
+    sink = stdout;
+  }
+
   scores.forEach((section, map) {
     var total = map.values.length;
     totalExamples += total;
@@ -109,16 +162,19 @@
 
     var pct = (100 * sectionValidCount / total).toStringAsFixed(1).padLeft(5);
 
-    print('${sectionValidCount.toString().padLeft(countWidth)} '
+    sink.writeln('${sectionValidCount.toString().padLeft(countWidth)} '
         'of ${total.toString().padLeft(countWidth)} '
         '– ${pct}%  $section');
   });
 
   var pct = (100 * totalValid / totalExamples).toStringAsFixed(1).padLeft(5);
 
-  print('${totalValid.toString().padLeft(countWidth)} '
+  sink.writeln('${totalValid.toString().padLeft(countWidth)} '
       'of ${totalExamples.toString().padLeft(countWidth)} '
       '– ${pct}%  TOTAL');
+
+  await sink.flush();
+  await sink.close();
 }
 
 /// Compare two DOM trees for equality.