PatchTool: Introduce PatchAction enum

Add static PatchTool::confirmPatching() and reuse it
in two places.

Use Tr::tr() inside PatchTool.

Change-Id: I70779619dbb58ab6e46a585bbeff51588ccb2f53
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Jarek Kobus
2022-09-29 15:31:27 +02:00
parent 2d360db2c3
commit b67c868f75
14 changed files with 140 additions and 131 deletions

View File

@@ -1,14 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "patchtool.h" #include "coreplugintr.h"
#include "messagemanager.h"
#include "icore.h" #include "icore.h"
#include "messagemanager.h"
#include "patchtool.h"
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <QApplication> #include <QMessageBox>
using namespace Utils; using namespace Utils;
@@ -37,22 +38,30 @@ void PatchTool::setPatchCommand(const FilePath &newCommand)
s->endGroup(); s->endGroup();
} }
bool PatchTool::confirmPatching(QWidget *parent, PatchAction patchAction)
{
const QString title = patchAction == PatchAction::Apply ? Tr::tr("Apply Chunk")
: Tr::tr("Revert Chunk");
const QString question = patchAction == PatchAction::Apply
? Tr::tr("Would you like to apply the chunk?")
: Tr::tr("Would you like to revert the chunk?");
return QMessageBox::question(parent, title, question, QMessageBox::Yes | QMessageBox::No)
== QMessageBox::Yes;
}
static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirectory, static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirectory,
int strip, bool reverse, bool withCrlf) int strip, PatchAction patchAction, bool withCrlf)
{ {
const FilePath patch = PatchTool::patchCommand(); const FilePath patch = PatchTool::patchCommand();
if (patch.isEmpty()) { if (patch.isEmpty()) {
MessageManager::writeDisrupting(QApplication::translate( MessageManager::writeDisrupting(Tr::tr("There is no patch-command configured in "
"Core::PatchTool", "the general \"Environment\" settings."));
"There is no patch-command configured in the general \"Environment\" settings."));
return false; return false;
} }
if (!patch.exists() && !patch.searchInPath().exists()) { if (!patch.exists() && !patch.searchInPath().exists()) {
MessageManager::writeDisrupting( MessageManager::writeDisrupting(Tr::tr("The patch-command configured in the general "
QApplication::translate("Core::PatchTool", "\"Environment\" settings does not exist."));
"The patch-command configured in the general \"Environment\" "
"settings does not exist."));
return false; return false;
} }
@@ -70,20 +79,18 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec
if (strip >= 0) if (strip >= 0)
args << ("-p" + QString::number(strip)); args << ("-p" + QString::number(strip));
if (reverse) if (patchAction == PatchAction::Revert)
args << "-R"; args << "-R";
if (withCrlf) if (withCrlf)
args << "--binary"; args << "--binary";
MessageManager::writeDisrupting( MessageManager::writeDisrupting(Tr::tr("Running in %1: %2 %3")
QApplication::translate("Core::PatchTool", "Running in %1: %2 %3")
.arg(workingDirectory.toUserOutput(), patch.toUserOutput(), args.join(' '))); .arg(workingDirectory.toUserOutput(), patch.toUserOutput(), args.join(' ')));
patchProcess.setCommand({patch, args}); patchProcess.setCommand({patch, args});
patchProcess.setWriteData(input); patchProcess.setWriteData(input);
patchProcess.start(); patchProcess.start();
if (!patchProcess.waitForStarted()) { if (!patchProcess.waitForStarted()) {
MessageManager::writeFlashing( MessageManager::writeFlashing(Tr::tr("Unable to launch \"%1\": %2")
QApplication::translate("Core::PatchTool", "Unable to launch \"%1\": %2") .arg(patch.toUserOutput(), patchProcess.errorString()));
.arg(patch.toUserOutput(), patchProcess.errorString()));
return false; return false;
} }
@@ -92,9 +99,8 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec
if (!patchProcess.readDataFromProcess(&stdOut, &stdErr)) { if (!patchProcess.readDataFromProcess(&stdOut, &stdErr)) {
patchProcess.stop(); patchProcess.stop();
patchProcess.waitForFinished(); patchProcess.waitForFinished();
MessageManager::writeFlashing( MessageManager::writeFlashing(Tr::tr("A timeout occurred running \"%1\"")
QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"") .arg(patch.toUserOutput()));
.arg(patch.toUserOutput()));
return false; return false;
} }
@@ -102,7 +108,7 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec
if (stdOut.contains("(different line endings)") && !withCrlf) { if (stdOut.contains("(different line endings)") && !withCrlf) {
QByteArray crlfInput = input; QByteArray crlfInput = input;
crlfInput.replace('\n', "\r\n"); crlfInput.replace('\n', "\r\n");
return runPatchHelper(crlfInput, workingDirectory, strip, reverse, true); return runPatchHelper(crlfInput, workingDirectory, strip, patchAction, true);
} else { } else {
MessageManager::writeFlashing(QString::fromLocal8Bit(stdOut)); MessageManager::writeFlashing(QString::fromLocal8Bit(stdOut));
} }
@@ -111,24 +117,21 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec
MessageManager::writeFlashing(QString::fromLocal8Bit(stdErr)); MessageManager::writeFlashing(QString::fromLocal8Bit(stdErr));
if (patchProcess.exitStatus() != QProcess::NormalExit) { if (patchProcess.exitStatus() != QProcess::NormalExit) {
MessageManager::writeFlashing( MessageManager::writeFlashing(Tr::tr("\"%1\" crashed.").arg(patch.toUserOutput()));
QApplication::translate("Core::PatchTool", "\"%1\" crashed.").arg(patch.toUserOutput()));
return false; return false;
} }
if (patchProcess.exitCode() != 0) { if (patchProcess.exitCode() != 0) {
MessageManager::writeFlashing( MessageManager::writeFlashing(Tr::tr("\"%1\" failed (exit code %2).")
QApplication::translate("Core::PatchTool", "\"%1\" failed (exit code %2).") .arg(patch.toUserOutput()).arg(patchProcess.exitCode()));
.arg(patch.toUserOutput())
.arg(patchProcess.exitCode()));
return false; return false;
} }
return true; return true;
} }
bool PatchTool::runPatch(const QByteArray &input, const FilePath &workingDirectory, bool PatchTool::runPatch(const QByteArray &input, const FilePath &workingDirectory,
int strip, bool reverse) int strip, PatchAction patchAction)
{ {
return runPatchHelper(input, workingDirectory, strip, reverse, false); return runPatchHelper(input, workingDirectory, strip, patchAction, false);
} }
} // namespace Core } // namespace Core

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once #pragma once
@@ -9,15 +9,22 @@
namespace Core { namespace Core {
enum class PatchAction {
Apply,
Revert
};
class CORE_EXPORT PatchTool class CORE_EXPORT PatchTool
{ {
public: public:
static Utils::FilePath patchCommand(); static Utils::FilePath patchCommand();
static void setPatchCommand(const Utils::FilePath &newCommand); static void setPatchCommand(const Utils::FilePath &newCommand);
static bool confirmPatching(QWidget *parent, PatchAction patchAction);
// Utility to run the 'patch' command // Utility to run the 'patch' command
static bool runPatch(const QByteArray &input, const Utils::FilePath &workingDirectory = {}, static bool runPatch(const QByteArray &input, const Utils::FilePath &workingDirectory = {},
int strip = 0, bool reverse = false); int strip = 0, PatchAction patchAction = PatchAction::Apply);
}; };
} // namespace Core } // namespace Core

View File

@@ -13,6 +13,7 @@
#include <QStringList> #include <QStringList>
using namespace Core;
using namespace Utils; using namespace Utils;
namespace DiffEditor { namespace DiffEditor {
@@ -55,7 +56,8 @@ QString DiffEditorController::makePatch(int fileIndex, int chunkIndex,
PatchOptions options) const PatchOptions options) const
{ {
return m_document->makePatch(fileIndex, chunkIndex, selection, return m_document->makePatch(fileIndex, chunkIndex, selection,
options & Revert, options & AddPrefix); (options & Revert) ? PatchAction::Revert : PatchAction::Apply,
options & AddPrefix);
} }
Core::IDocument *DiffEditorController::findOrCreateDocument(const QString &vcsId, Core::IDocument *DiffEditorController::findOrCreateDocument(const QString &vcsId,

View File

@@ -19,6 +19,7 @@
#include <QTextCodec> #include <QTextCodec>
#include <QUuid> #include <QUuid>
using namespace Core;
using namespace Utils; using namespace Utils;
namespace DiffEditor { namespace DiffEditor {
@@ -63,8 +64,8 @@ static void appendRow(ChunkData *chunk, const RowData &row)
chunk->rows.append(row); chunk->rows.append(row);
} }
ChunkData DiffEditorDocument::filterChunk(const ChunkData &data, ChunkData DiffEditorDocument::filterChunk(const ChunkData &data, const ChunkSelection &selection,
const ChunkSelection &selection, bool revert) PatchAction patchAction)
{ {
if (selection.isNull()) if (selection.isNull())
return data; return data;
@@ -85,13 +86,13 @@ ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
row.line[RightSide] = TextLineData(TextLineData::Separator); row.line[RightSide] = TextLineData(TextLineData::Separator);
appendRow(&chunk, row); appendRow(&chunk, row);
if (revert) { if (patchAction == PatchAction::Revert) {
newRow.line[LeftSide] = newRow.line[RightSide]; newRow.line[LeftSide] = newRow.line[RightSide];
newRow.equal = true; newRow.equal = true;
appendRow(&chunk, newRow); appendRow(&chunk, newRow);
} }
} else { // isRightSelected } else { // isRightSelected
if (!revert) { if (patchAction == PatchAction::Apply) {
RowData newRow = row; RowData newRow = row;
newRow.line[RightSide] = newRow.line[LeftSide]; newRow.line[RightSide] = newRow.line[LeftSide];
newRow.equal = true; newRow.equal = true;
@@ -102,10 +103,10 @@ ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
appendRow(&chunk, row); appendRow(&chunk, row);
} }
} else { } else {
if (revert) if (patchAction == PatchAction::Apply)
row.line[LeftSide] = row.line[RightSide];
else
row.line[RightSide] = row.line[LeftSide]; row.line[RightSide] = row.line[LeftSide];
else
row.line[LeftSide] = row.line[RightSide];
row.equal = true; row.equal = true;
appendRow(&chunk, row); appendRow(&chunk, row);
} }
@@ -115,9 +116,8 @@ ChunkData DiffEditorDocument::filterChunk(const ChunkData &data,
} }
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex, QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex,
const ChunkSelection &selection, const ChunkSelection &selection, PatchAction patchAction,
bool revert, bool addPrefix, bool addPrefix, const QString &overriddenFileName) const
const QString &overriddenFileName) const
{ {
if (fileIndex < 0 || chunkIndex < 0 || fileIndex >= m_diffFiles.count()) if (fileIndex < 0 || chunkIndex < 0 || fileIndex >= m_diffFiles.count())
return {}; return {};
@@ -126,22 +126,16 @@ QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex,
if (chunkIndex >= fileData.chunks.count()) if (chunkIndex >= fileData.chunks.count())
return {}; return {};
const ChunkData chunkData = filterChunk(fileData.chunks.at(chunkIndex), selection, revert); const ChunkData chunkData = filterChunk(fileData.chunks.at(chunkIndex), selection, patchAction);
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1); const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
const QString fileName = !overriddenFileName.isEmpty() const QString fileName = !overriddenFileName.isEmpty()
? overriddenFileName : revert ? overriddenFileName : patchAction == PatchAction::Apply
? fileData.fileInfo[RightSide].fileName ? fileData.fileInfo[LeftSide].fileName : fileData.fileInfo[RightSide].fileName;
: fileData.fileInfo[LeftSide].fileName;
QString leftPrefix, rightPrefix; const QString leftFileName = addPrefix ? QString("a/") + fileName : fileName;
if (addPrefix) { const QString rightFileName = addPrefix ? QString("b/") + fileName : fileName;
leftPrefix = "a/"; return DiffUtils::makePatch(chunkData, leftFileName, rightFileName,
rightPrefix = "b/";
}
return DiffUtils::makePatch(chunkData,
leftPrefix + fileName,
rightPrefix + fileName,
lastChunk && fileData.lastChunkAtTheEndOfFile); lastChunk && fileData.lastChunkAtTheEndOfFile);
} }

