| // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:io'; | |
| // TODO(rnystrom): Move all print calls to go through this. Unify with DebugLog. | |
| /// Interface for the test runner printing output to the user. | |
| /// | |
| /// It mainly exists to gracefully handle the inline progress indicator: | |
| /// | |
| /// [00:08 | 100% | + 139 | - 3] | |
| /// | |
| /// That does not print a newline at the end, but subsequent output should | |
| /// insert the newline before writing itself. This tracks whether that needs to | |
| /// be done. | |
| class Terminal { | |
| static bool _needsNewline = false; | |
| /// Prints [obj] to its own line. | |
| /// | |
| /// If this is called after a call to [writeLine], prints a newline first to | |
| /// end that earlier line. | |
| static void print(Object obj) { | |
| finishLine(); | |
| stdout.writeln(obj); | |
| } | |
| /// Overwrites the current line with [obj]. | |
| /// | |
| /// Does not output a newline at the end. | |
| static void writeLine(Object obj) { | |
| stdout.write('\r$obj'); | |
| _needsNewline = true; | |
| } | |
| /// If the last output was from [writeLine], finishes it by writing a newline. | |
| static void finishLine() { | |
| if (_needsNewline) stdout.writeln(); | |
| _needsNewline = false; | |
| } | |
| } | |
| /// The maximum line length for output. | |
| /// | |
| /// If the test runner isn't attached to a terminal, defaults to 80 columns. | |
| final int _lineLength = () { | |
| try { | |
| return stdout.terminalColumns; | |
| } on StdoutException { | |
| return 80; | |
| } | |
| }(); | |
| /// Wraps [text] so that it fits within [_lineLength], if there is a line length. | |
| /// | |
| /// This preserves existing newlines and only splits words on spaces, not on | |
| /// other sorts of whitespace or separators. | |
| /// | |
| /// If [prefix] is passed, it's added at the beginning of any wrapped lines. | |
| String wordWrap(String text, {String prefix = ''}) { | |
| var buffer = StringBuffer(); | |
| var originalLines = text.split('\n'); | |
| var lengthSoFar = 0; | |
| var needsNewline = false; | |
| var needsSpace = false; | |
| for (var i = 0; i < originalLines.length; i++) { | |
| var originalLine = originalLines[i]; | |
| for (var word in originalLine.split(' ')) { | |
| // If this word would push us over, split before it. | |
| if (lengthSoFar + 1 + word.length > _lineLength) needsNewline = true; | |
| if (needsNewline) { | |
| buffer.writeln(); | |
| buffer.write(prefix); | |
| lengthSoFar = prefix.length; | |
| needsSpace = false; | |
| } else if (needsSpace) { | |
| buffer.write(' '); | |
| lengthSoFar++; | |
| } | |
| buffer.write(word); | |
| lengthSoFar += word.length; | |
| // If the single word fills the entire line, we need to wrap after it too. | |
| needsNewline = lengthSoFar > _lineLength; | |
| needsSpace = !needsNewline; | |
| } | |
| if (needsNewline) buffer.writeln(); | |
| needsNewline = true; | |
| } | |
| return buffer.toString(); | |
| } |