diff options
author | Andre Hartmann <aha_1980@gmx.de> | 2017-11-29 21:36:30 +0100 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2019-11-19 11:19:43 +0000 |
commit | 17668329181be771669c10baa0e322e0192fecdb (patch) | |
tree | ca70331ef982dc38de26da13201b6f8c090dd3c9 /src/plugins/diffeditor | |
parent | 27586827238ca9079860e77a7b23ae20d163143e (diff) |
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>
Diffstat (limited to 'src/plugins/diffeditor')
-rw-r--r-- | src/plugins/diffeditor/diffeditorcontroller.cpp | 8 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditorcontroller.h | 11 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditordocument.cpp | 34 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditordocument.h | 5 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditorplugin.cpp | 135 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditorplugin.h | 2 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditorwidgetcontroller.cpp | 33 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffeditorwidgetcontroller.h | 6 | ||||
-rw-r--r-- | src/plugins/diffeditor/diffutils.h | 9 | ||||
-rw-r--r-- | src/plugins/diffeditor/sidebysidediffeditorwidget.cpp | 80 | ||||
-rw-r--r-- | src/plugins/diffeditor/sidebysidediffeditorwidget.h | 4 | ||||
-rw-r--r-- | src/plugins/diffeditor/unifieddiffeditorwidget.cpp | 94 | ||||
-rw-r--r-- | src/plugins/diffeditor/unifieddiffeditorwidget.h | 14 |
13 files changed, 389 insertions, 46 deletions
diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index 0a82110bbe..7ca1a4694b 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -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 diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index b32537c0e4..ef8f209254 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -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 diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index b38235adbe..529dac382e 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -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() diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h index 42657e43f3..dce1106260 100644 --- a/src/plugins/diffeditor/diffeditordocument.h +++ b/src/plugins/diffeditor/diffeditordocument.h @@ -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; diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 0c52b55a9e..652c6e9d14 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -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" diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index 84d642b9f3..7ec3e2d392 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -73,6 +73,8 @@ private slots: void testMakePatch(); void testReadPatch_data(); void testReadPatch(); + void testFilterPatch_data(); + void testFilterPatch(); #endif // WITH_TESTS }; diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp index e1c656d5c7..c4f0ab5cb5 100644 --- a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp @@ -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; diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.h b/src/plugins/diffeditor/diffeditorwidgetcontroller.h index c0c1be9548..4951ec1cb4 100644 --- a/src/plugins/diffeditor/diffeditorwidgetcontroller.h +++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.h @@ -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 diff --git a/src/plugins/diffeditor/diffutils.h b/src/plugins/diffeditor/diffutils.h index 605266a0ef..47ae8c126a 100644 --- a/src/plugins/diffeditor/diffutils.h +++ b/src/plugins/diffeditor/diffutils.h @@ -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 { diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index a2799e7ca0..ffe4b2bc14 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -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() diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index 5fbd253e7c..14795cf085 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -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(); diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 83767e0a72..a383a55c15 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -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) { diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index 087426e94e..993d6cba20 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -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; |