Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Unified Diff: packages/cli_util/lib/cli_logging.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « packages/cli_util/example/main.dart ('k') | packages/cli_util/lib/cli_util.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/cli_util/lib/cli_logging.dart
diff --git a/packages/cli_util/lib/cli_logging.dart b/packages/cli_util/lib/cli_logging.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2da62ca723ad9fe374815793ebfcd9ae77c97774
--- /dev/null
+++ b/packages/cli_util/lib/cli_logging.dart
@@ -0,0 +1,273 @@
+// Copyright (c) 2017, 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.
+
+/// This library contains functionality to help command-line utilities to easily
+/// create aesthetic output.
+library cli_logging;
+
+import 'dart:async';
+import 'dart:io' as io;
+
+/// A small utility class to make it easier to work with common ANSI escape
+/// sequences.
+class Ansi {
+ /// Return whether the current stdout terminal supports ANSI escape sequences.
+ static bool get terminalSupportsAnsi {
+ return io.stdout.supportsAnsiEscapes &&
+ io.stdioType(io.stdout) == io.StdioType.TERMINAL;
+ }
+
+ final bool useAnsi;
+
+ Ansi(this.useAnsi);
+
+ String get cyan => _code('\u001b[36m');
+ String get green => _code('\u001b[32m');
+ String get magenta => _code('\u001b[35m');
+ String get red => _code('\u001b[31m');
+ String get yellow => _code('\u001b[33m');
+ String get blue => _code('\u001b[34m');
+ String get gray => _code('\u001b[1;30m');
+ String get noColor => _code('\u001b[39m');
+
+ String get none => _code('\u001b[0m');
+
+ String get bold => _code('\u001b[1m');
+
+ String get backspace => '\b';
+
+ String get bullet => io.stdout.supportsAnsiEscapes ? '•' : '-';
+
+ /// Display [message] in an emphasized format.
+ String emphasized(String message) => '$bold$message$none';
+
+ /// Display [message] in an subtle (gray) format.
+ String subtle(String message) => '$gray$message$none';
+
+ /// Display [message] in an error (red) format.
+ String error(String message) => '$red$message$none';
+
+ String _code(String ansiCode) => useAnsi ? ansiCode : '';
+}
+
+/// An abstract representation of a [Logger] - used to pretty print errors,
+/// standard status messages, trace level output, and indeterminate progress.
+abstract class Logger {
+ /// Create a normal [Logger]; this logger will not display trace level output.
+ factory Logger.standard({Ansi ansi}) => new _StandardLogger(ansi: ansi);
+
+ /// Create a [Logger] that will display trace level output.
+ factory Logger.verbose({Ansi ansi}) => new _VerboseLogger(ansi: ansi);
+
+ Ansi get ansi;
+
+ bool get isVerbose;
+
+ /// Print an error message.
+ void stderr(String message);
+
+ /// Print a standard status message.
+ void stdout(String message);
+
+ /// Print trace output.
+ void trace(String message);
+
+ /// Start an indeterminate progress display.
+ Progress progress(String message);
+ void _progressFinished(Progress progress);
+
+ /// Flush any un-written output.
+ void flush();
+}
+
+/// A handle to an indeterminate progress display.
+abstract class Progress {
+ final String message;
+ final Stopwatch _stopwatch;
+
+ Progress._(this.message) : _stopwatch = new Stopwatch()..start();
+
+ Duration get elapsed => _stopwatch.elapsed;
+
+ /// Finish the indeterminate progress display.
+ void finish({String message, bool showTiming});
+
+ /// Cancel the indeterminate progress display.
+ void cancel();
+}
+
+class _StandardLogger implements Logger {
+ Ansi ansi;
+
+ _StandardLogger({this.ansi}) {
+ ansi ??= new Ansi(Ansi.terminalSupportsAnsi);
+ }
+
+ bool get isVerbose => false;
+
+ Progress _currentProgress;
+
+ void stderr(String message) {
+ io.stderr.writeln(message);
+ _currentProgress?.cancel();
+ _currentProgress = null;
+ }
+
+ void stdout(String message) {
+ print(message);
+ _currentProgress?.cancel();
+ _currentProgress = null;
+ }
+
+ void trace(String message) {}
+
+ Progress progress(String message) {
+ _currentProgress?.cancel();
+ _currentProgress = null;
+
+ Progress progress = ansi.useAnsi
+ ? new _AnsiProgress(this, ansi, message)
+ : new _SimpleProgress(this, message);
+ _currentProgress = progress;
+ return progress;
+ }
+
+ void _progressFinished(Progress progress) {
+ if (_currentProgress == progress) {
+ _currentProgress = null;
+ }
+ }
+
+ void flush() {}
+}
+
+class _SimpleProgress extends Progress {
+ final Logger logger;
+
+ _SimpleProgress(this.logger, String message) : super._(message) {
+ logger.stdout('$message...');
+ }
+
+ @override
+ void cancel() {
+ logger._progressFinished(this);
+ }
+
+ @override
+ void finish({String message, bool showTiming}) {
+ logger._progressFinished(this);
+ }
+}
+
+class _AnsiProgress extends Progress {
+ static const List<String> kAnimationItems = const ['/', '-', '\\', '|'];
+
+ final Logger logger;
+ final Ansi ansi;
+
+ int _index = 0;
+ Timer _timer;
+
+ _AnsiProgress(this.logger, this.ansi, String message) : super._(message) {
+ io.stdout.write('${message}... '.padRight(40));
+
+ _timer = new Timer.periodic(new Duration(milliseconds: 80), (t) {
+ _index++;
+ _updateDisplay();
+ });
+
+ _updateDisplay();
+ }
+
+ @override
+ void cancel() {
+ if (_timer.isActive) {
+ _timer.cancel();
+ _updateDisplay(cancelled: true);
+ logger._progressFinished(this);
+ }
+ }
+
+ @override
+ void finish({String message, bool showTiming: false}) {
+ if (_timer.isActive) {
+ _timer.cancel();
+ _updateDisplay(isFinal: true, message: message, showTiming: showTiming);
+ logger._progressFinished(this);
+ }
+ }
+
+ void _updateDisplay(
+ {bool isFinal: false,
+ bool cancelled: false,
+ String message,
+ bool showTiming: false}) {
+ String char = kAnimationItems[_index % kAnimationItems.length];
+ if (isFinal || cancelled) {
+ char = '';
+ }
+ io.stdout.write('${ansi.backspace}${char}');
+ if (isFinal || cancelled) {
+ if (message != null) {
+ io.stdout.write(message.isEmpty ? ' ' : message);
+ } else if (showTiming) {
+ String time = (elapsed.inMilliseconds / 1000.0).toStringAsFixed(1);
+ io.stdout.write('${time}s');
+ } else {
+ io.stdout.write(' ');
+ }
+ io.stdout.writeln();
+ }
+ }
+}
+
+class _VerboseLogger implements Logger {
+ Ansi ansi;
+ Stopwatch _timer;
+
+ String _previousErr;
+ String _previousMsg;
+
+ _VerboseLogger({this.ansi}) {
+ ansi ??= new Ansi(Ansi.terminalSupportsAnsi);
+ _timer = new Stopwatch()..start();
+ }
+
+ bool get isVerbose => true;
+
+ void stderr(String message) {
+ flush();
+ _previousErr = '${ansi.red}$message${ansi.none}';
+ }
+
+ void stdout(String message) {
+ flush();
+ _previousMsg = message;
+ }
+
+ void trace(String message) {
+ flush();
+ _previousMsg = '${ansi.gray}$message${ansi.none}';
+ }
+
+ Progress progress(String message) => new _SimpleProgress(this, message);
+
+ void _progressFinished(Progress progress) {}
+
+ void flush() {
+ if (_previousErr != null) {
+ io.stderr.writeln('${_createTag()} $_previousErr');
+ _previousErr = null;
+ } else if (_previousMsg != null) {
+ io.stdout.writeln('${_createTag()} $_previousMsg');
+ _previousMsg = null;
+ }
+ }
+
+ String _createTag() {
+ int millis = _timer.elapsedMilliseconds;
+ _timer.reset();
+ return '[${millis.toString().padLeft(4)} ms]';
+ }
+}
« no previous file with comments | « packages/cli_util/example/main.dart ('k') | packages/cli_util/lib/cli_util.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698