diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 0d6ad83df024dafbfb4c7bfba13a9c1655e04d53..699b4716c17fa1598d8726ec283011475cbb7fd2 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -240,13 +240,26 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() rows << RowData(TextLineData(QLatin1String("ABCD")), TextLineData(TextLineData::Separator)); rows << RowData(TextLineData(QLatin1String("EFGH"))); - rows << RowData(TextLineData(QLatin1String(""))); ChunkData chunk; chunk.rows = rows; QString patchText = header + QLatin1String("@@ -1,2 +1,1 @@\n" "-ABCD\n" " EFGH\n"); - QTest::newRow("Simple") << chunk + QTest::newRow("Simple not a last chunk") << chunk + << fileName + << fileName + << false + << patchText; + + /////////// + + // chunk the same here + patchText = header + QLatin1String("@@ -1,2 +1,1 @@\n" + "-ABCD\n" + " EFGH\n" + "\\ No newline at end of file\n"); + + QTest::newRow("Simple last chunk") << chunk << fileName << fileName << true @@ -255,8 +268,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() /////////// rows.clear(); - rows << RowData(TextLineData(QLatin1String("ABCD")), - TextLineData(QLatin1String("ABCD"))); + rows << RowData(TextLineData(QLatin1String("ABCD"))); rows << RowData(TextLineData(QLatin1String("")), TextLineData(TextLineData::Separator)); chunk.rows = rows; @@ -265,7 +277,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() "+ABCD\n" "\\ No newline at end of file\n"); - QTest::newRow("Last newline removed") << chunk + QTest::newRow("EOL in last line removed") << chunk << fileName << fileName << true @@ -275,11 +287,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() // chunk the same here patchText = header + QLatin1String("@@ -1,2 +1,1 @@\n" - "-ABCD\n" - "-\n" - "+ABCD\n"); + " ABCD\n" + "-\n"); - QTest::newRow("Not a last newline removed") << chunk + QTest::newRow("Last empty line removed") << chunk << fileName << fileName << false @@ -288,8 +299,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() /////////// rows.clear(); - rows << RowData(TextLineData(QLatin1String("ABCD")), - TextLineData(QLatin1String("ABCD"))); + rows << RowData(TextLineData(QLatin1String("ABCD"))); rows << RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String(""))); chunk.rows = rows; @@ -298,7 +308,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() "\\ No newline at end of file\n" "+ABCD\n"); - QTest::newRow("Last newline added") << chunk + QTest::newRow("EOL to last line added") << chunk << fileName << fileName << true @@ -308,11 +318,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() // chunk the same here patchText = header + QLatin1String("@@ -1,1 +1,2 @@\n" - "-ABCD\n" - "+ABCD\n" + " ABCD\n" "+\n"); - QTest::newRow("Not a last newline added") << chunk + QTest::newRow("Last empty line added") << chunk << fileName << fileName << false @@ -323,7 +332,6 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() rows.clear(); rows << RowData(TextLineData(QLatin1String("ABCD")), TextLineData(QLatin1String("EFGH"))); - rows << RowData(TextLineData(QLatin1String(""))); chunk.rows = rows; patchText = header + QLatin1String("@@ -1,1 +1,1 @@\n" "-ABCD\n" @@ -332,12 +340,16 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch_data() QTest::newRow("Last line with a newline modified") << chunk << fileName << fileName - << true + << false << patchText; /////////// - // chunk the same here + rows.clear(); + rows << RowData(TextLineData(QLatin1String("ABCD")), + TextLineData(QLatin1String("EFGH"))); + rows << RowData(TextLineData(QLatin1String(""))); + chunk.rows = rows; patchText = header + QLatin1String("@@ -1,2 +1,2 @@\n" "-ABCD\n" "+EFGH\n" @@ -424,7 +436,35 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch() QString result = DiffUtils::makePatch(sourceChunk, leftFileName, rightFileName, lastChunk); - QCOMPARE(patchText, result); + QCOMPARE(result, patchText); + + bool ok; + QList<FileData> resultList = DiffUtils::readPatch(result, false, &ok); + + QVERIFY(ok); + QCOMPARE(resultList.count(), 1); + for (int i = 0; i < resultList.count(); i++) { + const FileData &resultFileData = resultList.at(i); + QCOMPARE(resultFileData.leftFileInfo.fileName, leftFileName); + QCOMPARE(resultFileData.rightFileInfo.fileName, rightFileName); + QCOMPARE(resultFileData.chunks.count(), 1); + for (int j = 0; j < resultFileData.chunks.count(); j++) { + const ChunkData &resultChunkData = resultFileData.chunks.at(j); + QCOMPARE(resultChunkData.leftStartingLineNumber, sourceChunk.leftStartingLineNumber); + QCOMPARE(resultChunkData.rightStartingLineNumber, sourceChunk.rightStartingLineNumber); + QCOMPARE(resultChunkData.contextChunk, sourceChunk.contextChunk); + QCOMPARE(resultChunkData.rows.count(), sourceChunk.rows.count()); + for (int k = 0; k < sourceChunk.rows.count(); k++) { + const RowData &sourceRowData = sourceChunk.rows.at(k); + const RowData &resultRowData = resultChunkData.rows.at(k); + QCOMPARE(resultRowData.equal, sourceRowData.equal); + QCOMPARE(resultRowData.leftLine.text, sourceRowData.leftLine.text); + QCOMPARE(resultRowData.leftLine.textLineType, sourceRowData.leftLine.textLineType); + QCOMPARE(resultRowData.rightLine.text, sourceRowData.rightLine.text); + QCOMPARE(resultRowData.rightLine.textLineType, sourceRowData.rightLine.textLineType); + } + } + } } void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data() @@ -614,11 +654,74 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data() fileData8.rightFileInfo = DiffFileInfo(QLatin1String("file b.txt")); fileData8.fileOperation = FileData::RenameFile; - QList<FileData> fileDataList; - fileDataList << fileData1 << fileData2 << fileData3 << fileData4 << fileData5 << fileData6 << fileData7 << fileData8; + QList<FileData> fileDataList1; + fileDataList1 << fileData1 << fileData2 << fileData3 << fileData4 << fileData5 << fileData6 << fileData7 << fileData8; QTest::newRow("Git patch") << patch - << fileDataList; + << fileDataList1; + + ////////////// + + patch = QLatin1String("diff --git a/file foo.txt b/file foo.txt\n" + "index 1234567..9876543 100644\n" + "--- a/file foo.txt\n" + "+++ b/file foo.txt\n" + "@@ -50,4 +50,5 @@ void DiffEditor::ctor()\n" + " A\n" + " B\n" + " C\n" + "+\n"); + + fileData1.leftFileInfo = DiffFileInfo(QLatin1String("file foo.txt"), QLatin1String("1234567")); + fileData1.rightFileInfo = DiffFileInfo(QLatin1String("file foo.txt"), QLatin1String("9876543")); + fileData1.fileOperation = FileData::ChangeFile; + chunkData1.leftStartingLineNumber = 49; + chunkData1.rightStartingLineNumber = 49; + rows1.clear(); + rows1.append(RowData(TextLineData(QLatin1String("A")))); + rows1.append(RowData(TextLineData(QLatin1String("B")))); + rows1.append(RowData(TextLineData(QLatin1String("C")))); + rows1.append(RowData(TextLineData(TextLineData::Separator), + TextLineData(QLatin1String("")))); + chunkData1.rows = rows1; + fileData1.chunks.clear(); + fileData1.chunks.append(chunkData1); + + QList<FileData> fileDataList2; + fileDataList2 << fileData1; + + QTest::newRow("Added line") << patch + << fileDataList2; + + ////////////// + + patch = QLatin1String("diff --git a/file foo.txt b/file foo.txt\n" + "index 1234567..9876543 100644\n" + "--- a/file foo.txt\n" + "+++ b/file foo.txt\n" + "@@ -1,1 +1,1 @@\n" + "-ABCD\n" + "\\ No newline at end of file\n" + "+ABCD\n"); + + fileData1.leftFileInfo = DiffFileInfo(QLatin1String("file foo.txt"), QLatin1String("1234567")); + fileData1.rightFileInfo = DiffFileInfo(QLatin1String("file foo.txt"), QLatin1String("9876543")); + fileData1.fileOperation = FileData::ChangeFile; + chunkData1.leftStartingLineNumber = 0; + chunkData1.rightStartingLineNumber = 0; + rows1.clear(); + rows1.append(RowData(TextLineData(QLatin1String("ABCD")))); + rows1.append(RowData(TextLineData(TextLineData::Separator), + TextLineData(QLatin1String("")))); + chunkData1.rows = rows1; + fileData1.chunks.clear(); + fileData1.chunks.append(chunkData1); + + QList<FileData> fileDataList3; + fileDataList3 << fileData1; + + QTest::newRow("Last newline added to a line without newline") << patch + << fileDataList3; } void DiffEditor::Internal::DiffEditorPlugin::testReadPatch() diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index 18725363fb357f597817e062b35bb4b5c358e676..f975462c47eaf0eb86d64d09a0a3ac04cadad2db 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -131,15 +131,23 @@ ChunkData DiffUtils::calculateOriginalData(const QList<Diff> &leftDiffList, : Diff(Diff::Equal); if (leftDiff.command == Diff::Delete) { + if (j == rightDiffList.count() && lastLineEqual && leftDiff.text.startsWith(QLatin1Char('\n'))) + equalLines.insert(leftLineNumber, rightLineNumber); // process delete handleDifference(leftDiff.text, &leftLines, &leftLineNumber); lastLineEqual = lastLinesEqual(leftLines, rightLines); + if (j == rightDiffList.count()) + lastLineEqual = false; i++; } if (rightDiff.command == Diff::Insert) { + if (i == leftDiffList.count() && lastLineEqual && rightDiff.text.startsWith(QLatin1Char('\n'))) + equalLines.insert(leftLineNumber, rightLineNumber); // process insert handleDifference(rightDiff.text, &rightLines, &rightLineNumber); lastLineEqual = lastLinesEqual(leftLines, rightLines); + if (i == leftDiffList.count()) + lastLineEqual = false; j++; } if (leftDiff.command == Diff::Equal && rightDiff.command == Diff::Equal) { @@ -262,6 +270,7 @@ FileData DiffUtils::calculateContextData(const ChunkData &originalData, FileData fileData; fileData.contextChunksIncluded = true; + fileData.lastChunkAtTheEndOfFile = true; QMap<int, bool> hiddenRows; int i = 0; @@ -353,13 +362,24 @@ QString DiffUtils::makePatch(const ChunkData &chunkData, int rightLineCount = 0; QList<TextLineData> leftBuffer, rightBuffer; + int lastEqualRow = -1; + if (lastChunk) { + for (int i = chunkData.rows.count(); i > 0; i--) { + if (chunkData.rows.at(i - 1).equal) { + if (i != chunkData.rows.count()) + lastEqualRow = i - 1; + break; + } + } + } + for (int i = 0; i <= chunkData.rows.count(); i++) { const RowData &rowData = i < chunkData.rows.count() ? chunkData.rows.at(i) : RowData(TextLineData(TextLineData::Separator)); // dummy, // ensure we process buffers to the end. // rowData will be equal - if (rowData.equal) { + if (rowData.equal && i != lastEqualRow) { if (leftBuffer.count()) { for (int j = 0; j < leftBuffer.count(); j++) { const QString line = makePatchLine(QLatin1Char('-'), @@ -554,11 +574,15 @@ static QList<RowData> readLines(const QString &patch, } } - if (i < lines.count() + if (i < lines.count() // we broke before + // or we have noNewLine in some equal line and in either delete or insert line || (noNewLineInEqual >= 0 && (noNewLineInDelete >= 0 || noNewLineInInsert >= 0)) + // or we have noNewLine in not the last equal line || (noNewLineInEqual >= 0 && noNewLineInEqual != lastEqual) - || (noNewLineInDelete >= 0 && noNewLineInDelete != lastDelete) - || (noNewLineInInsert >= 0 && noNewLineInInsert != lastInsert)) { + // or we have noNewLine in not the last delete line or there is a equal line after the noNewLine for delete + || (noNewLineInDelete >= 0 && (noNewLineInDelete != lastDelete || lastEqual > lastDelete)) + // or we have noNewLine in not the last insert line or there is a equal line after the noNewLine for insert + || (noNewLineInInsert >= 0 && (noNewLineInInsert != lastInsert || lastEqual > lastInsert))) { if (ok) *ok = false; return QList<RowData>(); @@ -577,26 +601,35 @@ static QList<RowData> readLines(const QString &patch, removeNewLineFromLastDelete = true; if (noNewLineInInsert >= 0) removeNewLineFromLastInsert = true; - } else if (lastEqual > lastDelete && lastEqual > lastInsert) { - removeNewLineFromLastEqual = true; - } else if (lastDelete > lastEqual && lastDelete > lastInsert) { - if (lastInsert > lastEqual) { - removeNewLineFromLastDelete = true; - removeNewLineFromLastInsert = true; - } else if (lastEqual > lastInsert) { - removeNewLineFromLastEqual = true; - prependNewLineAfterLastEqual = true; - } - } else if (lastInsert > lastEqual && lastInsert > lastDelete) { - if (lastDelete > lastEqual) { - removeNewLineFromLastDelete = true; - removeNewLineFromLastInsert = true; - } else if (lastEqual > lastDelete) { + } else { + if (noNewLineInEqual >= 0) { removeNewLineFromLastEqual = true; - prependNewLineAfterLastEqual = true; + } else if (lastChunk) { + if (lastEqual > lastDelete && lastEqual > lastInsert) { + removeNewLineFromLastEqual = true; + } else if (lastDelete > lastEqual && lastDelete > lastInsert) { + if (lastInsert > lastEqual) { + removeNewLineFromLastDelete = true; + removeNewLineFromLastInsert = true; + } else if (lastEqual > lastInsert) { + removeNewLineFromLastEqual = true; + removeNewLineFromLastDelete = true; + prependNewLineAfterLastEqual = true; + } + } else if (lastInsert > lastEqual && lastInsert > lastDelete) { + if (lastDelete > lastEqual) { + removeNewLineFromLastDelete = true; + removeNewLineFromLastInsert = true; + } else if (lastEqual > lastDelete) { + removeNewLineFromLastEqual = true; + removeNewLineFromLastInsert = true; + prependNewLineAfterLastEqual = true; + } + } } } + if (removeNewLineFromLastEqual) { Diff &diff = diffList[lastEqual]; diff.text = diff.text.left(diff.text.count() - 1); diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 87001b3fe6f9be0dffbc9a8b72e865aceef4cb8c..5858fe91ff59067d5bef6f6aef5b490c6e518c91 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -478,13 +478,24 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData, (*selections)[*blockNumber].append(DiffSelection(&m_chunkLineFormat)); + int lastEqualRow = -1; + if (lastChunk) { + for (int i = chunkData.rows.count(); i > 0; i--) { + if (chunkData.rows.at(i - 1).equal) { + if (i != chunkData.rows.count()) + lastEqualRow = i - 1; + break; + } + } + } + for (int i = 0; i <= chunkData.rows.count(); i++) { const RowData &rowData = i < chunkData.rows.count() ? chunkData.rows.at(i) : RowData(TextLineData(TextLineData::Separator)); // dummy, // ensure we process buffers to the end. // rowData will be equal - if (rowData.equal) { + if (rowData.equal && i != lastEqualRow) { if (leftBuffer.count()) { for (int j = 0; j < leftBuffer.count(); j++) { const TextLineData &lineData = leftBuffer.at(j);