Commit d7cddd4e authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

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.
parent 82ce382f
......@@ -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"
......@@ -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;
......
......@@ -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);
}
}
}
......
......@@ -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"
......@@ -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;
......
......@@ -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();
}
......
......@@ -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() +
......
......@@ -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;
......
......@@ -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)) {
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment