Commit 9c2cdc89 authored by jkobus's avatar jkobus Committed by Jarek Kobus

DiffEditor: refactor internal structures.

Simplify the implementation a lot.

Change-Id: I3f5daa3d2ce14c28d48c2e1e996ec4935d1dae3f
Reviewed-by: default avatarJarek Kobus <jaroslaw.kobus@digia.com>
parent b76fb6ba
......@@ -133,15 +133,4 @@ QString DiffEditorPlugin::getFileContents(const QString &fileName) const
} // namespace Internal
} // namespace DiffEditor
#ifdef WITH_TESTS
#include "sidebysidediffeditorwidget.h"
void DiffEditor::Internal::DiffEditorPlugin::testFixPositions()
{
SideBySideDiffEditorWidget::testFixPositions();
}
#endif // WITH_TESTS
Q_EXPORT_PLUGIN(DiffEditor::Internal::DiffEditorPlugin)
......@@ -53,10 +53,6 @@ public:
private slots:
void diff();
#ifdef WITH_TESTS
void testFixPositions();
#endif // WITH_TESTS
private:
QString getFileContents(const QString &fileName) const;
......
......@@ -35,7 +35,7 @@
namespace DiffEditor {
namespace Internal {
static QList<TextLineData> assemblyRows(const QStringList &lines,
static QList<TextLineData> assemblyRows(const QList<TextLineData> &lines,
const QMap<int, int> &lineSpans)
{
QList<TextLineData> data;
......@@ -50,49 +50,51 @@ static QList<TextLineData> assemblyRows(const QStringList &lines,
return data;
}
static bool lastLinesEqual(const QStringList &leftLines,
const QStringList &rightLines)
static bool lastLinesEqual(const QList<TextLineData> &leftLines,
const QList<TextLineData> &rightLines)
{
const bool leftLineEqual = leftLines.count()
? leftLines.last().isEmpty()
? leftLines.last().text.isEmpty()
: true;
const bool rightLineEqual = rightLines.count()
? rightLines.last().isEmpty()
? rightLines.last().text.isEmpty()
: true;
return leftLineEqual && rightLineEqual;
}
static void handleLine(const QStringList &newLines,
int line,
QStringList *lines,
int *lineNumber,
int *charNumber)
QList<TextLineData> *lines,
int *lineNumber)
{
if (line < newLines.count()) {
const QString text = newLines.at(line);
if (lines->isEmpty() || line > 0) {
if (line > 0)
++*lineNumber;
lines->append(text);
lines->append(TextLineData(text));
} else {
lines->last() += text;
lines->last().text += text;
}
*charNumber += text.count();
}
}
static void handleDifference(const QString &text,
QStringList *lines,
QMap<int, int> *changedPositions,
int *lineNumber,
int *charNumber)
QList<TextLineData> *lines,
int *lineNumber)
{
const int oldPosition = *lineNumber + *charNumber;
const QStringList newLeftLines = text.split(QLatin1Char('\n'));
for (int line = 0; line < newLeftLines.count(); ++line)
handleLine(newLeftLines, line, lines, lineNumber, charNumber);
const int newPosition = *lineNumber + *charNumber;
changedPositions->insert(oldPosition, newPosition);
const QStringList newLines = text.split(QLatin1Char('\n'));
for (int line = 0; line < newLines.count(); ++line) {
const int startPos = line > 0
? -1
: lines->isEmpty() ? 0 : lines->last().text.count();
handleLine(newLines, line, lines, lineNumber);
const int endPos = line < newLines.count() - 1
? -1
: lines->isEmpty() ? 0 : lines->last().text.count();
if (!lines->isEmpty())
lines->last().changedPositions.insert(startPos, endPos);
}
}
/*
......@@ -108,8 +110,8 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
int i = 0;
int j = 0;
QStringList leftLines;
QStringList rightLines;
QList<TextLineData> leftLines;
QList<TextLineData> rightLines;
// <line number, span count>
QMap<int, int> leftSpans;
......@@ -119,8 +121,6 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
int leftLineNumber = 0;
int rightLineNumber = 0;
int leftCharNumber = 0;
int rightCharNumber = 0;
int leftLineAligned = -1;
int rightLineAligned = -1;
bool lastLineEqual = true;
......@@ -135,13 +135,13 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
if (leftDiff.command == Diff::Delete) {
// process delete
handleDifference(leftDiff.text, &leftLines, &chunkData.changedLeftPositions, &leftLineNumber, &leftCharNumber);
handleDifference(leftDiff.text, &leftLines, &leftLineNumber);
lastLineEqual = lastLinesEqual(leftLines, rightLines);
i++;
}
if (rightDiff.command == Diff::Insert) {
// process insert
handleDifference(rightDiff.text, &rightLines, &chunkData.changedRightPositions, &rightLineNumber, &rightCharNumber);
handleDifference(rightDiff.text, &rightLines, &rightLineNumber);
lastLineEqual = lastLinesEqual(leftLines, rightLines);
j++;
}
......@@ -153,8 +153,8 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
int line = 0;
while (line < qMax(newLeftLines.count(), newRightLines.count())) {
handleLine(newLeftLines, line, &leftLines, &leftLineNumber, &leftCharNumber);
handleLine(newRightLines, line, &rightLines, &rightLineNumber, &rightCharNumber);
handleLine(newLeftLines, line, &leftLines, &leftLineNumber);
handleLine(newRightLines, line, &rightLines, &rightLineNumber);
const int commonLineCount = qMin(newLeftLines.count(), newRightLines.count());
if (line < commonLineCount) {
......@@ -172,7 +172,7 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
if (line == commonLineCount - 1) {
// omit alignment when last lines of equalities are empty
if (leftLines.last().isEmpty() || rightLines.last().isEmpty())
if (leftLines.last().text.isEmpty() || rightLines.last().text.isEmpty())
doAlign = false;
// unless it's the last dummy line (don't omit in that case)
......@@ -283,72 +283,39 @@ FileData calculateContextData(const ChunkData &originalData, int contextLinesNum
}
}
i = 0;
int leftCharCounter = 0;
int rightCharCounter = 0;
QMap<int, int>::ConstIterator leftChangedIt = originalData.changedLeftPositions.constBegin();
QMap<int, int>::ConstIterator rightChangedIt = originalData.changedRightPositions.constBegin();
const QMap<int, int>::ConstIterator leftChangedItEnd = originalData.changedLeftPositions.constEnd();
const QMap<int, int>::ConstIterator rightChangedItEnd = originalData.changedRightPositions.constEnd();
while (i < originalData.rows.count()) {
if (!hiddenRows.contains(i)) {
ChunkData chunkData;
int leftOffset = leftCharCounter;
int rightOffset = rightCharCounter;
chunkData.contextChunk = false;
while (i < originalData.rows.count()) {
if (hiddenRows.contains(i))
break;
RowData rowData = originalData.rows.at(i);
chunkData.rows.append(rowData);
if (rowData.leftLine.textLineType == TextLineData::TextLine)
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
if (rowData.rightLine.textLineType == TextLineData::TextLine)
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
i++;
}
while (leftChangedIt != leftChangedItEnd) {
if (leftChangedIt.key() < leftOffset
|| leftChangedIt.key() > leftCharCounter)
break;
const int startPos = leftChangedIt.key();
const int endPos = leftChangedIt.value();
chunkData.changedLeftPositions.insert(startPos - leftOffset, endPos - leftOffset);
leftChangedIt++;
}
while (rightChangedIt != rightChangedItEnd) {
if (rightChangedIt.key() < rightOffset
|| rightChangedIt.key() > rightCharCounter)
break;
const int startPos = rightChangedIt.key();
const int endPos = rightChangedIt.value();
chunkData.changedRightPositions.insert(startPos - rightOffset, endPos - rightOffset);
rightChangedIt++;
}
fileData.chunks.append(chunkData);
} else {
ChunkData chunkData;
chunkData.contextChunk = true;
while (i < originalData.rows.count()) {
if (!hiddenRows.contains(i))
break;
RowData rowData = originalData.rows.at(i);
chunkData.rows.append(rowData);
if (rowData.leftLine.textLineType == TextLineData::TextLine)
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
if (rowData.rightLine.textLineType == TextLineData::TextLine)
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
i++;
}
fileData.chunks.append(chunkData);
const bool contextChunk = hiddenRows.contains(i);
ChunkData chunkData;
chunkData.contextChunk = contextChunk;
while (i < originalData.rows.count()) {
if (contextChunk != hiddenRows.contains(i))
break;
RowData rowData = originalData.rows.at(i);
chunkData.rows.append(rowData);
++i;
}
fileData.chunks.append(chunkData);
}
return fileData;
}
void addChangedPositions(int positionOffset, const QMap<int, int> &originalChangedPositions, QMap<int, int> *changedPositions)
{
QMapIterator<int, int> it(originalChangedPositions);
while (it.hasNext()) {
it.next();
const int startPos = it.key();
const int endPos = it.value();
const int newStartPos = startPos < 0 ? -1 : startPos + positionOffset;
const int newEndPos = endPos < 0 ? -1 : endPos + positionOffset;
if (startPos < 0 && !changedPositions->isEmpty())
changedPositions->insert(changedPositions->lastKey(), newEndPos);
else
changedPositions->insert(newStartPos, newEndPos);
}
}
QList<QTextEdit::ExtraSelection> colorPositions(
const QTextCharFormat &format,
QTextCursor &cursor,
......
......@@ -57,6 +57,13 @@ public:
TextLineData(TextLineType t) : textLineType(t) {}
TextLineType textLineType;
QString text;
/*
* <start position, end position>
* <-1, n> means this is a continuation from the previous line
* <n, -1> means this will be continued in the next line
* <-1, -1> the whole line is a continuation (from the previous line to the next line)
*/
QMap<int, int> changedPositions; // counting from the beginning of the line
};
class RowData {
......@@ -76,9 +83,6 @@ public:
ChunkData() : contextChunk(false) {}
QList<RowData> rows;
bool contextChunk;
// start position, end position, TextLineData::Separator lines not taken into account
QMap<int, int> changedLeftPositions; // counting from the beginning of the chunk
QMap<int, int> changedRightPositions; // counting from the beginning of the chunk
};
class FileData {
......@@ -94,6 +98,9 @@ ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
const QList<Diff> &rightDiffList);
FileData calculateContextData(const ChunkData &originalData,
int contextLinesNumber);
void addChangedPositions(int positionOffset,
const QMap<int, int> &originalChangedPositions,
QMap<int, int> *changedPositions);
QList<QTextEdit::ExtraSelection> colorPositions(const QTextCharFormat &format,
QTextCursor &cursor,
const QMap<int, int> &positions);
......
......@@ -1037,86 +1037,6 @@ void SideBySideDiffEditorWidget::showDiff()
m_rightEditor->updateFoldingHighlight(QPoint(-1, -1));
}
static void fixPositions(QMap<int, int>::ConstIterator *it,
const QMap<int, int>::ConstIterator &itEnd,
int fileOffset,
int charCounter,
int spanCounter,
int *lastSpanCounter,
QMap<int, int> *changedPositions)
{
while (*it != itEnd) {
if (it->key() >= charCounter)
break;
if (it->value() >= charCounter) {
if (*lastSpanCounter != -1)
break;
*lastSpanCounter = spanCounter;
break;
}
const int startSpanOffset = *lastSpanCounter != -1
? *lastSpanCounter : spanCounter;
*lastSpanCounter = -1;
const int startPos = it->key() + startSpanOffset + fileOffset;
const int endPos = it->value() + spanCounter + fileOffset;
changedPositions->insert(startPos, endPos);
++(*it);
}
}
static void fixPositions(const ChunkData &chunkData,
const int leftFileOffset,
const int rightFileOffset,
QMap<int, int> *leftCharPos,
QMap<int, int> *rightCharPos)
{
QMap<int, int>::ConstIterator leftIt = chunkData.changedLeftPositions.constBegin();
const QMap<int, int>::ConstIterator leftItEnd = chunkData.changedLeftPositions.constEnd();
QMap<int, int>::ConstIterator rightIt = chunkData.changedRightPositions.constBegin();
const QMap<int, int>::ConstIterator rightItEnd = chunkData.changedRightPositions.constEnd();
if (leftIt == leftItEnd && rightIt == rightItEnd)
return;
int leftCharCounter = 0;
int rightCharCounter = 0;
int leftSpanCounter = 0;
int rightSpanCounter = 0;
int leftLastSpanCounter = -1;
int rightLastSpanCounter = -1;
for (int i = 0; i < chunkData.rows.count(); i++) {
const RowData &row = chunkData.rows.at(i);
if (row.leftLine.textLineType == TextLineData::TextLine)
leftCharCounter += row.leftLine.text.count() + 1; // +1 for '\n'
else
++leftSpanCounter;
if (row.rightLine.textLineType == TextLineData::TextLine)
rightCharCounter += row.rightLine.text.count() + 1; // +1 for '\n'
else
++rightSpanCounter;
fixPositions(&leftIt,
leftItEnd,
leftFileOffset,
leftCharCounter,
leftSpanCounter,
&leftLastSpanCounter,
leftCharPos);
fixPositions(&rightIt,
rightItEnd,
rightFileOffset,
rightCharCounter,
rightSpanCounter,
&rightLastSpanCounter,
rightCharPos);
}
}
void SideBySideDiffEditorWidget::colorDiff(const QList<FileData> &fileDataList)
{
QPalette pal = m_leftEditor->extraArea()->palette();
......@@ -1144,31 +1064,30 @@ void SideBySideDiffEditorWidget::colorDiff(const QList<FileData> &fileDataList)
int rightLastSkippedBlockStartPos = 0;
for (int i = 0; i < fileDataList.count(); i++) {
const FileData &fileData = fileDataList.at(i);
leftFilePos[leftPos] = leftPos + 1;
rightFilePos[rightPos] = rightPos + 1;
leftPos++; // for file line
rightPos++; // for file line
const FileData &fileData = fileDataList.at(i);
for (int j = 0; j < fileData.chunks.count(); j++) {
ChunkData chunkData = fileData.chunks.at(j);
const ChunkData &chunkData = fileData.chunks.at(j);
if (chunkData.contextChunk) {
leftChunkPos[leftPos] = leftPos + 1;
rightChunkPos[rightPos] = rightPos + 1;
leftPos++; // for chunk line
rightPos++; // for chunk line
}
const int leftFileOffset = leftPos;
const int rightFileOffset = rightPos;
leftLastDiffBlockStartPos = leftPos;
rightLastDiffBlockStartPos = rightPos;
leftLastSkippedBlockStartPos = leftPos;
rightLastSkippedBlockStartPos = rightPos;
fixPositions(chunkData, leftFileOffset, rightFileOffset, &leftCharPos, &rightCharPos);
for (int k = 0; k < chunkData.rows.count(); k++) {
RowData rowData = chunkData.rows.at(k);
const RowData &rowData = chunkData.rows.at(k);
addChangedPositions(leftPos, rowData.leftLine.changedPositions, &leftCharPos);
addChangedPositions(rightPos, rowData.rightLine.changedPositions, &rightCharPos);
leftPos += rowData.leftLine.text.count() + 1; // +1 for '\n'
rightPos += rowData.rightLine.text.count() + 1; // +1 for '\n'
......@@ -1203,23 +1122,23 @@ void SideBySideDiffEditorWidget::colorDiff(const QList<FileData> &fileDataList)
QList<QTextEdit::ExtraSelection> leftSelections
= colorPositions(m_leftLineFormat, leftCursor, leftLinePos);
leftSelections
+= colorPositions(spanLineFormat, leftCursor, leftSkippedPos);
leftSelections
+= colorPositions(m_chunkLineFormat, leftCursor, leftChunkPos);
leftSelections
+= colorPositions(m_fileLineFormat, leftCursor, leftFilePos);
leftSelections
+= colorPositions(spanLineFormat, leftCursor, leftSkippedPos);
leftSelections
+= colorPositions(m_leftCharFormat, leftCursor, leftCharPos);
QList<QTextEdit::ExtraSelection> rightSelections
= colorPositions(m_rightLineFormat, rightCursor, rightLinePos);
rightSelections
+= colorPositions(spanLineFormat, rightCursor, rightSkippedPos);
rightSelections
+= colorPositions(m_chunkLineFormat, rightCursor, rightChunkPos);
rightSelections
+= colorPositions(m_fileLineFormat, rightCursor, rightFilePos);
rightSelections
+= colorPositions(spanLineFormat, rightCursor, rightSkippedPos);
rightSelections
+= colorPositions(m_rightCharFormat, rightCursor, rightCharPos);
......@@ -1485,44 +1404,6 @@ void SideBySideDiffEditorWidget::synchronizeFoldings(SideDiffEditorWidget *sourc
m_foldingBlocker = false;
}
} // namespace DiffEditor
#ifdef WITH_TESTS
#include <QTest>
void DiffEditor::SideBySideDiffEditorWidget::testFixPositions()
{
ChunkData chunkData;
chunkData.rows.append(RowData(TextLineData(QLatin1String("abcd efgh")), TextLineData(QLatin1String("abcd "))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))));
chunkData.rows.append(RowData(TextLineData(QLatin1String("ijkl mnop")), TextLineData(QLatin1String(" mnop"))));
chunkData.changedLeftPositions.insert(5, 14); // changed text from position 5 to position 14, occupy 9 characters: "efgh\nijkl"
QMap<int, int> expectedLeftChangedPositions;
expectedLeftChangedPositions[5] = 20; // "efgh\n[\n\n\n\n\n\n]ijkl" - [\n] means inserted span
QMap<int, int> outputLeftChangedPositions;
QMap<int, int> outputRightChangedPositions;
fixPositions(chunkData, 0, 0, &outputLeftChangedPositions, &outputRightChangedPositions);
QVERIFY(outputLeftChangedPositions == expectedLeftChangedPositions);
QMap<int, int> expectedLeftMovedPositions;
expectedLeftMovedPositions[15] = 30; // moved by 10
outputLeftChangedPositions.clear();
outputRightChangedPositions.clear();
fixPositions(chunkData, 10, 0, &outputLeftChangedPositions, &outputRightChangedPositions);
QVERIFY(outputLeftChangedPositions == expectedLeftMovedPositions);
}
#endif // WITH_TESTS
#include "sidebysidediffeditorwidget.moc"
......@@ -62,10 +62,6 @@ public:
void setDiffEditorGuiController(DiffEditorGuiController *controller);
DiffEditorGuiController *diffEditorGuiController() const;
#ifdef WITH_TESTS
static void testFixPositions();
#endif // WITH_TESTS
private slots:
void clear(const QString &message = QString());
void setDiff(const QList<DiffEditorController::DiffFilesContents> &diffFileList, const QString &workingDirectory);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment