blob: f9f19b61fb5913c977569eea76efd00eb878f67d [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 'package:nnbd_migration/src/utilities/source_edit_diff_formatter.dart';
/// Implementation of [SourceEditDiffOutput] for generating compact intra-line diffs.
class CompactOutput extends SourceEditDiffOutput {
final DiffStyleImpl style;
/// Output generated so far.
final List<String> _lines = [];
/// Accumulator for the current output line.
final _currentLine = StringBuffer();
/// True if the string in [_currentLine] indicates changes.
bool _pendingChanges = false;
/// The current line number, with reference to the original source text.
int _lineNum = 1;
CompactOutput(this.style) {
_writeLineHeader(true);
}
void addDeletedNewline() {
_flushLine();
_lineNum++;
_writeLineHeader(true);
}
void addDeletedText(String text) {
if (text.isNotEmpty) {
_currentLine.write(style.deleted(text));
_pendingChanges = true;
}
}
void addInsertedNewline() {
_flushLine();
_writeLineHeader(false);
}
void addInsertedText(String text) {
if (text.isNotEmpty) {
_currentLine.write(style.inserted(text));
_pendingChanges = true;
}
}
void addUnchangedText(String text) {
if (text.isNotEmpty) {
_currentLine.write(style.unchanged(text));
}
}
@override
List<String> finish() {
assert(!_pendingChanges);
return _lines;
}
void skipUnchangedNewlines(int count) {
_flushLine(suppressOutput: !_pendingChanges);
_lineNum += count;
_writeLineHeader(true);
}
void _flushLine({bool suppressOutput = false}) {
if (!suppressOutput) {
_lines.add(_currentLine.toString());
}
_currentLine.clear();
_pendingChanges = false;
}
void _writeLineHeader(bool includeLineNum) {
_currentLine.write(
style.lineHeader(includeLineNum ? _lineNum : null, '${style.bullet} '));
}
}
/// Abstract base class capable of generating diff output.
///
/// Clients shouldn't interact with this class directly; they should use
/// [DiffStyle.formatDiff] instead.
abstract class SourceEditDiffOutput {
void addDeletedNewline();
void addDeletedText(String text);
void addInsertedNewline();
void addInsertedText(String text);
void addUnchangedText(String text);
List<String> finish();
void skipUnchangedNewlines(int count);
}
/// Implementation of [SourceEditDiffOutput] for generating traditional diffs that show
/// before and after lines.
class TraditionalOutput extends SourceEditDiffOutput {
final DiffStyleImpl style;
/// Output generated so far.
final List<String> _lines = [];
/// Accumulator for the "after" lines in the current diff hunk.
final List<String> _afterLines = [];
/// Accumulator for the current "before" line.
final _currentBeforeLine = StringBuffer();
/// Accumulator for the current "after" line.
final _currentAfterLine = StringBuffer();
/// True if a hunk is currently in progress that represents changes.
bool _pendingChanges = false;
/// The current line number, with reference to the original source text.
int _lineNum = 1;
TraditionalOutput(this.style);
void addDeletedNewline() {
_flushBeforeLine();
_lineNum++;
if (_currentAfterLine.isEmpty) {
// After text is at a line break, so we can output pending changes
_outputPendingChanges();
}
}
void addDeletedText(String text) {
if (text.isNotEmpty) {
_currentBeforeLine.write(style.deleted(text));
_pendingChanges = true;
}
}
void addInsertedNewline() {
if (_currentBeforeLine.isEmpty) {
// Before text is at a line break, so we are adding a whole line
_flushAfterLine(includeLineNum: true);
_outputPendingChanges();
} else {
_flushAfterLine();
}
}
void addInsertedText(String text) {
if (text.isNotEmpty) {
_currentAfterLine.write(style.inserted(text));
_pendingChanges = true;
}
}
void addUnchangedText(String text) {
if (text.isNotEmpty) {
var styledText = style.unchanged(text);
_currentBeforeLine.write(styledText);
_currentAfterLine.write(styledText);
}
}
@override
List<String> finish() {
assert(!_pendingChanges);
assert(_afterLines.isEmpty);
return _lines;
}
void skipUnchangedNewlines(int count) {
_flushBeforeLine(suppressOutput: !_pendingChanges);
_flushAfterLine(suppressOutput: !_pendingChanges);
_outputPendingChanges();
_lineNum += count;
}
void _flushAfterLine(
{bool suppressOutput = false, bool includeLineNum = false}) {
if (!suppressOutput) {
_afterLines.add(style.lineHeader(includeLineNum ? _lineNum : null, '+') +
_currentAfterLine.toString());
}
_currentAfterLine.clear();
}
void _flushBeforeLine({bool suppressOutput = false}) {
if (!suppressOutput) {
_lines
.add(style.lineHeader(_lineNum, '-') + _currentBeforeLine.toString());
}
_currentBeforeLine.clear();
}
void _outputPendingChanges() {
_lines.addAll(_afterLines);
_afterLines.clear();
_pendingChanges = false;
}
}