DiffEditor: Stage and unstage selected lines for Git

Fixes: QTCREATORBUG-19071
Change-Id: I560ba208e68e477ea865e499847d819cfdfeb6f3
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: André Hartmann <aha_1980@gmx.de>
This commit is contained in:
Andre Hartmann
2017-11-29 21:36:30 +01:00
committed by Jarek Kobus
parent 2758682723
commit 1766832918
15 changed files with 422 additions and 57 deletions

View File

@@ -71,9 +71,10 @@ bool DiffEditorController::ignoreWhitespace() const
}
QString DiffEditorController::makePatch(int fileIndex, int chunkIndex,
const ChunkSelection &selection,
PatchOptions options) const
{
return m_document->makePatch(fileIndex, chunkIndex,
return m_document->makePatch(fileIndex, chunkIndex, selection,
options & Revert, options & AddPrefix);
}
@@ -143,9 +144,10 @@ void DiffEditorController::reloadFinished(bool success)
m_isReloading = false;
}
void DiffEditorController::requestChunkActions(QMenu *menu, int fileIndex, int chunkIndex)
void DiffEditorController::requestChunkActions(QMenu *menu, int fileIndex, int chunkIndex,
const ChunkSelection &selection)
{
emit chunkActionsRequested(menu, fileIndex, chunkIndex);
emit chunkActionsRequested(menu, fileIndex, chunkIndex, selection);
}
bool DiffEditorController::chunkExists(int fileIndex, int chunkIndex) const

View File

@@ -38,6 +38,8 @@ namespace DiffEditor {
namespace Internal { class DiffEditorDocument; }
class ChunkSelection;
class DIFFEDITOR_EXPORT DiffEditorController : public QObject
{
Q_OBJECT
@@ -58,18 +60,21 @@ public:
AddPrefix = 2
};
Q_DECLARE_FLAGS(PatchOptions, PatchOption)
QString makePatch(int fileIndex, int chunkIndex, PatchOptions options) const;
QString makePatch(int fileIndex, int chunkIndex, const ChunkSelection &selection,
PatchOptions options) const;
static Core::IDocument *findOrCreateDocument(const QString &vcsId,
const QString &displayName);
static DiffEditorController *controller(Core::IDocument *document);
void requestChunkActions(QMenu *menu, int fileIndex, int chunkIndex);
void requestChunkActions(QMenu *menu, int fileIndex, int chunkIndex,
const ChunkSelection &selection);
bool chunkExists(int fileIndex, int chunkIndex) const;
Core::IDocument *document() const;
signals:
void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex);
void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex,
const ChunkSelection &selection);
protected:
// reloadFinished() should be called

View File