View File

@@ -5,6 +5,7 @@
#include "diffutils.h" #include "diffutils.h"
#include <coreplugin/patchtool.h>
#include <coreplugin/textdocument.h> #include <coreplugin/textdocument.h>
QT_FORWARD_DECLARE_CLASS(QMenu) QT_FORWARD_DECLARE_CLASS(QMenu)
@@ -31,10 +32,10 @@ public:
LoadFailed LoadFailed
}; };
static ChunkData filterChunk(const ChunkData &data, static ChunkData filterChunk(const ChunkData &data, const ChunkSelection &selection,
const ChunkSelection &selection, bool revert); Core::PatchAction patchAction);
QString makePatch(int fileIndex, int chunkIndex, const ChunkSelection &selection, QString makePatch(int fileIndex, int chunkIndex, const ChunkSelection &selection,
bool revert, bool addPrefix = false, Core::PatchAction patchAction, bool addPrefix = false,
const QString &overriddenFileName = {}) const; const QString &overriddenFileName = {}) const;
void setDiffFiles(const QList<FileData> &data, const Utils::FilePath &directory, void setDiffFiles(const QList<FileData> &data, const Utils::FilePath &directory,

View File

@@ -1421,7 +1421,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
QTest::addColumn<ChunkData>("chunk"); QTest::addColumn<ChunkData>("chunk");
QTest::addColumn<ListOfStringPairs>("rows"); QTest::addColumn<ListOfStringPairs>("rows");
QTest::addColumn<ChunkSelection>("selection"); QTest::addColumn<ChunkSelection>("selection");
QTest::addColumn<bool>("revert"); QTest::addColumn<PatchAction>("patchAction");
auto createChunk = [] { auto createChunk = [] {
ChunkData chunk; ChunkData chunk;
@@ -1451,7 +1451,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"", "B"}, {"", "B"},
{"C", "C"} {"C", "C"}
}; };
QTest::newRow("one added") << chunk << rows << ChunkSelection() << false; QTest::newRow("one added") << chunk << rows << ChunkSelection() << PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1462,7 +1462,7 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", ""}, {"B", ""},
{"C", "C"} {"C", "C"}
}; };
QTest::newRow("one removed") << chunk << rows << ChunkSelection() << false; QTest::newRow("one removed") << chunk << rows << ChunkSelection() << PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1477,7 +1477,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"", "D"}, {"", "D"},
{"F", "F"} {"F", "F"}
}; };
QTest::newRow("stage selected added") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false; QTest::newRow("stage selected added") << chunk << rows << ChunkSelection({2, 3}, {2, 3})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1490,7 +1491,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"C", "C"}, {"C", "C"},
{"E", "E"} {"E", "E"}
}; };
QTest::newRow("stage selected added keep changed") << chunk << rows << ChunkSelection({1}, {1}) << false; QTest::newRow("stage selected added keep changed") << chunk << rows << ChunkSelection({1}, {1})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1507,7 +1509,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"E", "E"}, {"E", "E"},
{"F", "F"} {"F", "F"}
}; };
QTest::newRow("stage selected removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false; QTest::newRow("stage selected removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1523,7 +1526,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"", "D"}, {"", "D"},
{"F", "F"} {"F", "F"}
}; };
QTest::newRow("stage selected added/removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3}) << false; QTest::newRow("stage selected added/removed") << chunk << rows << ChunkSelection({2, 3}, {2, 3})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1534,7 +1538,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", "C"}, {"B", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage modified row") << chunk << rows << ChunkSelection({1}, {1}) << false; QTest::newRow("stage modified row") << chunk << rows << ChunkSelection({1}, {1})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1545,7 +1550,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", "C"}, {"B", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage modified and unmodified rows") << chunk << rows << ChunkSelection({0, 1, 2}, {0, 1, 2}) << false; QTest::newRow("stage modified and unmodified rows") << chunk << rows
<< ChunkSelection({0, 1, 2}, {0, 1, 2}) << PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1556,7 +1562,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", "C"}, {"B", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage unmodified left rows") << chunk << rows << ChunkSelection({0, 1, 2}, {1}) << false; QTest::newRow("stage unmodified left rows") << chunk << rows << ChunkSelection({0, 1, 2}, {1})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1567,7 +1574,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", "C"}, {"B", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage unmodified right rows") << chunk << rows << ChunkSelection({1}, {0, 1, 2}) << false; QTest::newRow("stage unmodified right rows") << chunk << rows << ChunkSelection({1}, {0, 1, 2})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1578,7 +1586,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", ""}, {"B", ""},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage left only") << chunk << rows << ChunkSelection({1}, {}) << false; QTest::newRow("stage left only") << chunk << rows << ChunkSelection({1}, {})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1590,7 +1599,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"", "C"}, {"", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage right only") << chunk << rows << ChunkSelection({}, {1}) << false; QTest::newRow("stage right only") << chunk << rows << ChunkSelection({}, {1})
<< PatchAction::Apply;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1601,7 +1611,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"B", "C"}, {"B", "C"},
{"D", "D"} {"D", "D"}
}; };
QTest::newRow("stage modified row and revert") << chunk << rows << ChunkSelection({1}, {1}) << true; QTest::newRow("stage modified row and revert") << chunk << rows << ChunkSelection({1}, {1})
<< PatchAction::Revert;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1614,7 +1625,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"D", "D"} {"D", "D"}
}; };
// symmetric to: "stage right only" // symmetric to: "stage right only"
QTest::newRow("stage left only and revert") << chunk << rows << ChunkSelection({1}, {}) << true; QTest::newRow("stage left only and revert") << chunk << rows << ChunkSelection({1}, {})
<< PatchAction::Revert;
chunk = createChunk(); chunk = createChunk();
appendRow(&chunk, "A", "A"); // 50 appendRow(&chunk, "A", "A"); // 50
@@ -1626,8 +1638,8 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch_data()
{"D", "D"} {"D", "D"}
}; };
// symmetric to: "stage left only" // symmetric to: "stage left only"
QTest::newRow("stage right only and revert") << chunk << rows << ChunkSelection({}, {1}) << true; QTest::newRow("stage right only and revert") << chunk << rows << ChunkSelection({}, {1})
<< PatchAction::Revert;
} }
void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch() void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch()
@@ -1635,9 +1647,9 @@ void DiffEditor::Internal::DiffEditorPlugin::testFilterPatch()
QFETCH(ChunkData, chunk); QFETCH(ChunkData, chunk);
QFETCH(ListOfStringPairs, rows); QFETCH(ListOfStringPairs, rows);
QFETCH(ChunkSelection, selection); QFETCH(ChunkSelection, selection);
QFETCH(bool, revert); QFETCH(PatchAction, patchAction);
const ChunkData result = DiffEditorDocument::filterChunk(chunk, selection, revert); const ChunkData result = DiffEditorDocument::filterChunk(chunk, selection, patchAction);
QCOMPARE(result.rows.size(), rows.size()); QCOMPARE(result.rows.size(), rows.size());
for (int i = 0; i < rows.size(); ++i) { for (int i = 0; i < rows.size(); ++i) {
QCOMPARE(result.rows.at(i).line[LeftSide].text, rows.at(i).first); QCOMPARE(result.rows.at(i).line[LeftSide].text, rows.at(i).first);

View File

@@ -22,7 +22,6 @@
#include <utils/temporaryfile.h> #include <utils/temporaryfile.h>
#include <QMenu> #include <QMenu>
#include <QMessageBox>
#include <QTextCodec> #include <QTextCodec>
using namespace Core; using namespace Core;
@@ -127,7 +126,7 @@ void DiffEditorWidgetController::onDocumentReloadFinished()
hideProgress(); hideProgress();
} }
void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkIndex) void DiffEditorWidgetController::patch(PatchAction patchAction, int fileIndex, int chunkIndex)
{ {
if (!m_document) if (!m_document)
return; return;
@@ -135,24 +134,16 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
if (!chunkExists(fileIndex, chunkIndex)) if (!chunkExists(fileIndex, chunkIndex))
return; return;
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk"); if (!PatchTool::confirmPatching(m_diffEditorWidget, patchAction))
const QString question = revert
? tr("Would you like to revert the chunk?")
: tr("Would you like to apply the chunk?");
if (QMessageBox::No == QMessageBox::question(m_diffEditorWidget, title,
question,
QMessageBox::Yes
| QMessageBox::No)) {
return; return;
}
const FileData fileData = m_contextFileData.at(fileIndex); const FileData fileData = m_contextFileData.at(fileIndex);
const QString fileName = revert const QString fileName = patchAction == PatchAction::Apply
? fileData.fileInfo[RightSide].fileName ? fileData.fileInfo[LeftSide].fileName
: fileData.fileInfo[LeftSide].fileName; : fileData.fileInfo[RightSide].fileName;
const DiffFileInfo::PatchBehaviour patchBehaviour = revert const DiffFileInfo::PatchBehaviour patchBehaviour = patchAction == PatchAction::Apply
? fileData.fileInfo[RightSide].patchBehaviour ? fileData.fileInfo[LeftSide].patchBehaviour
: fileData.fileInfo[LeftSide].patchBehaviour; : fileData.fileInfo[RightSide].patchBehaviour;
const FilePath workingDirectory = m_document->baseDirectory().isEmpty() const FilePath workingDirectory = m_document->baseDirectory().isEmpty()
? FilePath::fromString(fileName).absolutePath() ? FilePath::fromString(fileName).absolutePath()
@@ -162,14 +153,14 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
if (patchBehaviour == DiffFileInfo::PatchFile) { if (patchBehaviour == DiffFileInfo::PatchFile) {
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0; 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, {}, patchAction);
if (patch.isEmpty()) if (patch.isEmpty())
return; return;
FileChangeBlocker fileChangeBlocker(absFilePath); FileChangeBlocker fileChangeBlocker(absFilePath);
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch), if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert)) workingDirectory, strip, patchAction))
m_document->reload(); m_document->reload();
} else { // PatchEditor } else { // PatchEditor
auto textDocument = qobject_cast<TextEditor::TextDocument *>( auto textDocument = qobject_cast<TextEditor::TextDocument *>(
@@ -187,15 +178,14 @@ void DiffEditorWidgetController::patch(bool revert, int fileIndex, int chunkInde
const QString contentsCopyFileName = contentsCopy.fileName(); const QString contentsCopyFileName = contentsCopy.fileName();
const QString contentsCopyDir = QFileInfo(contentsCopyFileName).absolutePath(); const QString contentsCopyDir = QFileInfo(contentsCopyFileName).absolutePath();
const QString patch = m_document->makePatch(fileIndex, chunkIndex, const QString patch = m_document->makePatch(fileIndex, chunkIndex, {}, patchAction, false,
{}, revert, false,
QFileInfo(contentsCopyFileName).fileName()); QFileInfo(contentsCopyFileName).fileName());
if (patch.isEmpty()) if (patch.isEmpty())
return; return;
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch), if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
FilePath::fromString(contentsCopyDir), 0, revert)) { FilePath::fromString(contentsCopyDir), 0, patchAction)) {
QString errorString; QString errorString;
if (textDocument->reload(&errorString, FilePath::fromString(contentsCopyFileName))) if (textDocument->reload(&errorString, FilePath::fromString(contentsCopyFileName)))
m_document->reload(); m_document->reload();
@@ -266,15 +256,17 @@ bool DiffEditorWidgetController::fileNamesAreDifferent(int fileIndex) const
return fileData.fileInfo[LeftSide].fileName != fileData.fileInfo[RightSide].fileName; return fileData.fileInfo[LeftSide].fileName != fileData.fileInfo[RightSide].fileName;
} }
void DiffEditorWidgetController::addApplyRevertAction(QMenu *menu, int fileIndex, int chunkIndex, DiffSide side) void DiffEditorWidgetController::addPatchAction(QMenu *menu, int fileIndex, int chunkIndex,
PatchAction patchAction)
{ {
const QString actionName = side == LeftSide ? tr("Apply Chunk...") : tr("Revert Chunk..."); const QString actionName = patchAction == PatchAction::Apply ? tr("Apply Chunk...")
: tr("Revert Chunk...");
QAction *action = menu->addAction(actionName); QAction *action = menu->addAction(actionName);
connect(action, &QAction::triggered, this, [this, fileIndex, chunkIndex, side] { connect(action, &QAction::triggered, this, [this, fileIndex, chunkIndex, patchAction] {
patch(side == RightSide, fileIndex, chunkIndex); patch(patchAction, fileIndex, chunkIndex);
}); });
const bool enabled = chunkExists(fileIndex, chunkIndex) const bool enabled = chunkExists(fileIndex, chunkIndex)
&& (side == RightSide || fileNamesAreDifferent(fileIndex)); && (patchAction == PatchAction::Revert || fileNamesAreDifferent(fileIndex));
action->setEnabled(enabled); action->setEnabled(enabled);
} }
@@ -315,7 +307,7 @@ void DiffEditorWidgetController::sendChunkToCodePaster(int fileIndex, int chunkI
auto pasteService = ExtensionSystem::PluginManager::getObject<CodePaster::Service>(); auto pasteService = ExtensionSystem::PluginManager::getObject<CodePaster::Service>();
QTC_ASSERT(pasteService, return); QTC_ASSERT(pasteService, return);
const QString patch = m_document->makePatch(fileIndex, chunkIndex, {}, false); const QString patch = m_document->makePatch(fileIndex, chunkIndex, {}, PatchAction::Apply);
if (patch.isEmpty()) if (patch.isEmpty())
return; return;

View File

@@ -5,6 +5,7 @@
#include "diffutils.h" #include "diffutils.h"
#include <coreplugin/patchtool.h>
#include <utils/guard.h> #include <utils/guard.h>
#include <QObject> #include <QObject>
@@ -38,7 +39,7 @@ public:
int columnNumber); int columnNumber);
void setFontSettings(const TextEditor::FontSettings &fontSettings); void setFontSettings(const TextEditor::FontSettings &fontSettings);
void addCodePasterAction(QMenu *menu, int fileIndex, int chunkIndex); void addCodePasterAction(QMenu *menu, int fileIndex, int chunkIndex);
void addApplyRevertAction(QMenu *menu, int fileIndex, int chunkIndex, DiffSide side); void addPatchAction(QMenu *menu, int fileIndex, int chunkIndex, Core::PatchAction patchAction);
void addExtraActions(QMenu *menu, int fileIndex, int chunkIndex, const ChunkSelection &selection); void addExtraActions(QMenu *menu, int fileIndex, int chunkIndex, const ChunkSelection &selection);
void updateCannotDecodeInfo(); void updateCannotDecodeInfo();
void setBusyShowing(bool busy); void setBusyShowing(bool busy);
@@ -60,7 +61,7 @@ private:
bool isInProgress() const; bool isInProgress() const;
void toggleProgress(bool wasInProgress); void toggleProgress(bool wasInProgress);
void patch(bool revert, int fileIndex, int chunkIndex); void patch(Core::PatchAction patchAction, int fileIndex, int chunkIndex);
void sendChunkToCodePaster(int fileIndex, int chunkIndex); void sendChunkToCodePaster(int fileIndex, int chunkIndex);
bool chunkExists(int fileIndex, int chunkIndex) const; bool chunkExists(int fileIndex, int chunkIndex) const;
bool fileNamesAreDifferent(int fileIndex) const; bool fileNamesAreDifferent(int fileIndex) const;

