From d7cddd4e1764d6513094bb47ccd2e73f2f4512c8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Mon, 28 Mar 2011 11:59:26 +0200 Subject: [PATCH] VCS[Bazaar, Mercurial]: Add diff formatting, revert chunk. Add toolbar controls for ignore-whitespace to editors and wire 'Revert Chunk' context menus. Fix Bazaar diff interaction (find the file on doubleclick). Introduce initializeDiffEditor to BaseClient and wire the editors there. --- src/plugins/bazaar/bazaarclient.cpp | 95 +++++++++++++++++++++- src/plugins/bazaar/bazaarclient.h | 11 ++- src/plugins/bazaar/bazaareditor.cpp | 24 +++--- src/plugins/mercurial/mercurialclient.cpp | 96 +++++++++++++++++++++-- src/plugins/mercurial/mercurialclient.h | 10 ++- src/plugins/mercurial/mercurialeditor.cpp | 20 ++--- src/plugins/vcsbase/vcsbaseclient.cpp | 12 ++- src/plugins/vcsbase/vcsbaseclient.h | 8 +- src/plugins/vcsbase/vcsbaseeditor.cpp | 2 + src/plugins/vcsbase/vcsbaseplugin.cpp | 2 +- 10 files changed, 246 insertions(+), 34 deletions(-) diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index e45f0b4f374..8ec9cf88a46 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -36,6 +36,10 @@ #include <vcsbase/vcsbaseclientsettings.h> #include <vcsbase/vcsbaseplugin.h> +#include <vcsbase/vcsbaseeditor.h> +#include <vcsbase/vcsbaseeditorparameterwidget.h> + +#include <utils/qtcassert.h> #include <QtCore/QDir> #include <QtCore/QFileInfo> @@ -314,9 +318,23 @@ QStringList BazaarClient::annotateArguments(const QString &file, return args << file; } -QStringList BazaarClient::diffArguments(const QStringList &files) const +QStringList BazaarClient::diffArguments(const QStringList &files, + const ExtraCommandOptions &extraOptions) const { QStringList args; + foreach (const QVariant &extraOption, extraOptions) { + switch (extraOption.type()) { + case QVariant::String: + args.append(extraOption.toString()); + break; + case QVariant::StringList: + args.append(extraOption.toStringList()); + break; + default: + QTC_ASSERT(false, continue; ) + break; + } + } if (!files.isEmpty()) args.append(files); return args; @@ -324,7 +342,7 @@ QStringList BazaarClient::diffArguments(const QStringList &files) const QStringList BazaarClient::logArguments(const QStringList &files) const { - return diffArguments(files); + return diffArguments(files, ExtraCommandOptions()); } QStringList BazaarClient::statusArguments(const QString &file) const @@ -410,5 +428,78 @@ QStringList BazaarClient::commonPullOrPushArguments(const ExtraCommandOptions &e return args; } +// Collect all parameters required for a diff to be able to associate them +// with a diff editor and re-run the diff with parameters. +struct BazaarDiffParameters +{ + QString workingDir; + QStringList files; + VCSBase::VCSBaseClient::ExtraCommandOptions extraOptions; +}; + +// Parameter widget controlling whitespace diff mode, associated with a parameter +class BazaarDiffParameterWidget : public VCSBase::VCSBaseEditorParameterWidget +{ + Q_OBJECT +public: + explicit BazaarDiffParameterWidget(const BazaarDiffParameters &p, QWidget *parent = 0); + +signals: + void reRunDiff(const Bazaar::Internal::BazaarDiffParameters &); + +private slots: + void triggerReRun(); + +private: + const BazaarDiffParameters m_parameters; +}; + +BazaarDiffParameterWidget::BazaarDiffParameterWidget(const BazaarDiffParameters &p, QWidget *parent) : + VCSBase::VCSBaseEditorParameterWidget(parent), m_parameters(p) +{ + addIgnoreWhiteSpaceButton(QLatin1String("-w")); + addIgnoreBlankLinesButton(QLatin1String("-B")); + connect(this, SIGNAL(argumentsChanged()), this, SLOT(triggerReRun())); +} + +void BazaarDiffParameterWidget::triggerReRun() +{ + BazaarDiffParameters effectiveParameters = m_parameters; + // Bazaar wants "--diff-options=-w -B.." + const QStringList formatArguments = arguments(); + if (!formatArguments.isEmpty()) { + const QString a = QLatin1String("--diff-options=") + + formatArguments.join(QString(QLatin1Char(' '))); + effectiveParameters.extraOptions.insert(42, QVariant(a)); + } + emit reRunDiff(effectiveParameters); +} + +void BazaarClient::bazaarDiff(const Bazaar::Internal::BazaarDiffParameters &p) +{ + diff(p.workingDir, p.files, p.extraOptions); +} + +void BazaarClient::initializeDiffEditor(const QString &workingDir, const QStringList &files, + const VCSBase::VCSBaseClient::ExtraCommandOptions &extra, + VCSBase::VCSBaseEditorWidget *diffEditorWidget) +{ + // Wire up the parameter widget to trigger a re-run on + // parameter change and 'revert' from inside the diff editor. + BazaarDiffParameters parameters; + parameters.workingDir = workingDir; + parameters.files = files; + parameters.extraOptions = extra; + diffEditorWidget->setRevertDiffChunkEnabled(true); + BazaarDiffParameterWidget *pw = new BazaarDiffParameterWidget(parameters); + connect(pw, SIGNAL(reRunDiff(Bazaar::Internal::BazaarDiffParameters)), + this, SLOT(bazaarDiff(Bazaar::Internal::BazaarDiffParameters))); + connect(diffEditorWidget, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)), + pw, SLOT(triggerReRun())); + diffEditorWidget->setConfigurationWidget(pw); +} + } //namespace Internal } // namespace Bazaar + +#include "bazaarclient.moc" diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h index e1118b3a814..79ad273241b 100644 --- a/src/plugins/bazaar/bazaarclient.h +++ b/src/plugins/bazaar/bazaarclient.h @@ -39,9 +39,11 @@ namespace Bazaar { namespace Internal { +struct BazaarDiffParameters; class BazaarClient : public VCSBase::VCSBaseClient { + Q_OBJECT public: enum ExtraOptionId { @@ -75,6 +77,9 @@ public: BranchInfo synchronousBranchQuery(const QString &repositoryRoot) const; virtual QString findTopLevelForFile(const QFileInfo &file) const; +private slots: + void bazaarDiff(const Bazaar::Internal::BazaarDiffParameters &p); + protected: virtual QString vcsEditorKind(VCSCommand cmd) const; @@ -94,7 +99,11 @@ protected: virtual QStringList revertAllArguments(const QString &revision) const; virtual QStringList annotateArguments(const QString &file, const QString &revision, int lineNumber) const; - virtual QStringList diffArguments(const QStringList &files) const; + virtual QStringList diffArguments(const QStringList &files, + const ExtraCommandOptions &extraOptions) const; + virtual void initializeDiffEditor(const QString &workingDir, const QStringList &files, + const VCSBase::VCSBaseClient::ExtraCommandOptions &extra, + VCSBase::VCSBaseEditorWidget *diffEditorWidget); virtual QStringList logArguments(const QStringList &files) const; virtual QStringList statusArguments(const QString &file) const; virtual QStringList viewArguments(const QString &revision) const; diff --git a/src/plugins/bazaar/bazaareditor.cpp b/src/plugins/bazaar/bazaareditor.cpp index b6e2c484110..f0beeeea57c 100644 --- a/src/plugins/bazaar/bazaareditor.cpp +++ b/src/plugins/bazaar/bazaareditor.cpp @@ -107,16 +107,22 @@ VCSBase::BaseAnnotationHighlighter *BazaarEditor::createAnnotationHighlighter(co return new BazaarAnnotationHighlighter(changes); } -QString BazaarEditor::fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const +QString BazaarEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const { - const QString filechangeId(QLatin1String("+++ b/")); - QTextBlock::iterator iterator; - for (iterator = diffFileSpec.begin(); !(iterator.atEnd()); iterator++) { - QTextFragment fragment = iterator.fragment(); - if(fragment.isValid()) { - if (fragment.text().startsWith(filechangeId)) { - const QString filename = fragment.text().remove(0, filechangeId.size()); - return findDiffFile(filename, BazaarPlugin::instance()->versionControl()); + // Check for: + // === modified file 'mainwindow.cpp' + // --- mainwindow.cpp<tab>2011-03-28 08:12:28 +0000 + // +++ mainwindow.cpp<tab>2011-03-28 08:53:55 +0000 + const QString newFileIndicator = QLatin1String("+++ "); + const QChar tab = QLatin1Char('\t'); + for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { + const QString line = block.text(); + if (line.startsWith(newFileIndicator)) { + const int tabIndex = line.indexOf(tab); + if (tabIndex != -1) { + const QString diffFileName = line.mid(newFileIndicator.size(), + tabIndex - newFileIndicator.size()); + return findDiffFile(diffFileName); } } } diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index ed1a1cdf8d9..7e6108be72e 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -36,14 +36,17 @@ #include <vcsbase/vcsbaseoutputwindow.h> #include <vcsbase/vcsbaseplugin.h> +#include <vcsbase/vcsbaseeditor.h> +#include <vcsbase/vcsbaseeditorparameterwidget.h> #include <vcsbase/vcsjobrunner.h> #include <utils/synchronousprocess.h> +#include <utils/qtcassert.h> -#include <QDir> -#include <QFileInfo> -#include <QTextCodec> -#include <QTextStream> -#include <QVariant> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> +#include <QtCore/QVariant> namespace Mercurial { namespace Internal { @@ -429,10 +432,24 @@ QStringList MercurialClient::annotateArguments(const QString &file, return args << file; } -QStringList MercurialClient::diffArguments(const QStringList &files) const +QStringList MercurialClient::diffArguments(const QStringList &files, + const ExtraCommandOptions &extraOptions) const { QStringList args; args << QLatin1String("-g") << QLatin1String("-p") << QLatin1String("-U 8"); + foreach (const QVariant &extraOption, extraOptions) { + switch (extraOption.type()) { + case QVariant::String: + args.append(extraOption.toString()); + break; + case QVariant::StringList: + args.append(extraOption.toStringList()); + break; + default: + QTC_ASSERT(false, continue; ) + break; + } + } if (!files.isEmpty()) args.append(files); return args; @@ -487,5 +504,72 @@ QPair<QString, QString> MercurialClient::parseStatusLine(const QString &line) co return status; } +// Collect all parameters required for a diff to be able to associate them +// with a diff editor and re-run the diff with parameters. +struct MercurialDiffParameters +{ + QString workingDir; + QStringList files; + VCSBase::VCSBaseClient::ExtraCommandOptions extraOptions; +}; + +// Parameter widget controlling whitespace diff mode, associated with a parameter +class MercurialDiffParameterWidget : public VCSBase::VCSBaseEditorParameterWidget +{ + Q_OBJECT +public: + explicit MercurialDiffParameterWidget(const MercurialDiffParameters &p, QWidget *parent = 0); + +signals: + void reRunDiff(const Mercurial::Internal::MercurialDiffParameters &); + +private slots: + void triggerReRun(); + +private: + const MercurialDiffParameters m_parameters; +}; + +MercurialDiffParameterWidget::MercurialDiffParameterWidget(const MercurialDiffParameters &p, QWidget *parent) : + VCSBase::VCSBaseEditorParameterWidget(parent), m_parameters(p) +{ + addIgnoreWhiteSpaceButton(QLatin1String("-w")); + addIgnoreBlankLinesButton(QLatin1String("-B")); + connect(this, SIGNAL(argumentsChanged()), this, SLOT(triggerReRun())); +} + +void MercurialDiffParameterWidget::triggerReRun() +{ + MercurialDiffParameters effectiveParameters = m_parameters; + effectiveParameters.extraOptions.insert(42, QVariant(arguments())); + emit reRunDiff(effectiveParameters); +} + +void MercurialClient::mercurialDiff(const Mercurial::Internal::MercurialDiffParameters &p) +{ + diff(p.workingDir, p.files, p.extraOptions); +} + +void MercurialClient::initializeDiffEditor(const QString &workingDir, const QStringList &files, + const VCSBase::VCSBaseClient::ExtraCommandOptions &extra, + VCSBase::VCSBaseEditorWidget *diffEditorWidget) +{ + // Wire up the parameter widget to trigger a re-run on + // parameter change and 'revert' from inside the diff editor. + MercurialDiffParameters parameters; + parameters.workingDir = workingDir; + parameters.files = files; + parameters.extraOptions = extra; + diffEditorWidget->setRevertDiffChunkEnabled(true); + MercurialDiffParameterWidget *pw = new MercurialDiffParameterWidget(parameters); + connect(pw, SIGNAL(reRunDiff(Mercurial::Internal::MercurialDiffParameters)), + this, SLOT(mercurialDiff(Mercurial::Internal::MercurialDiffParameters))); + connect(diffEditorWidget, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)), + pw, SLOT(triggerReRun())); + diffEditorWidget->setConfigurationWidget(pw); +} + } // namespace Internal } // namespace Mercurial + +#include "mercurialclient.moc" diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h index b36679ca781..278c1e9894e 100644 --- a/src/plugins/mercurial/mercurialclient.h +++ b/src/plugins/mercurial/mercurialclient.h @@ -38,6 +38,7 @@ namespace Mercurial { namespace Internal { +struct MercurialDiffParameters; class MercurialClient : public VCSBase::VCSBaseClient { @@ -71,6 +72,9 @@ public: void outgoing(const QString &repositoryRoot); QString vcsGetRepositoryURL(const QString &directory); +private slots: + void mercurialDiff(const Mercurial::Internal::MercurialDiffParameters &); + public: virtual QString findTopLevelForFile(const QFileInfo &file) const; @@ -93,7 +97,11 @@ protected: virtual QStringList revertAllArguments(const QString &revision) const; virtual QStringList annotateArguments(const QString &file, const QString &revision, int lineNumber) const; - virtual QStringList diffArguments(const QStringList &files) const; + virtual QStringList diffArguments(const QStringList &files, + const ExtraCommandOptions &extraOptions) const; + virtual void initializeDiffEditor(const QString &workingDir, const QStringList &files, + const VCSBase::VCSBaseClient::ExtraCommandOptions &extra, + VCSBase::VCSBaseEditorWidget *ed); virtual QStringList logArguments(const QStringList &files) const; virtual QStringList statusArguments(const QString &file) const; virtual QStringList viewArguments(const QString &revision) const; diff --git a/src/plugins/mercurial/mercurialeditor.cpp b/src/plugins/mercurial/mercurialeditor.cpp index 3c5a94152f8..3f425de82be 100644 --- a/src/plugins/mercurial/mercurialeditor.cpp +++ b/src/plugins/mercurial/mercurialeditor.cpp @@ -102,18 +102,18 @@ VCSBase::BaseAnnotationHighlighter *MercurialEditor::createAnnotationHighlighter return new MercurialAnnotationHighlighter(changes); } -QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const +QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const { - const QString filechangeId(QLatin1String("+++ b/")); - QTextBlock::iterator iterator; - for (iterator = diffFileSpec.begin(); !(iterator.atEnd()); iterator++) { - QTextFragment fragment = iterator.fragment(); - if(fragment.isValid()) { - if (fragment.text().startsWith(filechangeId)) { - const QString filename = fragment.text().remove(0, filechangeId.size()); - return findDiffFile(filename, MercurialPlugin::instance()->versionControl()); - } + // git-compatible format: check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff) + // Go back chunks. + const QString newFileIndicator = QLatin1String("+++ b/"); + for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { + QString diffFileName = block.text(); + if (diffFileName.startsWith(newFileIndicator)) { + diffFileName.remove(0, newFileIndicator.size()); + return findDiffFile(diffFileName, MercurialPlugin::instance()->versionControl()); } + } return QString(); } diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 66f0c4b2ec3..03ef4234f61 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -262,11 +262,12 @@ void VCSBaseClient::annotate(const QString &workingDir, const QString &file, enqueueJob(job); } -void VCSBaseClient::diff(const QString &workingDir, const QStringList &files) +void VCSBaseClient::diff(const QString &workingDir, const QStringList &files, + const ExtraCommandOptions &extraOptions) { const QString vcsCmdString = vcsCommandString(DiffCommand); QStringList args; - args << vcsCmdString << diffArguments(files); + args << vcsCmdString << diffArguments(files, extraOptions); const QString kind = vcsEditorKind(DiffCommand); const QString id = VCSBase::VCSBaseEditorWidget::getTitleId(workingDir, files); const QString title = vcsEditorTitle(vcsCmdString, id); @@ -274,6 +275,7 @@ void VCSBaseClient::diff(const QString &workingDir, const QStringList &files) VCSBase::VCSBaseEditorWidget *editor = createVCSEditor(kind, title, source, true, vcsCmdString.toLatin1().constData(), id); editor->setDiffBaseDirectory(workingDir); + initializeDiffEditor(workingDir, files, extraOptions, editor); QSharedPointer<VCSJob> job(new VCSJob(workingDir, args, editor)); enqueueJob(job); @@ -444,6 +446,12 @@ void VCSBaseClient::settingsChanged() } } +void VCSBaseClient::initializeDiffEditor(const QString & /* workingDir */, const QStringList & /* files */, + const ExtraCommandOptions & /* extraOptions */, + VCSBaseEditorWidget *) +{ +} + QString VCSBaseClient::vcsEditorTitle(const QString &vcsCmd, const QString &sourceId) const { return QFileInfo(d->m_clientSettings.binary()).baseName() + diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index a9ef78eb7c6..e72483592eb 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -89,7 +89,8 @@ public: const ExtraCommandOptions &extraOptions = ExtraCommandOptions()); void annotate(const QString &workingDir, const QString &file, const QString revision = QString(), int lineNumber = -1); - void diff(const QString &workingDir, const QStringList &files = QStringList()); + void diff(const QString &workingDir, const QStringList &files = QStringList(), + const ExtraCommandOptions &extraOptions = ExtraCommandOptions()); void log(const QString &workingDir, const QStringList &files = QStringList(), bool enableAnnotationContextMenu = false); void status(const QString &workingDir, const QString &file = QString()); @@ -154,7 +155,10 @@ protected: virtual QStringList revertAllArguments(const QString &revision) const = 0; virtual QStringList annotateArguments(const QString &file, const QString &revision, int lineNumber) const = 0; - virtual QStringList diffArguments(const QStringList &files) const = 0; + virtual QStringList diffArguments(const QStringList &files, + const ExtraCommandOptions &extraOptions) const = 0; + virtual void initializeDiffEditor(const QString &workingDir, const QStringList &files, + const ExtraCommandOptions &extraOptions, VCSBaseEditorWidget *ed); virtual QStringList logArguments(const QStringList &files) const = 0; virtual QStringList statusArguments(const QString &file) const = 0; virtual QStringList viewArguments(const QString &revision) const = 0; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 4e5da7bf9d0..c8797743323 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -700,6 +700,8 @@ DiffChunk VCSBaseEditorWidget::diffChunk(QTextCursor cursor) const return rc; // Concatenate chunk and convert QString unicode = block.text(); + if (!unicode.endsWith(QLatin1Char('\n'))) // Missing in case of hg. + unicode.append(QLatin1Char('\n')); for (block = block.next() ; block.isValid() ; block = block.next()) { const QString line = block.text(); if (checkChunkLine(line, &chunkStart)) { diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 24f28b86510..0df8d519f05 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -927,7 +927,7 @@ bool VCSBasePlugin::runPatch(const QByteArray &input, const QString &workingDire return false; } if (patchProcess.exitCode() != 0) { - ow->appendError(tr("'%1' failed (exit code %2).").arg(patchProcess.exitCode())); + ow->appendError(tr("'%1' failed (exit code %2).").arg(patch).arg(patchProcess.exitCode())); return false; } return true; -- GitLab