@@ -76,7 +76,39 @@ DiffEditorController *DiffEditorDocument::controller() const
return m_controller;
}
ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
const ChunkSelection &selection, bool revert)
{
if (selection.isNull())
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) {
if (revert)
row.leftLine = row.rightLine;
else
row.rightLine = row.leftLine;
row.equal = true;
}
}
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;
}
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex,
const ChunkSelection &selection,
bool revert, bool addPrefix,
const QString &overriddenFileName) const
{
@@ -90,7 +122,7 @@ QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex,
if (chunkIndex >= fileData.chunks.count())
return QString();
const ChunkData &chunkData = fileData.chunks.at(chunkIndex);
const ChunkData chunkData = filterChunk(fileData.chunks.at(chunkIndex), selection, revert);
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
const QString fileName = !overriddenFileName.isEmpty()

View File

@@ -34,6 +34,7 @@ QT_FORWARD_DECLARE_CLASS(QMenu)
namespace DiffEditor {
class DiffEditorController;
class ChunkSelection;
namespace Internal {
@@ -52,7 +53,9 @@ public:
LoadFailed
};
QString makePatch(int fileIndex, int chunkIndex,
static ChunkData filterChunk(const ChunkData &data,
const ChunkSelection &selection, bool revert);
QString makePatch(int fileIndex, int chunkIndex, const ChunkSelection &selection,
bool revert, bool addPrefix = false,
const QString &overriddenFileName = QString()) const;

View File

@@ -610,6 +610,7 @@ void DiffEditorPlugin::diffExternalFiles()
Q_DECLARE_METATYPE(DiffEditor::ChunkData)
Q_DECLARE_METATYPE(DiffEditor::FileData)
Q_DECLARE_METATYPE(DiffEditor::ChunkSelection)
static inline QString _(const char *string) { return QString::fromLatin1(string); }
@@ -1430,6 +1431,140 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch()
}
}
void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{
QTest::addColumn<ChunkData>("chunk");
QTest::addColumn<QStringList>("rightLines");
QTest::addColumn<ChunkSelection>("selection");
auto createChunk = []() {
ChunkData chunk;
chunk.contextInfo = "void DiffEditor::ctor()";
chunk.contextChunk = false;
chunk.leftStartingLineNumber = 49;
chunk.rightStartingLineNumber = 49;
return chunk;
};
auto appendRow = [](ChunkData *chunk, const QString &left, const QString &right) {
RowData row;
row.equal = (left == right);
row.leftLine.text = left;
row.leftLine.textLineType = left.isEmpty() ? TextLineData::Separator : TextLineData::TextLine;
row.rightLine.text = right;
row.rightLine.textLineType = right.isEmpty() ? TextLineData::Separator : TextLineData::TextLine;
chunk->rows.append(row);
};
ChunkData chunk;
QStringList rightLines;
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "", "B"); // 51 +
appendRow(&chunk, "C", "C"); // 52
rightLines = QStringList {
"A",
"B",
"C"
};
QTest::newRow("one added") << chunk << rightLines << ChunkSelection();
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "B", ""); // 51 -
appendRow(&chunk, "C", "C"); // 52
rightLines = QStringList {
"A",
"",
"C"
};
QTest::newRow("one removed") << chunk << rightLines << ChunkSelection();
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "", "B"); // 51
appendRow(&chunk, "", "C"); // 52 +
appendRow(&chunk, "", "D"); // 53 +
appendRow(&chunk, "", "E"); // 54
appendRow(&chunk, "F", "F"); // 55
rightLines = QStringList {
"A",
"C",
"D",
"F",
};
QTest::newRow("stage selected added") << chunk << rightLines << ChunkSelection(2, 2);
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",
};
QTest::newRow("stage selected added keep changed") << chunk << rightLines << ChunkSelection(1, 1);
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "B", ""); // 51
appendRow(&chunk, "C", ""); // 52 -
appendRow(&chunk, "D", ""); // 53 -
appendRow(&chunk, "E", ""); // 54
appendRow(&chunk, "F", "F"); // 55
rightLines = QStringList {
"A",
"B",
"",
"",
"E",
"F",
};
QTest::newRow("stage selected removed") << chunk << rightLines << ChunkSelection(2, 2);
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "B", ""); // 51
appendRow(&chunk, "C", ""); // 52 -
appendRow(&chunk, "", "D"); // 53 +
appendRow(&chunk, "", "E"); // 54
appendRow(&chunk, "F", "F"); // 55
rightLines = QStringList {
"A",
"B",
"",
"D",
"F",
};
QTest::newRow("stage selected added/removed") << chunk << rightLines << ChunkSelection(2, 2);
chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50
appendRow(&chunk, "B", "C"); // 51 -/+
appendRow(&chunk, "D", "D"); // 52
rightLines = QStringList {
"A",
"C",
"D",
};
QTest::newRow("stage modified row") << chunk << rightLines << ChunkSelection(1, 1);
}
void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch()
{
QFETCH(ChunkData, chunk);
QFETCH(QStringList, rightLines);
QFETCH(ChunkSelection, selection);
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));
}
}
#endif // WITH_TESTS
#include "diffeditorplugin.moc"

View File

@@ -73,6 +73,8 @@ private slots:
void testMakePatch();
void testReadPatch_data();
void testReadPatch();
void testFilterPatch_data();
void testFilterPatch();
#endif // WITH_TESTS
};

View File