View File

@@ -1107,8 +1107,9 @@ void SideBySideDiffEditorWidget::contextMenuRequested(DiffSide side, QMenu *menu
{ {
menu->addSeparator(); menu->addSeparator();
const PatchAction patchAction = side == LeftSide ? PatchAction::Apply : PatchAction::Revert;
m_controller.addCodePasterAction(menu, fileIndex, chunkIndex); m_controller.addCodePasterAction(menu, fileIndex, chunkIndex);
m_controller.addApplyRevertAction(menu, fileIndex, chunkIndex, side); m_controller.addPatchAction(menu, fileIndex, chunkIndex, patchAction);
m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection); m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection);
} }

View File

@@ -218,8 +218,8 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu, int fileIndex,
menu->addSeparator(); menu->addSeparator();
m_controller.addCodePasterAction(menu, fileIndex, chunkIndex); m_controller.addCodePasterAction(menu, fileIndex, chunkIndex);
m_controller.addApplyRevertAction(menu, fileIndex, chunkIndex, LeftSide); m_controller.addPatchAction(menu, fileIndex, chunkIndex, PatchAction::Apply);
m_controller.addApplyRevertAction(menu, fileIndex, chunkIndex, RightSide); m_controller.addPatchAction(menu, fileIndex, chunkIndex, PatchAction::Revert);
m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection); m_controller.addExtraActions(menu, fileIndex, chunkIndex, selection);
} }

