blob: f1fc122fe60f7443e409ed428647ba80b36777d4 [file] [log] [blame]
// 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';
import '../source_code.dart';
import 'formatter_options.dart';
/// The kind of summary shown after all formatting is complete.
class Summary {
static const Summary none = Summary._();
/// Creates a Summary that tracks how many files were formatted and the total
/// time.
static Summary line() => _LineSummary();
/// Creates a Summary that captures profiling information.
///
/// Mostly for internal use.
static Summary profile() => _ProfileSummary();
const Summary._();
/// Called when [file] is about to be formatted.
///
/// If stdin is being formatted, then [file] is `null`.
void beforeFile(File? file, String displayPath) {}
/// Describe the processed file at [path] whose formatted result is [output].
///
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
///
/// If stdin is being formatted, then [file] is `null`.
void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
{required bool changed}) {}
void show() {}
}
/// Tracks how many files were formatted and the total time.
class _LineSummary extends Summary {
final DateTime _start = DateTime.now();
/// The number of processed files.
int _files = 0;
/// The number of changed files.
int _changed = 0;
_LineSummary() : super._();
/// Describe the processed file at [path] whose formatted result is [output].
///
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
@override
void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
{required bool changed}) {
_files++;
if (changed) _changed++;
}
/// Show the times for the slowest files to format.
@override
void show() {
var elapsed = DateTime.now().difference(_start);
var time = (elapsed.inMilliseconds / 1000).toStringAsFixed(2);
if (_files == 0) {
print('Formatted no files in $time seconds.');
} else if (_files == 1) {
print('Formatted $_files file ($_changed changed) in $time seconds.');
} else {
print('Formatted $_files files ($_changed changed) in $time seconds.');
}
}
}
/// Reports how long it took for format each file.
class _ProfileSummary implements Summary {
/// The files that have been started but have not completed yet.
///
/// Maps a file label to the time that it started being formatted.
final Map<String, DateTime> _ongoing = {};
/// The elapsed time it took to format each completed file.
final Map<String, Duration> _elapsed = {};
/// The number of files that completed so fast that they aren't worth
/// tracking.
int _elided = 0;
/// Show the times for the slowest files to format.
@override
void show() {
// Everything should be done.
assert(_ongoing.isEmpty);
var files = _elapsed.keys.toList();
files.sort((a, b) => _elapsed[b]!.compareTo(_elapsed[a]!));
for (var file in files) {
print('${_elapsed[file]}: $file');
}
if (_elided >= 1) {
var s = _elided > 1 ? 's' : '';
print('...$_elided more file$s each took less than 10ms.');
}
}
/// Called when [file] is about to be formatted.
@override
void beforeFile(File? file, String displayPath) {
_ongoing[displayPath] = DateTime.now();
}
/// Describe the processed file at [path] whose formatted result is [output].
///
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
@override
void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
{required bool changed}) {
var elapsed = DateTime.now().difference(_ongoing.remove(displayPath)!);
if (elapsed.inMilliseconds >= 10) {
_elapsed[displayPath] = elapsed;
} else {
_elided++;
}
}
}