@@ -158,7 +158,7 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
if (patchBehaviour == DiffFileInfo::PatchFile) {
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
const QString patch = m_document->makePatch(fileIndex, chunkIndex, revert);
const QString patch = m_document->makePatch(fileIndex, chunkIndex, ChunkSelection(), revert);
if (patch.isEmpty())
return;
@@ -183,8 +183,9 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
const QString contentsCopyFileName = contentsCopy.fileName();
const QString contentsCopyDir = QFileInfo(contentsCopyFileName).absolutePath();
const QString patch = m_document->makePatch(fileIndex,
chunkIndex, revert, false, QFileInfo(contentsCopyFileName).fileName());
const QString patch = m_document->makePatch(fileIndex, chunkIndex,
ChunkSelection(), revert, false,
QFileInfo(contentsCopyFileName).fileName());
if (patch.isEmpty())
return;
@@ -244,6 +245,24 @@ bool DiffEditorWidgetController::chunkExists(int fileIndex, int chunkIndex) cons
return false;
}
ChunkData DiffEditorWidgetController::chunkData(int fileIndex, int chunkIndex) const
{
if (!m_document)
return ChunkData();
if (fileIndex < 0 || chunkIndex < 0)
return ChunkData();
if (fileIndex >= m_contextFileData.count())
return ChunkData();
const FileData fileData = m_contextFileData.at(fileIndex);
if (chunkIndex >= fileData.chunks.count())
return ChunkData();
return fileData.chunks.at(chunkIndex);
}
bool DiffEditorWidgetController::fileNamesAreDifferent(int fileIndex) const
{
const FileData fileData = m_contextFileData.at(fileIndex);
@@ -268,10 +287,11 @@ void DiffEditorWidgetController::addRevertAction(QMenu *menu, int fileIndex, int
revertAction->setEnabled(chunkExists(fileIndex, chunkIndex));
}
void DiffEditorWidgetController::addExtraActions(QMenu *menu, int fileIndex, int chunkIndex)
void DiffEditorWidgetController::addExtraActions(QMenu *menu, int fileIndex, int chunkIndex,
const ChunkSelection &selection)
{
if (DiffEditorController *controller = m_document->controller())
controller->requestChunkActions(menu, fileIndex, chunkIndex);
controller->requestChunkActions(menu, fileIndex, chunkIndex, selection);
}
void DiffEditorWidgetController::sendChunkToCodePaster(int fileIndex, int chunkIndex)
@@ -283,7 +303,8 @@ void DiffEditorWidgetController::sendChunkToCodePaster(int fileIndex, int chunkI
auto pasteService = ExtensionSystem::PluginManager::getObject<CodePaster::Service>();
QTC_ASSERT(pasteService, return);
const QString patch = m_document->makePatch(fileIndex, chunkIndex, false);
const QString patch = m_document->makePatch(fileIndex, chunkIndex,
ChunkSelection(), false);
if (patch.isEmpty())
return;

View File

@@ -39,6 +39,8 @@ namespace Utils { class ProgressIndicator; }
namespace DiffEditor {
class ChunkSelection;
namespace Internal {
class DiffEditorDocument;
@@ -58,7 +60,9 @@ public:
void addCodePasterAction(QMenu *menu, int fileIndex, int chunkIndex);
void addApplyAction(QMenu *menu, int fileIndex, int chunkIndex);
void addRevertAction(QMenu *menu, int fileIndex, int chunkIndex);
void addExtraActions(QMenu *menu, int fileIndex, int chunkIndex);
void addExtraActions(QMenu *menu, int fileIndex, int chunkIndex, const ChunkSelection &selection);
ChunkData chunkData(int fileIndex, int chunkIndex) const;
bool m_ignoreCurrentIndexChange = false;
QList<FileData> m_contextFileData; // ultimate data to be shown

View File

@@ -99,6 +99,15 @@ public:
bool contextChunk = false;
};
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;
};
class DIFFEDITOR_EXPORT FileData {
public:
enum FileOperation {

View File

@@ -79,6 +79,8 @@ public:
int blockNumberForFileIndex(int fileIndex) const;
int fileIndexForBlockNumber(int blockNumber) const;
int chunkIndexForBlockNumber(int blockNumber) const;
int chunkRowForBlockNumber(int blockNumber) const;
int chunkRowsCountForBlockNumber(int blockNumber) const;
bool isChunkLine(int blockNumber) const {
return m_skippedLines.contains(blockNumber);
}
@@ -97,7 +99,8 @@ signals:
int columnNumber);
void contextMenuRequested(QMenu *menu,
int diffFileIndex,
int chunkIndex);
int chunkIndex,
const ChunkSelection &selection);
void foldChanged(int blockNumber, bool folded);
void gotDisplaySettings();
void gotFocus();
@@ -355,6 +358,40 @@ int SideDiffEditorWidget::chunkIndexForBlockNumber(int blockNumber) const
return -1;
}
int SideDiffEditorWidget::chunkRowForBlockNumber(int blockNumber) const
{
if (m_chunkInfo.isEmpty())
return -1;
auto it = m_chunkInfo.upperBound(blockNumber);
if (it == m_chunkInfo.constBegin())
return -1;
--it;
if (blockNumber < it.key() + it.value().first)
return blockNumber - it.key();
return -1;
}
int SideDiffEditorWidget::chunkRowsCountForBlockNumber(int blockNumber) const
{
if (m_chunkInfo.isEmpty())
return -1;
auto it = m_chunkInfo.upperBound(blockNumber);
if (it == m_chunkInfo.constBegin())
return -1;
--it;
if (blockNumber < it.key() + it.value().first)
return it.value().first;
return -1;
}
void SideDiffEditorWidget::clearAll(const QString &message)
{
setBlockSelection(false);
@@ -446,11 +483,40 @@ void SideDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
{
QPointer<QMenu> menu = createStandardContextMenu();
const QTextCursor tc = textCursor();
QTextCursor start = tc;
start.setPosition(tc.selectionStart());
QTextCursor end = tc;
end.setPosition(tc.selectionEnd());
const int startBlockNumber = start.blockNumber();
const int endBlockNumber = end.blockNumber();
QTextCursor cursor = cursorForPosition(e->pos());
const int blockNumber = cursor.blockNumber();
const int fileIndex = fileIndexForBlockNumber(blockNumber);
const int chunkIndex = chunkIndexForBlockNumber(blockNumber);
const int selectionStartFileIndex = fileIndexForBlockNumber(startBlockNumber);
const int selectionStartChunkIndex = chunkIndexForBlockNumber(startBlockNumber);
const int selectionEndFileIndex = fileIndexForBlockNumber(endBlockNumber);
const int selectionEndChunkIndex = chunkIndexForBlockNumber(endBlockNumber);
const int selectionStart = selectionStartFileIndex == fileIndex
&& selectionStartChunkIndex == chunkIndex
? chunkRowForBlockNumber(startBlockNumber)
: 0;
const int selectionEnd = selectionEndFileIndex == fileIndex
&& selectionEndChunkIndex == chunkIndex
? chunkRowForBlockNumber(endBlockNumber)
: chunkRowsCountForBlockNumber(blockNumber);
const ChunkSelection selection(selectionStart, selectionEnd - selectionStart + 1);
emit contextMenuRequested(menu, fileIndexForBlockNumber(blockNumber),
chunkIndexForBlockNumber(blockNumber));
chunkIndexForBlockNumber(blockNumber),
selection);
connect(this, &SideDiffEditorWidget::destroyed, menu.data(), &QMenu::deleteLater);
menu->exec(e->globalPos());
@@ -1067,24 +1133,26 @@ void SideBySideDiffEditorWidget::slotRightJumpToOriginalFileRequested(
void SideBySideDiffEditorWidget::slotLeftContextMenuRequested(QMenu *menu,
int fileIndex,
int chunkIndex)
int chunkIndex,
const ChunkSelection &selection)
{
menu->addSeparator();
m_controller.addCodePasterAction(menu, fileIndex, chunkIndex);
m_controller.addApplyAction(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection);
}
void SideBySideDiffEditorWidget::slotRightContextMenuRequested(QMenu *menu,
int fileIndex,
int chunkIndex)
int chunkIndex,
const ChunkSelection &selection)
{
menu->addSeparator();
m_controller.addCodePasterAction(menu, fileIndex, chunkIndex);
m_controller.addRevertAction(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection);
}
void SideBySideDiffEditorWidget::leftVSliderChanged()

View File

@@ -85,9 +85,9 @@ private:
void slotRightJumpToOriginalFileRequested(int diffFileIndex,
int lineNumber, int columnNumber);
void slotLeftContextMenuRequested(QMenu *menu, int fileIndex,
int chunkIndex);
int chunkIndex, const ChunkSelection &selection);
void slotRightContextMenuRequested(QMenu *menu, int fileIndex,
int chunkIndex);
int chunkIndex, const ChunkSelection &selection);
void leftVSliderChanged();
void rightVSliderChanged();
void leftHSliderChanged();

