Chromium Code Reviews| Index: pkg/status_file/lib/status_file.dart |
| diff --git a/pkg/status_file/lib/status_file.dart b/pkg/status_file/lib/status_file.dart |
| index 067fce120eb4d70cfff4cd32d62fee724e1a5cd0..debc28fb2576ff8d2864a529f77f4e6b1965af0a 100644 |
| --- a/pkg/status_file/lib/status_file.dart |
| +++ b/pkg/status_file/lib/status_file.dart |
| @@ -45,6 +45,9 @@ final _issuePattern = new RegExp(r"[Ii]ssue (\d+)"); |
| class StatusFile { |
| final String path; |
| final List<StatusSection> sections = []; |
| + final List<String> _comments = []; |
| + |
| + int _lineCount = 0; |
| StatusFile(this.path); |
| @@ -53,17 +56,16 @@ class StatusFile { |
| /// Throws a [SyntaxError] if the file could not be parsed. |
| StatusFile.read(this.path) { |
| var lines = new File(path).readAsLinesSync(); |
| + _comments.length = lines.length + 1; |
| // The current section whose rules are being parsed. |
| StatusSection section; |
| - var lineNumber = 0; |
| - |
| for (var line in lines) { |
| - lineNumber++; |
| + _lineCount++; |
| fail(String message, [List<String> errors]) { |
| - throw new SyntaxError(_shortPath, lineNumber, line, message, errors); |
| + throw new SyntaxError(_shortPath, _lineCount, line, message, errors); |
| } |
| // Strip off the comment and whitespace. |
| @@ -72,7 +74,8 @@ class StatusFile { |
| var hashIndex = line.indexOf('#'); |
| if (hashIndex >= 0) { |
| source = line.substring(0, hashIndex); |
| - comment = line.substring(hashIndex); |
| + comment = line.substring(hashIndex + 1); |
| + _comments[_lineCount] = comment; |
| } |
| source = source.trim(); |
| @@ -84,7 +87,7 @@ class StatusFile { |
| if (match != null) { |
| try { |
| var condition = Expression.parse(match[1].trim()); |
| - section = new StatusSection(condition, lineNumber); |
| + section = new StatusSection(condition, _lineCount); |
| sections.add(section); |
| } on FormatException { |
| fail("Status expression syntax error"); |
| @@ -117,7 +120,7 @@ class StatusFile { |
| } |
| section.entries |
| - .add(new StatusEntry(path, lineNumber, expectations, issue)); |
| + .add(new StatusEntry(path, _lineCount, expectations, issue)); |
| continue; |
| } |
| @@ -178,6 +181,70 @@ class StatusFile { |
| return buffer.toString(); |
| } |
| + |
| + /// Serialize the status file to a string. |
| + /// |
| + /// Unlike [toString()], this preserves comments and gives a "canonical" |
| + /// rendering of the status file that can be saved back to disc. |
| + String serialize() { |
| + var buffer = new StringBuffer(); |
| + |
| + var lastLine = 0; |
| + var needBlankLine = false; |
| + |
| + void writeLine(String text, int line) { |
| + var comment = _comments[line]; |
| + if (text == null && comment == null) { |
| + // There's no comment on this line, so it's blank. |
| + needBlankLine = true; |
| + return; |
| + } |
| + |
| + if (needBlankLine) buffer.writeln(); |
| + needBlankLine = false; |
| + |
| + if (text != null) { |
| + buffer.write(text); |
| + } |
| + |
| + if (comment != null) { |
| + if (text != null) buffer.write(" "); |
| + buffer.write("#$comment"); |
| + } |
| + |
| + buffer.writeln(); |
| + } |
| + |
| + void writeText(String text, int line) { |
| + if (line != null) { |
| + while (++lastLine < line) { |
| + writeLine(null, lastLine); |
| + } |
| + } |
| + |
| + writeLine(text, line); |
| + } |
| + |
| + for (var section in sections) { |
| + if (section.condition != null) { |
| + writeText("[ ${section.condition} ]", section.lineNumber); |
| + } |
| + |
| + for (var entry in section.entries) { |
|
Bill Hesse
2017/08/03 14:24:07
Not in the printing, but as a separate stage, I th
Bob Nystrom
2017/08/03 20:28:49
Yeah, I thought of that after I sent this out. I m
|
| + writeText("${entry.path}: ${entry.expectations.join(', ')}", |
| + entry.lineNumber); |
| + } |
| + |
| + needBlankLine = true; |
| + } |
| + |
| + // Write any trailing comments. |
| + while (++lastLine <= _lineCount) { |
| + writeLine(null, lastLine); |
| + } |
| + |
| + return buffer.toString(); |
| + } |
| } |
| /// One section in a status file. |