View File

@@ -4,10 +4,8 @@
#include "giteditor.h" #include "giteditor.h"
#include "annotationhighlighter.h" #include "annotationhighlighter.h"
#include "branchadddialog.h"
#include "gitclient.h" #include "gitclient.h"
#include "gitsettings.h" #include "gitsettings.h"
#include "gitsubmiteditorwidget.h"
#include "gitconstants.h" #include "gitconstants.h"
#include "githighlighters.h" #include "githighlighters.h"
@@ -32,6 +30,7 @@
#define CHANGE_PATTERN "[a-f0-9]{7,40}" #define CHANGE_PATTERN "[a-f0-9]{7,40}"
using namespace Core;
using namespace Utils; using namespace Utils;
using namespace VcsBase; using namespace VcsBase;
@@ -214,7 +213,7 @@ void GitEditorWidget::setPlainText(const QString &text)
textDocument()->setPlainText(modText); textDocument()->setPlainText(modText);
} }
void GitEditorWidget::applyDiffChunk(const DiffChunk& chunk, bool revert) void GitEditorWidget::applyDiffChunk(const DiffChunk& chunk, PatchAction patchAction)
{ {
Utils::TemporaryFile patchFile("git-apply-chunk"); Utils::TemporaryFile patchFile("git-apply-chunk");
if (!patchFile.open()) if (!patchFile.open())
@@ -226,7 +225,7 @@ void GitEditorWidget::applyDiffChunk(const DiffChunk& chunk, bool revert)
patchFile.close(); patchFile.close();
QStringList args = {"--cached"}; QStringList args = {"--cached"};
if (revert) if (patchAction == PatchAction::Revert)
args << "--reverse"; args << "--reverse";
QString errorMessage; QString errorMessage;
if (GitClient::instance()->synchronousApplyPatch(baseDir, patchFile.fileName(), &errorMessage, args)) { if (GitClient::instance()->synchronousApplyPatch(baseDir, patchFile.fileName(), &errorMessage, args)) {
@@ -234,7 +233,7 @@ void GitEditorWidget::applyDiffChunk(const DiffChunk& chunk, bool revert)
VcsOutputWindow::append(tr("Chunk successfully staged")); VcsOutputWindow::append(tr("Chunk successfully staged"));
else else
VcsOutputWindow::append(errorMessage); VcsOutputWindow::append(errorMessage);
if (revert) if (patchAction == PatchAction::Revert)
emit diffChunkReverted(chunk); emit diffChunkReverted(chunk);
else else
emit diffChunkApplied(chunk); emit diffChunkApplied(chunk);
@@ -264,12 +263,12 @@ void GitEditorWidget::addDiffActions(QMenu *menu, const DiffChunk &chunk)
QAction *stageAction = menu->addAction(tr("Stage Chunk...")); QAction *stageAction = menu->addAction(tr("Stage Chunk..."));
connect(stageAction, &QAction::triggered, this, [this, chunk] { connect(stageAction, &QAction::triggered, this, [this, chunk] {
applyDiffChunk(chunk, false); applyDiffChunk(chunk, PatchAction::Apply);
}); });
QAction *unstageAction = menu->addAction(tr("Unstage Chunk...")); QAction *unstageAction = menu->addAction(tr("Unstage Chunk..."));
connect(unstageAction, &QAction::triggered, this, [this, chunk] { connect(unstageAction, &QAction::triggered, this, [this, chunk] {
applyDiffChunk(chunk, true); applyDiffChunk(chunk, PatchAction::Revert);
}); });
} }

View File

@@ -37,7 +37,7 @@ signals:
void toggleFilters(bool value); void toggleFilters(bool value);
private: private:
void applyDiffChunk(const VcsBase::DiffChunk& chunk, bool revert); void applyDiffChunk(const VcsBase::DiffChunk& chunk, Core::PatchAction patchAction);
void init() override; void init() override;
void addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk) override; void addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk) override;