View File

@@ -178,11 +178,57 @@ void UnifiedDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
{
QPointer<QMenu> menu = createStandardContextMenu();
const QTextCursor tc = textCursor();
QTextCursor start = tc;
start.setPosition(tc.selectionStart());
QTextCursor end = tc;
end.setPosition(tc.selectionEnd());
const int startBlockNumber = start.blockNumber();
const int endBlockNumber = end.blockNumber();
QTextCursor cursor = cursorForPosition(e->pos());
const int blockNumber = cursor.blockNumber();
const int fileIndex = fileIndexForBlockNumber(blockNumber);
const int chunkIndex = chunkIndexForBlockNumber(blockNumber);
const ChunkData chunkData = m_controller.chunkData(fileIndex, chunkIndex);
int selectionStart = -1;
int selectionEnd = -1;
for (int i = startBlockNumber; i <= endBlockNumber; ++i) {
const int currentFileIndex = fileIndexForBlockNumber(i);
if (currentFileIndex < fileIndex)
continue;
if (currentFileIndex > fileIndex)
break;
const int currentChunkIndex = chunkIndexForBlockNumber(i);
if (currentChunkIndex < chunkIndex)
continue;
if (currentChunkIndex > chunkIndex)
break;
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;
}
const ChunkSelection selection(selectionStart, selectionEnd - selectionStart + 1);
addContextMenuActions(menu, fileIndexForBlockNumber(blockNumber),
chunkIndexForBlockNumber(blockNumber));
chunkIndexForBlockNumber(blockNumber), selection);
connect(this, &UnifiedDiffEditorWidget::destroyed, menu.data(), &QMenu::deleteLater);
menu->exec(e->globalPos());
@@ -191,14 +237,15 @@ void UnifiedDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
int fileIndex,
int chunkIndex)
int chunkIndex,
const ChunkSelection &selection)
{
menu->addSeparator();
m_controller.addCodePasterAction(menu, fileIndex, chunkIndex);
m_controller.addApplyAction(menu, fileIndex, chunkIndex);
m_controller.addRevertAction(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex);
m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection);
}
void UnifiedDiffEditorWidget::clear(const QString &message)
@@ -228,7 +275,7 @@ QString UnifiedDiffEditorWidget::lineNumber(int blockNumber) const
if (leftLineExists || rightLineExists) {
const QString leftLine = leftLineExists
? QString::number(m_leftLineNumbers.value(blockNumber))
? QString::number(m_leftLineNumbers.value(blockNumber).first)
: QString();
lineNumberString += QString(m_leftLineNumberDigits - leftLine.count(),
' ') + leftLine;
@@ -236,7 +283,7 @@ QString UnifiedDiffEditorWidget::lineNumber(int blockNumber) const
lineNumberString += '|';
const QString rightLine = rightLineExists
? QString::number(m_rightLineNumbers.value(blockNumber))
? QString::number(m_rightLineNumbers.value(blockNumber).first)
: QString();
lineNumberString += QString(m_rightLineNumberDigits - rightLine.count(),
' ') + rightLine;
@@ -249,18 +296,20 @@ int UnifiedDiffEditorWidget::lineNumberDigits() const
return m_leftLineNumberDigits + m_rightLineNumberDigits + 1;
}
void UnifiedDiffEditorWidget::setLeftLineNumber(int blockNumber, int lineNumber)
void UnifiedDiffEditorWidget::setLeftLineNumber(int blockNumber, int lineNumber,
int rowNumberInChunk)
{
const QString lineNumberString = QString::number(lineNumber);
m_leftLineNumbers.insert(blockNumber, lineNumber);
m_leftLineNumbers.insert(blockNumber, qMakePair(lineNumber, rowNumberInChunk));
m_leftLineNumberDigits = qMax(m_leftLineNumberDigits,
lineNumberString.count());
}
void UnifiedDiffEditorWidget::setRightLineNumber(int blockNumber, int lineNumber)
void UnifiedDiffEditorWidget::setRightLineNumber(int blockNumber, int lineNumber,
int rowNumberInChunk)
{
const QString lineNumberString = QString::number(lineNumber);
m_rightLineNumbers.insert(blockNumber, lineNumber);
m_rightLineNumbers.insert(blockNumber, qMakePair(lineNumber, rowNumberInChunk));
m_rightLineNumberDigits = qMax(m_rightLineNumberDigits,
lineNumberString.count());
}
@@ -307,6 +356,7 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
int blockCount = 0;
int charCount = 0;
QList<TextLineData> leftBuffer, rightBuffer;
QList<int> leftRowsBuffer, rightRowsBuffer;
(*selections)[*blockNumber].append(DiffSelection(&m_controller.m_chunkLineFormat));
@@ -356,7 +406,8 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
if (!line.isEmpty()) {
setLeftLineNumber(*blockNumber + blockCount + 1,
chunkData.leftStartingLineNumber
+ leftLineCount + 1);
+ leftLineCount + 1,
leftRowsBuffer.at(j));
blockCount += blockDelta;
++leftLineCount;
}
@@ -366,6 +417,7 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
charCount += line.count();
}
leftBuffer.clear();
leftRowsBuffer.clear();
}
if (rightBuffer.count()) {
for (int j = 0; j < rightBuffer.count(); j++) {
@@ -396,7 +448,8 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
if (!line.isEmpty()) {
setRightLineNumber(*blockNumber + blockCount + 1,
chunkData.rightStartingLineNumber
+ rightLineCount + 1);
+ rightLineCount + 1,
rightRowsBuffer.at(j));
blockCount += blockDelta;
++rightLineCount;
}
@@ -406,6 +459,7 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
charCount += line.count();
}
rightBuffer.clear();
rightRowsBuffer.clear();
}
if (i < chunkData.rows.count()) {
const QString line = DiffUtils::makePatchLine(' ',
@@ -416,10 +470,12 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
if (!line.isEmpty()) {
setLeftLineNumber(*blockNumber + blockCount + 1,
chunkData.leftStartingLineNumber
+ leftLineCount + 1);
+ leftLineCount + 1,
i);
setRightLineNumber(*blockNumber + blockCount + 1,
chunkData.rightStartingLineNumber
+ rightLineCount + 1);
+ rightLineCount + 1,
i);
blockCount += line.count('\n');
++leftLineCount;
++rightLineCount;
@@ -430,10 +486,14 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
charCount += line.count();
}
} else {
if (rowData.leftLine.textLineType == TextLineData::TextLine)
if (rowData.leftLine.textLineType == TextLineData::TextLine) {
leftBuffer.append(rowData.leftLine);
if (rowData.rightLine.textLineType == TextLineData::TextLine)
leftRowsBuffer.append(i);
}
if (rowData.rightLine.textLineType == TextLineData::TextLine) {
rightBuffer.append(rowData.rightLine);
rightRowsBuffer.append(i);
}
}
}
@@ -584,13 +644,13 @@ void UnifiedDiffEditorWidget::jumpToOriginalFile(const QTextCursor &cursor)
const int columnNumber = cursor.positionInBlock() - 1; // -1 for the first character in line
const int rightLineNumber = m_rightLineNumbers.value(blockNumber, -1);
const int rightLineNumber = m_rightLineNumbers.value(blockNumber, qMakePair(-1, 0)).first;
if (rightLineNumber >= 0) {
m_controller.jumpToOriginalFile(rightFileName, rightLineNumber, columnNumber);
return;
}
const int leftLineNumber = m_leftLineNumbers.value(blockNumber, -1);
const int leftLineNumber = m_leftLineNumbers.value(blockNumber, qMakePair(-1, 0)).first;
if (leftLineNumber >= 0) {
if (leftFileName == rightFileName) {
for (const ChunkData &chunkData : fileData.chunks) {

View File

@@ -39,6 +39,7 @@ namespace DiffEditor {
class ChunkData;
class FileData;
class ChunkSelection;
namespace Internal {
@@ -79,8 +80,8 @@ private:
void slotCursorPositionChangedInEditor();
void setLeftLineNumber(int blockNumber, int lineNumber);
void setRightLineNumber(int blockNumber, int lineNumber);
void setLeftLineNumber(int blockNumber, int lineNumber, int rowNumberInChunk);
void setRightLineNumber(int blockNumber, int lineNumber, int rowNumberInChunk);
void setFileInfo(int blockNumber,
const DiffFileInfo &leftFileInfo,
const DiffFileInfo &rightFileInfo);
@@ -97,11 +98,12 @@ private:
void jumpToOriginalFile(const QTextCursor &cursor);
void addContextMenuActions(QMenu *menu,
int fileIndex,
int chunkIndex);
int chunkIndex,
const ChunkSelection &selection);
// block number, visual line number.
QMap<int, int> m_leftLineNumbers;
QMap<int, int> m_rightLineNumbers;
// block number, visual line number, chunk row number
QMap<int, QPair<int, int> > m_leftLineNumbers;
QMap<int, QPair<int, int> > m_rightLineNumbers;
DiffEditorWidgetController m_controller;

View File

@@ -852,38 +852,58 @@ QTextCodec *GitClient::codecFor(GitClient::CodecType codecType, const QString &s
return nullptr;
}
void GitClient::chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex)
void GitClient::chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex,
const DiffEditor::ChunkSelection &selection)
{
QPointer<DiffEditor::DiffEditorController> diffController
= qobject_cast<DiffEditorController *>(sender());
auto stageChunk = [this](QPointer<DiffEditor::DiffEditorController> diffController,
int fileIndex, int chunkIndex, bool revert) {
int fileIndex, int chunkIndex, DiffEditorController::PatchOptions options,
const DiffEditor::ChunkSelection &selection) {
if (diffController.isNull())
return;
DiffEditorController::PatchOptions options = DiffEditorController::AddPrefix;
if (revert)
options |= DiffEditorController::Revert;
const QString patch = diffController->makePatch(fileIndex, chunkIndex, options);
stage(diffController, patch, revert);
options |= DiffEditorController::AddPrefix;
const QString patch = diffController->makePatch(fileIndex, chunkIndex, selection, options);
stage(diffController, patch, options & Revert);
};
menu->addSeparator();
QAction *stageChunkAction = menu->addAction(tr("Stage Chunk"));
connect(stageChunkAction, &QAction::triggered, this,
[stageChunk, diffController, fileIndex, chunkIndex]() {
stageChunk(diffController, fileIndex, chunkIndex, false);
stageChunk(diffController, fileIndex, chunkIndex,
DiffEditorController::NoOption, DiffEditor::ChunkSelection());
});
QAction *stageLinesAction = menu->addAction(tr("Stage %n Line(s)", "", selection.selectedRowsCount));
connect(stageLinesAction, &QAction::triggered, this,
[stageChunk, diffController, fileIndex, chunkIndex, selection]() {
stageChunk(diffController, fileIndex, chunkIndex,
DiffEditorController::NoOption, selection);
});
QAction *unstageChunkAction = menu->addAction(tr("Unstage Chunk"));
connect(unstageChunkAction, &QAction::triggered, this,
[stageChunk, diffController, fileIndex, chunkIndex]() {
stageChunk(diffController, fileIndex, chunkIndex, true);
stageChunk(diffController, fileIndex, chunkIndex,
DiffEditorController::Revert, DiffEditor::ChunkSelection());
});
QAction *unstageLinesAction = menu->addAction(tr("Unstage %n Line(s)", "", selection.selectedRowsCount));
connect(unstageLinesAction, &QAction::triggered, this,
[stageChunk, diffController, fileIndex, chunkIndex, selection]() {
stageChunk(diffController, fileIndex, chunkIndex,
DiffEditorController::Revert,
selection);
});
if (selection.isNull()) {
stageLinesAction->setVisible(false);
unstageLinesAction->setVisible(false);
}
if (!diffController || !diffController->chunkExists(fileIndex, chunkIndex)) {
stageChunkAction->setEnabled(false);
stageLinesAction->setEnabled(false);
unstageChunkAction->setEnabled(false);
unstageLinesAction->setEnabled(false);
}
}

View File

@@ -54,6 +54,7 @@ namespace VcsBase {
}
namespace DiffEditor {
class ChunkSelection;
class DiffEditorController;
}
@@ -333,7 +334,8 @@ public:
private:
void finishSubmoduleUpdate();
void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex);
void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex,
const DiffEditor::ChunkSelection &selection);
void stage(DiffEditor::DiffEditorController *diffController,
const QString &patch, bool revert);