Files
sdk/pkg/test_runner/lib/src/terminal.dart
T
Robert Nystrom f99631b12c Show human-readable output when an analyzer test fails.
After, what, five years? I finally got tired of reading pipe-separated
machine-readable fields in analyzer test failures. This parses that and
prints the failures in a sorted, human-friendly form.

Change-Id: I1e7761bff8d1ffaf1734d065ddaa1e624e4509d9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/147683
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
2020-05-14 02:08:06 +00:00

100 lines
2.9 KiB
Dart

// 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}) {
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();
}