View File

@@ -41,7 +41,6 @@
#include <QFileInfo> #include <QFileInfo>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <QMessageBox>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSet> #include <QSet>
#include <QTextBlock> #include <QTextBlock>
@@ -979,12 +978,12 @@ void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e)
// fileNameFromDiffSpecification() works. // fileNameFromDiffSpecification() works.
QAction *applyAction = menu->addAction(tr("Apply Chunk...")); QAction *applyAction = menu->addAction(tr("Apply Chunk..."));
connect(applyAction, &QAction::triggered, this, [this, chunk] { connect(applyAction, &QAction::triggered, this, [this, chunk] {
slotApplyDiffChunk(chunk, false); slotApplyDiffChunk(chunk, PatchAction::Apply);
}); });
// Revert a chunk from a VCS diff, which might be linked to reloading the diff. // Revert a chunk from a VCS diff, which might be linked to reloading the diff.
QAction *revertAction = menu->addAction(tr("Revert Chunk...")); QAction *revertAction = menu->addAction(tr("Revert Chunk..."));
connect(revertAction, &QAction::triggered, this, [this, chunk] { connect(revertAction, &QAction::triggered, this, [this, chunk] {
slotApplyDiffChunk(chunk, true); slotApplyDiffChunk(chunk, PatchAction::Revert);
}); });
// Custom diff actions // Custom diff actions
addDiffActions(menu, chunk); addDiffActions(menu, chunk);
@@ -1506,10 +1505,10 @@ bool VcsBaseEditorWidget::canApplyDiffChunk(const DiffChunk &dc) const
// Default implementation of revert: Apply a chunk by piping it into patch, // Default implementation of revert: Apply a chunk by piping it into patch,
// (passing '-R' for revert), assuming we got absolute paths from the VCS plugins. // (passing '-R' for revert), assuming we got absolute paths from the VCS plugins.
bool VcsBaseEditorWidget::applyDiffChunk(const DiffChunk &dc, bool revert) const bool VcsBaseEditorWidget::applyDiffChunk(const DiffChunk &dc, PatchAction patchAction) const
{ {
return Core::PatchTool::runPatch(dc.asPatch(d->m_workingDirectory), return Core::PatchTool::runPatch(dc.asPatch(d->m_workingDirectory),
FilePath::fromString(d->m_workingDirectory), 0, revert); FilePath::fromString(d->m_workingDirectory), 0, patchAction);
} }
QString VcsBaseEditorWidget::fileNameFromDiffSpecification(const QTextBlock &inBlock, QString *header) const QString VcsBaseEditorWidget::fileNameFromDiffSpecification(const QTextBlock &inBlock, QString *header) const
@@ -1586,16 +1585,13 @@ bool VcsBaseEditorWidget::hasDiff() const
} }
} }
void VcsBaseEditorWidget::slotApplyDiffChunk(const DiffChunk &chunk, bool revert) void VcsBaseEditorWidget::slotApplyDiffChunk(const DiffChunk &chunk, PatchAction patchAction)
{ {
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk"); if (!PatchTool::confirmPatching(this, patchAction))
const QString question = revert ? tr("Would you like to revert the chunk?")
: tr("Would you like to apply the chunk?");
if (QMessageBox::No == QMessageBox::question(this, title, question, QMessageBox::Yes|QMessageBox::No))
return; return;
if (applyDiffChunk(chunk, revert)) { if (applyDiffChunk(chunk, patchAction)) {
if (revert) if (patchAction == PatchAction::Revert) // TODO: make just one signal
emit diffChunkReverted(chunk); emit diffChunkReverted(chunk);
else else
emit diffChunkApplied(chunk); emit diffChunkApplied(chunk);

View File

@@ -5,6 +5,7 @@
#include "vcsbase_global.h" #include "vcsbase_global.h"
#include <coreplugin/patchtool.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <QSet> #include <QSet>
@@ -245,14 +246,14 @@ private:
void slotJumpToEntry(int); void slotJumpToEntry(int);
void slotCursorPositionChanged() override; void slotCursorPositionChanged() override;
void slotAnnotateRevision(const QString &change); void slotAnnotateRevision(const QString &change);
void slotApplyDiffChunk(const DiffChunk &chunk, bool revert); void slotApplyDiffChunk(const DiffChunk &chunk, Core::PatchAction patchAction);
void slotPaste(); void slotPaste();
void showProgressIndicator(); void showProgressIndicator();
void hideProgressIndicator(); void hideProgressIndicator();
bool canApplyDiffChunk(const DiffChunk &dc) const; bool canApplyDiffChunk(const DiffChunk &dc) const;
// Revert a patch chunk. Default implementation uses patch.exe // Revert a patch chunk. Default implementation uses patch.exe
bool applyDiffChunk(const DiffChunk &dc, bool revert = false) const; bool applyDiffChunk(const DiffChunk &dc, Core::PatchAction patchAction) const;
// Indicates if the editor has diff contents. If true, an appropriate // Indicates if the editor has diff contents. If true, an appropriate
// highlighter is used and double-click inside a diff chunk jumps to // highlighter is used and double-click inside a diff chunk jumps to