forked from qt-creator/qt-creator
Git/DiffEditor: Fix staging added/removed lines separately
Fixes: QTCREATORBUG-23243 Change-Id: Ice19e1c778aabd9cb1b9fe0681234073de85cfcb Reviewed-by: hjk <hjk@qt.io> Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -76,6 +76,14 @@ DiffEditorController *DiffEditorDocument::controller() const
|
||||
return m_controller;
|
||||
}
|
||||
|
||||
static void appendRow(ChunkData *chunk, const RowData &row)
|
||||
{
|
||||
const bool isSeparator = row.leftLine.textLineType == TextLineData::Separator
|
||||
&& row.rightLine.textLineType == TextLineData::Separator;
|
||||
if (!isSeparator)
|
||||
chunk->rows.append(row);
|
||||
}
|
||||
|
||||
ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
|
||||
const ChunkSelection &selection, bool revert)
|
||||
{
|
||||
@@ -83,27 +91,47 @@ ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
|
||||
return data;
|
||||
|
||||
ChunkData chunk(data);
|
||||
for (int i = 0; i < chunk.rows.count(); ++i) {
|
||||
RowData &row = chunk.rows[i];
|
||||
if (i < selection.startRow || i >= selection.startRow + selection.selectedRowsCount) {
|
||||
chunk.rows.clear();
|
||||
for (int i = 0; i < data.rows.count(); ++i) {
|
||||
RowData row = data.rows[i];
|
||||
const bool isLeftSelected = selection.leftSelection.contains(i);
|
||||
const bool isRightSelected = selection.rightSelection.contains(i);
|
||||
|
||||
if (isLeftSelected || isRightSelected) {
|
||||
if (row.equal || (isLeftSelected && isRightSelected)) {
|
||||
appendRow(&chunk, row);
|
||||
} else if (isLeftSelected) {
|
||||
RowData newRow = row;
|
||||
|
||||
row.rightLine = TextLineData(TextLineData::Separator);
|
||||
appendRow(&chunk, row);
|
||||
|
||||
if (revert) {
|
||||
newRow.leftLine = newRow.rightLine;
|
||||
newRow.equal = true;
|
||||
appendRow(&chunk, newRow);
|
||||
}
|
||||
} else { // isRightSelected
|
||||
if (!revert) {
|
||||
RowData newRow = row;
|
||||
newRow.rightLine = newRow.leftLine;
|
||||
newRow.equal = true;
|
||||
appendRow(&chunk, newRow);
|
||||
}
|
||||
|
||||
row.leftLine = TextLineData(TextLineData::Separator);
|
||||
appendRow(&chunk, row);
|
||||
}
|
||||
} else {
|
||||
if (revert)
|
||||
row.leftLine = row.rightLine;
|
||||
else
|
||||
row.rightLine = row.leftLine;
|
||||
row.equal = true;
|
||||
appendRow(&chunk, row);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < chunk.rows.count(); ) {
|
||||
const RowData &row = chunk.rows[i];
|
||||
const bool isSeparator = row.leftLine.textLineType == TextLineData::Separator
|
||||
&& row.rightLine.textLineType == TextLineData::Separator;
|
||||
if (isSeparator)
|
||||
chunk.rows.removeAt(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
@@ -1431,11 +1431,14 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch()
|
||||
}
|
||||
}
|
||||
|
||||
using ListOfStringPairs = QList<QPair<QString, QString>>;
|
||||
|
||||
void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
|
||||
{
|
||||
QTest::addColumn<ChunkData>("chunk");
|
||||
QTest::addColumn<QStringList>("rightLines");
|
||||
QTest::addColumn<ListOfStringPairs>("rows");
|
||||
QTest::addColumn<ChunkSelection>("selection");
|
||||
QTest::addColumn<bool>("revert");
|
||||
|
||||
auto createChunk = []() {
|
||||
ChunkData chunk;
|
||||
@@ -1455,29 +1458,29 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
|
||||
chunk->rows.append(row);
|
||||
};
|
||||
ChunkData chunk;
|
||||
QStringList rightLines;
|
||||
ListOfStringPairs rows;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "", "B"); // 51 +
|
||||
appendRow(&chunk, "C", "C"); // 52
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"B",
|
||||
"C"
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"", "B"},
|
||||
{"C", "C"}
|
||||
};
|
||||
QTest::newRow("one added") << chunk << rightLines << ChunkSelection();
|
||||
QTest::newRow("one added") << chunk << rows << ChunkSelection() << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", ""); // 51 -
|
||||
appendRow(&chunk, "C", "C"); // 52
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"",
|
||||
"C"
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", ""},
|
||||
{"C", "C"}
|
||||
};
|
||||
QTest::newRow("one removed") << chunk << rightLines << ChunkSelection();
|
||||
QTest::newRow("one removed") << chunk << rows << ChunkSelection() << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
@@ -1486,26 +1489,26 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
|
||||
appendRow(&chunk, "", "D"); // 53 +
|
||||
appendRow(&chunk, "", "E"); // 54
|
||||
appendRow(&chunk, "F", "F"); // 55
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"C",
|
||||
"D",
|
||||
"F",
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"", "C"},
|
||||
{"", "D"},
|
||||
{"F", "F"}
|
||||
};
|
||||
QTest::newRow("stage selected added") << chunk << rightLines << ChunkSelection(2, 2);
|
||||
QTest::newRow("stage selected added") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "", "B"); // 51 +
|
||||
appendRow(&chunk, "C", "D"); // 52
|
||||
appendRow(&chunk, "E", "E"); // 53
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"E",
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"", "B"},
|
||||
{"C", "C"},
|
||||
{"E", "E"}
|
||||
};
|
||||
QTest::newRow("stage selected added keep changed") << chunk << rightLines << ChunkSelection(1, 1);
|
||||
QTest::newRow("stage selected added keep changed") << chunk << rows << ChunkSelection({1}, {1}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
@@ -1514,15 +1517,15 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
|
||||
appendRow(&chunk, "D", ""); // 53 -
|
||||
appendRow(&chunk, "E", ""); // 54
|
||||
appendRow(&chunk, "F", "F"); // 55
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"B",
|
||||
"",
|
||||
"",
|
||||
"E",
|
||||
"F",
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "B"},
|
||||
{"C", ""},
|
||||
{"D", ""},
|
||||
{"E", "E"},
|
||||
{"F", "F"}
|
||||
};
|
||||
QTest::newRow("stage selected removed") << chunk << rightLines << ChunkSelection(2, 2);
|
||||
QTest::newRow("stage selected removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
@@ -1531,37 +1534,132 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
|
||||
appendRow(&chunk, "", "D"); // 53 +
|
||||
appendRow(&chunk, "", "E"); // 54
|
||||
appendRow(&chunk, "F", "F"); // 55
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"B",
|
||||
"",
|
||||
"D",
|
||||
"F",
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "B"},
|
||||
{"C", ""},
|
||||
{"", "D"},
|
||||
{"F", "F"}
|
||||
};
|
||||
QTest::newRow("stage selected added/removed") << chunk << rightLines << ChunkSelection(2, 2);
|
||||
QTest::newRow("stage selected added/removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rightLines = QStringList {
|
||||
"A",
|
||||
"C",
|
||||
"D",
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage modified row") << chunk << rightLines << ChunkSelection(1, 1);
|
||||
QTest::newRow("stage modified row") << chunk << rows << ChunkSelection({1}, {1}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage modified and unmodified rows") << chunk << rows << ChunkSelection({0, 1, 2}, {0, 1, 2}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage unmodified left rows") << chunk << rows << ChunkSelection({0, 1, 2}, {1}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage unmodified right rows") << chunk << rows << ChunkSelection({1}, {0, 1, 2}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", ""},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage left only") << chunk << rows << ChunkSelection({1}, {}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "B"},
|
||||
{"", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage right only") << chunk << rows << ChunkSelection({}, {1}) << false;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
QTest::newRow("stage modified row and revert") << chunk << rows << ChunkSelection({1}, {1}) << true;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"B", ""},
|
||||
{"C", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
// symmetric to: "stage right only"
|
||||
QTest::newRow("stage left only and revert") << chunk << rows << ChunkSelection({1}, {}) << true;
|
||||
|
||||
chunk = createChunk();
|
||||
appendRow(&chunk, "A", "A"); // 50
|
||||
appendRow(&chunk, "B", "C"); // 51 -/+
|
||||
appendRow(&chunk, "D", "D"); // 52
|
||||
rows = ListOfStringPairs {
|
||||
{"A", "A"},
|
||||
{"", "C"},
|
||||
{"D", "D"}
|
||||
};
|
||||
// symmetric to: "stage left only"
|
||||
QTest::newRow("stage right only and revert") << chunk << rows << ChunkSelection({}, {1}) << true;
|
||||
|
||||
}
|
||||
|
||||
void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch()
|
||||
{
|
||||
QFETCH(ChunkData, chunk);
|
||||
QFETCH(QStringList, rightLines);
|
||||
QFETCH(ListOfStringPairs, rows);
|
||||
QFETCH(ChunkSelection, selection);
|
||||
QFETCH(bool, revert);
|
||||
|
||||
ChunkData result = DiffEditorDocument::filterChunk(chunk, selection, false);
|
||||
QCOMPARE(result.rows.size(), rightLines.size());
|
||||
for (int i = 0; i < rightLines.size(); ++i) {
|
||||
QCOMPARE(result.rows.at(i).rightLine.text, rightLines.at(i));
|
||||
const ChunkData result = DiffEditorDocument::filterChunk(chunk, selection, revert);
|
||||
QCOMPARE(result.rows.size(), rows.size());
|
||||
for (int i = 0; i < rows.size(); ++i) {
|
||||
QCOMPARE(result.rows.at(i).leftLine.text, rows.at(i).first);
|
||||
QCOMPARE(result.rows.at(i).rightLine.text, rows.at(i).second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "diffutils.h"
|
||||
|
||||
#include <texteditor/fontsettings.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/differ.h>
|
||||
|
||||
#include <QFutureInterfaceBase>
|
||||
@@ -37,6 +38,11 @@ using namespace Utils;
|
||||
|
||||
namespace DiffEditor {
|
||||
|
||||
int ChunkSelection::selectedRowsCount() const
|
||||
{
|
||||
return Utils::toSet(leftSelection).unite(Utils::toSet(rightSelection)).count();
|
||||
}
|
||||
|
||||
static QList<TextLineData> assemblyRows(const QList<TextLineData> &lines,
|
||||
const QMap<int, int> &lineSpans)
|
||||
{
|
||||
|
||||
@@ -102,10 +102,12 @@ public:
|
||||
class DIFFEDITOR_EXPORT ChunkSelection {
|
||||
public:
|
||||
ChunkSelection() {}
|
||||
ChunkSelection(int s, int c) : startRow(s), selectedRowsCount(c) {}
|
||||
bool isNull() const { return selectedRowsCount <= 0; }
|
||||
int startRow = -1;
|
||||
int selectedRowsCount = 0;
|
||||
ChunkSelection(const QList<int> &left, const QList<int> &right)
|
||||
: leftSelection(left), rightSelection(right) {}
|
||||
bool isNull() const { return leftSelection.isEmpty() && rightSelection.isEmpty(); }
|
||||
int selectedRowsCount() const;
|
||||
QList<int> leftSelection;
|
||||
QList<int> rightSelection;
|
||||
};
|
||||
|
||||
class DIFFEDITOR_EXPORT FileData {
|
||||
|
||||
@@ -512,7 +512,11 @@ void SideDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
||||
? chunkRowForBlockNumber(endBlockNumber)
|
||||
: chunkRowsCountForBlockNumber(blockNumber);
|
||||
|
||||
const ChunkSelection selection(selectionStart, selectionEnd - selectionStart + 1);
|
||||
QList<int> rows;
|
||||
for (int i = selectionStart; i <= selectionEnd; ++i)
|
||||
rows.append(i);
|
||||
|
||||
const ChunkSelection selection(rows, rows);
|
||||
|
||||
emit contextMenuRequested(menu, fileIndexForBlockNumber(blockNumber),
|
||||
chunkIndexForBlockNumber(blockNumber),
|
||||
|
||||
@@ -194,8 +194,7 @@ void UnifiedDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
||||
|
||||
const ChunkData chunkData = m_controller.chunkData(fileIndex, chunkIndex);
|
||||
|
||||
int selectionStart = -1;
|
||||
int selectionEnd = -1;
|
||||
QList<int> leftSelection, rightSelection;
|
||||
|
||||
for (int i = startBlockNumber; i <= endBlockNumber; ++i) {
|
||||
const int currentFileIndex = fileIndexForBlockNumber(i);
|
||||
@@ -214,18 +213,14 @@ void UnifiedDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
||||
|
||||
const int leftRow = m_leftLineNumbers.value(i, qMakePair(-1, -1)).second;
|
||||
const int rightRow = m_rightLineNumbers.value(i, qMakePair(-1, -1)).second;
|
||||
const int row = leftRow >= 0 ? leftRow : rightRow;
|
||||
|
||||
if (row < 0)
|
||||
continue;
|
||||
|
||||
if (selectionStart < 0 || selectionStart > row)
|
||||
selectionStart = row;
|
||||
if (selectionEnd < 0 || selectionEnd < row)
|
||||
selectionEnd = row;
|
||||
if (leftRow >= 0)
|
||||
leftSelection.append(leftRow);
|
||||
if (rightRow >= 0)
|
||||
rightSelection.append(rightRow);
|
||||
}
|
||||
|
||||
const ChunkSelection selection(selectionStart, selectionEnd - selectionStart + 1);
|
||||
const ChunkSelection selection(leftSelection, rightSelection);
|
||||
|
||||
addContextMenuActions(menu, fileIndexForBlockNumber(blockNumber),
|
||||
chunkIndexForBlockNumber(blockNumber), selection);
|
||||
|
||||
@@ -875,7 +875,7 @@ void GitClient::chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex
|
||||
stageChunk(diffController, fileIndex, chunkIndex,
|
||||
DiffEditorController::NoOption, DiffEditor::ChunkSelection());
|
||||
});
|
||||
QAction *stageLinesAction = menu->addAction(tr("Stage %n Line(s)", "", selection.selectedRowsCount));
|
||||
QAction *stageLinesAction = menu->addAction(tr("Stage Selection (%n Lines)", "", selection.selectedRowsCount()));
|
||||
connect(stageLinesAction, &QAction::triggered, this,
|
||||
[stageChunk, diffController, fileIndex, chunkIndex, selection]() {
|
||||
stageChunk(diffController, fileIndex, chunkIndex,
|
||||
@@ -887,7 +887,7 @@ void GitClient::chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex
|
||||
stageChunk(diffController, fileIndex, chunkIndex,
|
||||
DiffEditorController::Revert, DiffEditor::ChunkSelection());
|
||||
});
|
||||
QAction *unstageLinesAction = menu->addAction(tr("Unstage %n Line(s)", "", selection.selectedRowsCount));
|
||||
QAction *unstageLinesAction = menu->addAction(tr("Unstage Selection (%n Lines)", "", selection.selectedRowsCount()));
|
||||
connect(unstageLinesAction, &QAction::triggered, this,
|
||||
[stageChunk, diffController, fileIndex, chunkIndex, selection]() {
|
||||
stageChunk(diffController, fileIndex, chunkIndex,
|
||||
|
||||
Reference in New Issue
Block a user