diff --git a/src/plugins/bazaar/bazaareditor.cpp b/src/plugins/bazaar/bazaareditor.cpp index 48a1687b8dbbe2d7eba642366073a1d7bd1747f6..99c241d12742ff5224700f7af750f89c65c83e8a 100644 --- a/src/plugins/bazaar/bazaareditor.cpp +++ b/src/plugins/bazaar/bazaareditor.cpp @@ -52,11 +52,13 @@ using namespace Bazaar; BazaarEditor::BazaarEditor(const VcsBase::VcsBaseEditorParameters *type, QWidget *parent) : VcsBase::VcsBaseEditorWidget(type, parent), m_changesetId(QLatin1String(Constants::CHANGESET_ID)), - m_exactChangesetId(QLatin1String(Constants::CHANGESET_ID_EXACT)), - m_diffFileId(QLatin1String("^=== [a-z]+ [a-z]+ '(.*)'\\s*")) + m_exactChangesetId(QLatin1String(Constants::CHANGESET_ID_EXACT)) { setAnnotateRevisionTextFormat(tr("Annotate %1")); setAnnotatePreviousRevisionTextFormat(tr("Annotate parent revision %1")); + // Diff format: + // === <change> <file|dir> 'mainwindow.cpp' + setDiffFilePattern(QRegExp(QLatin1String("^=== [a-z]+ [a-z]+ '(.+)'\\s*"))); } QSet<QString> BazaarEditor::annotationChanges() const @@ -111,25 +113,8 @@ QString BazaarEditor::changeUnderCursor(const QTextCursor &cursorIn) const return QString(); } -QRegExp BazaarEditor::diffFilePattern() const -{ - return m_diffFileId; -} - VcsBase::BaseAnnotationHighlighter *BazaarEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new BazaarAnnotationHighlighter(changes, bg); } - -QString BazaarEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // Check for: - // === <change> <file|dir> 'mainwindow.cpp' - for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { - const QString line = block.text(); - if (m_diffFileId.indexIn(line) != -1) - return findDiffFile(m_diffFileId.cap(1)); - } - return QString(); -} diff --git a/src/plugins/bazaar/bazaareditor.h b/src/plugins/bazaar/bazaareditor.h index b895fb6593bf899daeb38a6faff2c8ddbec51911..6b92909ecc9cad32ee0f73c03353f89e8292571c 100644 --- a/src/plugins/bazaar/bazaareditor.h +++ b/src/plugins/bazaar/bazaareditor.h @@ -46,13 +46,10 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &cursor) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const; mutable QRegExp m_changesetId; mutable QRegExp m_exactChangesetId; - mutable QRegExp m_diffFileId; }; } // namespace Internal diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 618b9d3ca7b0546e0d8646684257e03fb39bb507..bfee3ee6348f163fcbb77765d74eddd421a3b084 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -591,6 +591,41 @@ void BazaarPlugin::diffFromEditorSelected(const QStringList &files) m_client->diff(m_submitRepository, files); } +#ifdef WITH_TESTS +#include <QTest> + +void BazaarPlugin::testDiffFileResolving_data() +{ + QTest::addColumn<QByteArray>("header"); + QTest::addColumn<QByteArray>("fileName"); + + QTest::newRow("New") << QByteArray( + "=== added file 'src/plugins/bazaar/bazaareditor.cpp'\n" + "--- src/plugins/bazaar/bazaareditor.cpp\t1970-01-01 00:00:00 +0000\n" + "+++ src/plugins/bazaar/bazaareditor.cpp\t2013-01-20 21:39:47 +0000\n" + "@@ -0,0 +1,121 @@\n\n") + << QByteArray("src/plugins/bazaar/bazaareditor.cpp"); + QTest::newRow("Deleted") << QByteArray( + "=== removed file 'src/plugins/bazaar/bazaareditor.cpp'\n" + "--- src/plugins/bazaar/bazaareditor.cpp\t2013-01-20 21:39:47 +0000\n" + "+++ src/plugins/bazaar/bazaareditor.cpp\t1970-01-01 00:00:00 +0000\n" + "@@ -1,121 +0,0 @@\n\n") + << QByteArray("src/plugins/bazaar/bazaareditor.cpp"); + QTest::newRow("Modified") << QByteArray( + "=== modified file 'src/plugins/bazaar/bazaareditor.cpp'\n" + "--- src/plugins/bazaar/bazaareditor.cpp\t2010-08-27 14:12:44 +0000\n" + "+++ src/plugins/bazaar/bazaareditor.cpp\t2011-02-28 21:24:19 +0000\n" + "@@ -727,6 +727,9 @@\n\n") + << QByteArray("src/plugins/bazaar/bazaareditor.cpp"); +} + +void BazaarPlugin::testDiffFileResolving() +{ + BazaarEditor editor(editorParameters + 3, 0); + VcsBase::VcsBaseEditorWidget::testDiffFileResolving(&editor); +} +#endif + void BazaarPlugin::commitFromEditor() { // Close the submit editor diff --git a/src/plugins/bazaar/bazaarplugin.h b/src/plugins/bazaar/bazaarplugin.h index ff6b6fbbd7652162cada0542a2fb8727f2ae9aa0..b483e2ef140bc8470a66e59887e0ad29538a7a9f 100644 --- a/src/plugins/bazaar/bazaarplugin.h +++ b/src/plugins/bazaar/bazaarplugin.h @@ -112,6 +112,10 @@ private slots: void showCommitWidget(const QList<VcsBase::VcsBaseClient::StatusItem> &status); void commitFromEditor(); void diffFromEditorSelected(const QStringList &files); +#ifdef WITH_TESTS + void testDiffFileResolving_data(); + void testDiffFileResolving(); +#endif protected: void updateActions(VcsBase::VcsBasePlugin::ActionState); diff --git a/src/plugins/clearcase/clearcaseeditor.cpp b/src/plugins/clearcase/clearcaseeditor.cpp index c00a973b428c194ccca4f576177805d0588fa927..63d7964ecedd78e96f68d53e8c397a4fc143707d 100644 --- a/src/plugins/clearcase/clearcaseeditor.cpp +++ b/src/plugins/clearcase/clearcaseeditor.cpp @@ -51,6 +51,12 @@ ClearCaseEditor::ClearCaseEditor(const VcsBase::VcsBaseEditorParameters *type, m_versionNumberPattern(QLatin1String("[\\\\/]main[\\\\/][^ \t\n\"]*")) { QTC_ASSERT(m_versionNumberPattern.isValid(), return); + // Diff formats: + // "+++ D:\depot\...\mainwindow.cpp@@\main\3" (versioned) + // "+++ D:\depot\...\mainwindow.cpp[TAB]Sun May 01 14:22:37 2011" (local) + QRegExp diffFilePattern(QLatin1String("^[-+]{3} ([^\\t]+)(?:@@|\\t)")); + diffFilePattern.setMinimal(true); + setDiffFilePattern(diffFilePattern); setAnnotateRevisionTextFormat(tr("Annotate version \"%1\"")); } @@ -87,41 +93,8 @@ QString ClearCaseEditor::changeUnderCursor(const QTextCursor &c) const return QString(); } -/* - Diff header format (on Windows, native separators are used after the @@) ---- main.cpp@@\main\2 -+++ main.cpp@@\main\1 -@@ -6,6 +6,5 @@ -*/ -QRegExp ClearCaseEditor::diffFilePattern() const -{ - return QRegExp(QLatin1String("^[-+][-+][-+] ")); -} - VcsBase::BaseAnnotationHighlighter *ClearCaseEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new ClearCaseAnnotationHighlighter(changes, bg); } - -QString ClearCaseEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // "+++ D:\depot\...\mainwindow.cpp@@\main\3" - // "+++ D:\depot\...\mainwindow.cpp[TAB]Sun May 01 14:22:37 2011" - // Go back chunks - const QString diffIndicator = QLatin1String("+++ "); - for (QTextBlock block = inBlock; block.isValid() ; block = block.previous()) { - QString diffFileName = block.text(); - if (diffFileName.startsWith(diffIndicator)) { - diffFileName.remove(0, diffIndicator.size()); - const int tabIndex = diffFileName.indexOf(QRegExp(QLatin1String("@@|\t"))); - if (tabIndex != -1) - diffFileName.truncate(tabIndex); - const QString rc = findDiffFile(diffFileName); - if (ClearCase::Constants::debug) - qDebug() << Q_FUNC_INFO << diffFileName << rc << source(); - return rc; - } - } - return QString(); -} diff --git a/src/plugins/clearcase/clearcaseeditor.h b/src/plugins/clearcase/clearcaseeditor.h index afb795536660f9908fc9c5b0f67c37d6674e794b..18577d95466f4fa711cd4beea460245d865833e7 100644 --- a/src/plugins/clearcase/clearcaseeditor.h +++ b/src/plugins/clearcase/clearcaseeditor.h @@ -49,11 +49,9 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const; - mutable QRegExp m_versionNumberPattern; + QRegExp m_versionNumberPattern; }; } // namespace Internal diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 048d50a2347ffe47067b09ac0b822278033b4521..215a0741e21f57fc079a7150c52de942dfacc0d7 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -96,7 +96,9 @@ #include <QVariant> #include <QVBoxLayout> #include <QXmlStreamReader> - +#ifdef WITH_TESTS +#include <QTest> +#endif namespace ClearCase { namespace Internal { @@ -1943,6 +1945,26 @@ void ClearCasePlugin::sync(QFutureInterface<void> &future, QString topLevel, QSt ccSync.run(future, topLevel, files); } +#ifdef WITH_TESTS +void ClearCasePlugin::testDiffFileResolving_data() +{ + QTest::addColumn<QByteArray>("header"); + QTest::addColumn<QByteArray>("fileName"); + + QTest::newRow("Modified") << QByteArray( + "--- src/plugins/clearcase/clearcaseeditor.cpp@@/main/1\t2013-01-20 23:45:48.549615210 +0200\n" + "+++ src/plugins/clearcase/clearcaseeditor.cpp@@/main/2\t2013-01-20 23:45:53.217604679 +0200\n" + "@@ -58,6 +58,10 @@\n\n") + << QByteArray("src/plugins/clearcase/clearcaseeditor.cpp"); +} + +void ClearCasePlugin::testDiffFileResolving() +{ + ClearCaseEditor editor(editorParameters + 3, 0); + VcsBase::VcsBaseEditorWidget::testDiffFileResolving(&editor); +} +#endif + } // namespace Internal } // namespace ClearCase diff --git a/src/plugins/clearcase/clearcaseplugin.h b/src/plugins/clearcase/clearcaseplugin.h index 7f8a5e32525949743d70e0d9b41f2a391a8a90b6..8b8f976eb51b25658dffe8dbeabcebb06df1b1ff 100644 --- a/src/plugins/clearcase/clearcaseplugin.h +++ b/src/plugins/clearcase/clearcaseplugin.h @@ -192,6 +192,10 @@ private slots: void syncSlot(); void closing(); void updateStatusActions(); +#ifdef WITH_TESTS + void testDiffFileResolving_data(); + void testDiffFileResolving(); +#endif protected: void updateActions(VcsBase::VcsBasePlugin::ActionState); diff --git a/src/plugins/cvs/cvseditor.cpp b/src/plugins/cvs/cvseditor.cpp index f2624fb15f2cd49d7cab307671c891ee0c5b20e9..a2de1f235ae1821d0cfb8ca3e94dd0a0ccc56eed 100644 --- a/src/plugins/cvs/cvseditor.cpp +++ b/src/plugins/cvs/cvseditor.cpp @@ -55,6 +55,15 @@ CvsEditor::CvsEditor(const VcsBase::VcsBaseEditorParameters *type, { QTC_ASSERT(m_revisionAnnotationPattern.isValid(), return); QTC_ASSERT(m_revisionLogPattern.isValid(), return); + /* Diff format: + \code + cvs diff -d -u -r1.1 -r1.2: + --- mainwindow.cpp<\t>13 Jul 2009 13:50:15 -0000<tab>1.1 + +++ mainwindow.cpp<\t>14 Jul 2009 07:09:24 -0000<tab>1.2 + @@ -6,6 +6,5 @@ + \endcode + */ + setDiffFilePattern(QRegExp(QLatin1String("^[-+]{3} ([^\\t]+)"))); setAnnotateRevisionTextFormat(tr("Annotate revision \"%1\"")); } @@ -113,42 +122,12 @@ QString CvsEditor::changeUnderCursor(const QTextCursor &c) const return QString(); } -/* \code -cvs diff -d -u -r1.1 -r1.2: ---- mainwindow.cpp<\t>13 Jul 2009 13:50:15 -0000 <\t>1.1 -+++ mainwindow.cpp<\t>14 Jul 2009 07:09:24 -0000<\t>1.2 -@@ -6,6 +6,5 @@ -\endcode -*/ -QRegExp CvsEditor::diffFilePattern() const -{ - return QRegExp(QLatin1String("^[-+][-+][-+] .*1\\.[\\d\\.]+$")); -} - VcsBase::BaseAnnotationHighlighter *CvsEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new CvsAnnotationHighlighter(changes, bg); } -QString CvsEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // "+++ mainwindow.cpp<\t>13 Jul 2009 13:50:15 -0000 1.1" - // Go back chunks - const QString diffIndicator = QLatin1String("+++ "); - for (QTextBlock block = inBlock; block.isValid() ; block = block.previous()) { - QString diffFileName = block.text(); - if (diffFileName.startsWith(diffIndicator)) { - diffFileName.remove(0, diffIndicator.size()); - const int tabIndex = diffFileName.indexOf(QLatin1Char('\t')); - if (tabIndex != -1) - diffFileName.truncate(tabIndex); - return findDiffFile(diffFileName); - } - } - return QString(); -} - QStringList CvsEditor::annotationPreviousVersions(const QString &revision) const { if (isFirstRevision(revision)) diff --git a/src/plugins/cvs/cvseditor.h b/src/plugins/cvs/cvseditor.h index 5e4a2fda980a99fcacb690441bf5a3962dd02b1f..d9e63275235cfc4c9af9aa8618841f6c2fec293d 100644 --- a/src/plugins/cvs/cvseditor.h +++ b/src/plugins/cvs/cvseditor.h @@ -48,9 +48,7 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const; QStringList annotationPreviousVersions(const QString &revision) const; mutable QRegExp m_revisionAnnotationPattern; diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index 40997ffcd6c7cd50f110a4fb79e8793e53d0c547..69e0b52cb139087e74eb0cba273b97c35d768ad0 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -66,6 +66,13 @@ GitEditor::GitEditor(const VcsBase::VcsBaseEditorParameters *type, { QTC_ASSERT(m_changeNumberPattern8.isValid(), return); QTC_ASSERT(m_changeNumberPattern40.isValid(), return); + /* Diff format: + diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp + index 40997ff..4e49337 100644 + --- a/src/plugins/git/giteditor.cpp + +++ b/src/plugins/git/giteditor.cpp + */ + setDiffFilePattern(QRegExp(QLatin1String("^(?:diff --git a/|index |[+-]{3} (?:/dev/null|[ab]/(.+$)))"))); setAnnotateRevisionTextFormat(tr("Blame %1")); setAnnotatePreviousRevisionTextFormat(tr("Blame Parent Revision %1")); } @@ -107,46 +114,12 @@ QString GitEditor::changeUnderCursor(const QTextCursor &c) const return QString(); } -QRegExp GitEditor::diffFilePattern() const -{ - return QRegExp(QLatin1String("^(diff --git a/|index |[+-][+-][+-] [ab/]).*$")); -} - VcsBase::BaseAnnotationHighlighter *GitEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new GitAnnotationHighlighter(changes, bg); } -QString GitEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // Check for "+++ b/src/plugins/git/giteditor.cpp" (blame and diff) - // as well as "--- a/src/plugins/git/giteditor.cpp". - // Go back chunks. - bool checkForOld = false; - - const QString oldFileIndicator = QLatin1String("--- a/"); - const QString newFileIndicator = QLatin1String("+++ "); - for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { - QString diffFileName = block.text(); - if (diffFileName.startsWith(oldFileIndicator) && checkForOld) { - diffFileName.remove(0, oldFileIndicator.size()); - checkForOld = false; - return diffFileName; - } else if (diffFileName.startsWith(newFileIndicator)) { - diffFileName.remove(0, newFileIndicator.size()); - if (diffFileName == QLatin1String("/dev/null")) { - checkForOld = true; - continue; - } - diffFileName.remove(0, 2); // remove "b/" - return findDiffFile(diffFileName); - } - checkForOld = false; - } - return QString(); -} - /* Remove the date specification from annotation, which is tabular: \code 8ca887aa (author YYYY-MM-DD HH:MM:SS <offset> <line>)<content> diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h index 5fc066c4cc72a5e002099767eb88512e8a086e4b..6b55f0b3ef0e036e8546ca878b84ee8696c55a86 100644 --- a/src/plugins/git/giteditor.h +++ b/src/plugins/git/giteditor.h @@ -57,9 +57,7 @@ public slots: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const; QString decorateVersion(const QString &revision) const; QStringList annotationPreviousVersions(const QString &revision) const; bool isValidRevision(const QString &revision) const; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 8951ffe088583761eacb724ab06901ab45d8cd5f..ea91635342418124f835ec1a11cfe6f69d6530aa 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -1253,8 +1253,14 @@ GitClient *GitPlugin::gitClient() const } #ifdef WITH_TESTS +#include "giteditor.h" + #include <QTest> +#include <QTextBlock> +#include <QTextDocument> + Q_DECLARE_METATYPE(FileStates) + void GitPlugin::testStatusParsing_data() { QTest::addColumn<FileStates>("first"); @@ -1301,6 +1307,42 @@ void GitPlugin::testStatusParsing() else QCOMPARE(data.files.at(1).first, second); } + +void GitPlugin::testDiffFileResolving_data() +{ + QTest::addColumn<QByteArray>("header"); + QTest::addColumn<QByteArray>("fileName"); + + QTest::newRow("New") << QByteArray( + "diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp\n" + "new file mode 100644\n" + "index 0000000..40997ff\n" + "--- /dev/null\n" + "+++ b/src/plugins/git/giteditor.cpp\n" + "@@ -0,0 +1,281 @@\n\n") + << QByteArray("src/plugins/git/giteditor.cpp"); + QTest::newRow("Deleted") << QByteArray( + "diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp\n" + "deleted file mode 100644\n" + "index 40997ff..0000000\n" + "--- a/src/plugins/git/giteditor.cpp\n" + "+++ /dev/null\n" + "@@ -1,281 +0,0 @@\n\n") + << QByteArray("src/plugins/git/giteditor.cpp"); + QTest::newRow("Normal") << QByteArray( + "diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp\n" + "index 69e0b52..8fc974d 100644\n" + "--- a/src/plugins/git/giteditor.cpp\n" + "+++ b/src/plugins/git/giteditor.cpp\n" + "@@ -49,6 +49,8 @@\n\n") + << QByteArray("src/plugins/git/giteditor.cpp"); +} + +void GitPlugin::testDiffFileResolving() +{ + GitEditor editor(editorParameters + 3, 0); + VcsBase::VcsBaseEditorWidget::testDiffFileResolving(&editor); +} #endif Q_EXPORT_PLUGIN(GitPlugin) diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index a02d428df1c34d113aeb61448e3d433bb6327461..8e9dd0a636d01e5e44e9eb89fcd835af083e67a2 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -144,6 +144,8 @@ private slots: #ifdef WITH_TESTS void testStatusParsing_data(); void testStatusParsing(); + void testDiffFileResolving_data(); + void testDiffFileResolving(); #endif protected: void updateActions(VcsBase::VcsBasePlugin::ActionState); diff --git a/src/plugins/mercurial/constants.h b/src/plugins/mercurial/constants.h index c9798c63d48f3e9fa385a8bda977ad623a181e1d..b5b1daa6b2a24eb97da97de468e2e883748e2fcb 100644 --- a/src/plugins/mercurial/constants.h +++ b/src/plugins/mercurial/constants.h @@ -42,7 +42,7 @@ const char CHANGESETID12[] = " ([a-f0-9]{12,12}) "; //match 12 hex chars and cap const char CHANGESETID40[] = " ([a-f0-9]{40,40}) "; const char CHANGEIDEXACT12[] = "[a-f0-9]{12,12}"; //match 12 hex chars a const char CHANGEIDEXACT40[] = "[a-f0-9]{40,40}"; -const char DIFFIDENTIFIER[] = "^[-+]{3,3} [ab]{1,1}.*"; // match e.g. +++ b/filename +const char DIFFIDENTIFIER[] = "^[-+]{3} [ab]/(.+)$"; // match e.g. +++ b/filename // Base editor parameters const char COMMANDLOG_ID[] = "Mercurial Command Log Editor"; diff --git a/src/plugins/mercurial/mercurialeditor.cpp b/src/plugins/mercurial/mercurialeditor.cpp index 4e775e6a935d184b00504085c4c0a53c75e6ae1d..4eafe92b72b52532fd53162848cc6d2409a13e97 100644 --- a/src/plugins/mercurial/mercurialeditor.cpp +++ b/src/plugins/mercurial/mercurialeditor.cpp @@ -51,9 +51,9 @@ MercurialEditor::MercurialEditor(const VcsBase::VcsBaseEditorParameters *type, Q exactIdentifier12(QLatin1String(Constants::CHANGEIDEXACT12)), exactIdentifier40(QLatin1String(Constants::CHANGEIDEXACT40)), changesetIdentifier12(QLatin1String(Constants::CHANGESETID12)), - changesetIdentifier40(QLatin1String(Constants::CHANGESETID40)), - diffIdentifier(QLatin1String(Constants::DIFFIDENTIFIER)) + changesetIdentifier40(QLatin1String(Constants::CHANGESETID40)) { + setDiffFilePattern(QRegExp(QLatin1String(Constants::DIFFIDENTIFIER))); setAnnotateRevisionTextFormat(tr("Annotate %1")); setAnnotatePreviousRevisionTextFormat(tr("Annotate parent revision %1")); } @@ -88,33 +88,12 @@ QString MercurialEditor::changeUnderCursor(const QTextCursor &cursorIn) const return QString(); } -QRegExp MercurialEditor::diffFilePattern() const -{ - return diffIdentifier; -} - VcsBase::BaseAnnotationHighlighter *MercurialEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new MercurialAnnotationHighlighter(changes, bg); } -QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // 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); - } - - } - return QString(); -} - QString MercurialEditor::decorateVersion(const QString &revision) const { const QFileInfo fi(source()); diff --git a/src/plugins/mercurial/mercurialeditor.h b/src/plugins/mercurial/mercurialeditor.h index da0d48789b4e6f6c7069e89a58941f9847dd28f7..28a1b38bb51f7bbf2b67308c2eee85608a0e7b6c 100644 --- a/src/plugins/mercurial/mercurialeditor.h +++ b/src/plugins/mercurial/mercurialeditor.h @@ -46,9 +46,7 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &cursor) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const; QString decorateVersion(const QString &revision) const; QStringList annotationPreviousVersions(const QString &revision) const; @@ -56,7 +54,6 @@ private: mutable QRegExp exactIdentifier40; mutable QRegExp changesetIdentifier12; const QRegExp changesetIdentifier40; - const QRegExp diffIdentifier; }; } // namespace Internal diff --git a/src/plugins/perforce/perforceeditor.cpp b/src/plugins/perforce/perforceeditor.cpp index aa925a86ec4c35b79b563e2368bcd4472c0a3cbd..c97da58e61f2c4e1b9e8df525c095d8d351b3f72 100644 --- a/src/plugins/perforce/perforceeditor.cpp +++ b/src/plugins/perforce/perforceeditor.cpp @@ -63,6 +63,10 @@ PerforceEditor::PerforceEditor(const VcsBase::VcsBaseEditorParameters *type, m_plugin(PerforcePlugin::perforcePluginInstance()) { QTC_CHECK(m_changeNumberPattern.isValid()); + // Diff format: + // 1) "==== //depot/.../mainwindow.cpp#2 - /depot/.../mainwindow.cpp ====" (created by p4 diff) + // 2) "==== //depot/.../mainwindow.cpp#15 (text) ====" (created by p4 describe) + setDiffFilePattern(QRegExp(QLatin1String("^==== (.+)#\\d"))); setAnnotateRevisionTextFormat(tr("Annotate change list \"%1\"")); if (Perforce::Constants::debug) qDebug() << "PerforceEditor::PerforceEditor" << type->type << type->id; @@ -103,57 +107,19 @@ QString PerforceEditor::changeUnderCursor(const QTextCursor &c) const return m_changeNumberPattern.exactMatch(change) ? change : QString(); } -QRegExp PerforceEditor::diffFilePattern() const -{ - return QRegExp(QLatin1String("^====.*")); -} - VcsBase::BaseAnnotationHighlighter *PerforceEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new PerforceAnnotationHighlighter(changes, bg); } -QString PerforceEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const +QString PerforceEditor::findDiffFile(const QString &f) const { QString errorMessage; - const QString diffIndicator = QLatin1String("==== "); - const QString diffEndIndicator = QLatin1String(" ===="); - // Go back chunks. Note that for 'describe', an extra, empty line - // occurs. - for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { - QString diffFileName = block.text(); - if (diffFileName.startsWith(diffIndicator) && diffFileName.endsWith(diffEndIndicator)) { - // Split: - // 1) "==== //depot/.../mainwindow.cpp#2 - /depot/.../mainwindow.cpp ====" - // (as created by p4 diff) or - // 2) "==== //depot/.../mainwindow.cpp#15 (text) ====" - // (as created by p4 describe). - diffFileName.remove(0, diffIndicator.size()); - diffFileName.truncate(diffFileName.size() - diffEndIndicator.size()); - const int separatorPos = diffFileName.indexOf(QLatin1String(" - ")); - if (separatorPos == -1) { - // ==== depot path (text) ==== (p4 describe) - const int blankPos = diffFileName.indexOf(QLatin1Char(' ')); - if (blankPos == -1) - return QString(); - diffFileName.truncate(blankPos); - } else { - // ==== depot path - local path ==== (p4 diff) - diffFileName.truncate(separatorPos); - } - // Split off revision "#4" - const int revisionPos = diffFileName.lastIndexOf(QLatin1Char('#')); - if (revisionPos != -1 && revisionPos < diffFileName.length() - 1) - diffFileName.truncate(revisionPos); - // Ask plugin to map back - const QString fileName = m_plugin->fileNameFromPerforceName(diffFileName.trimmed(), false, &errorMessage); - if (fileName.isEmpty()) - qWarning("%s", qPrintable(errorMessage)); - return fileName; - } - } - return QString(); + const QString fileName = m_plugin->fileNameFromPerforceName(f.trimmed(), false, &errorMessage); + if (fileName.isEmpty()) + qWarning("%s", qPrintable(errorMessage)); + return fileName; } QStringList PerforceEditor::annotationPreviousVersions(const QString &v) const diff --git a/src/plugins/perforce/perforceeditor.h b/src/plugins/perforce/perforceeditor.h index 3a8791eb5221ea50c22603d061ab9f1722d381aa..1edf5eba3e3f65ad5772e2d68ca071e16abf8904 100644 --- a/src/plugins/perforce/perforceeditor.h +++ b/src/plugins/perforce/perforceeditor.h @@ -50,9 +50,8 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const; + QString findDiffFile(const QString &f) const; QStringList annotationPreviousVersions(const QString &v) const; mutable QRegExp m_changeNumberPattern; diff --git a/src/plugins/subversion/subversioneditor.cpp b/src/plugins/subversion/subversioneditor.cpp index 7a7b44424bfa226af786445eeb24e0126cd22094..cb8141a3467a4bdd711b09ace7354e5795255605 100644 --- a/src/plugins/subversion/subversioneditor.cpp +++ b/src/plugins/subversion/subversioneditor.cpp @@ -52,6 +52,16 @@ SubversionEditor::SubversionEditor(const VcsBase::VcsBaseEditorParameters *type, { QTC_ASSERT(m_changeNumberPattern.isValid(), return); QTC_ASSERT(m_revisionNumberPattern.isValid(), return); + /* Diff pattern: + \code + Index: main.cpp + =================================================================== + --- main.cpp<tab>(revision 2) + +++ main.cpp<tab>(working copy) + @@ -6,6 +6,5 @@ + \endcode + */ + setDiffFilePattern(QRegExp(QLatin1String("^[-+]{3} ([^\\t]+)|^Index: .*|^=+$"))); setAnnotateRevisionTextFormat(tr("Annotate revision \"%1\"")); } @@ -98,46 +108,12 @@ QString SubversionEditor::changeUnderCursor(const QTextCursor &c) const return QString(); } -/* code: - Index: main.cpp -=================================================================== ---- main.cpp (revision 2) -+++ main.cpp (working copy) -@@ -6,6 +6,5 @@ -\endcode -*/ -QRegExp SubversionEditor::diffFilePattern() const -{ - return QRegExp(QLatin1String("^[-+][-+][-+] .*|^Index: .*|^==*$")); -} - VcsBase::BaseAnnotationHighlighter *SubversionEditor::createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const { return new SubversionAnnotationHighlighter(changes, bg); } -QString SubversionEditor::fileNameFromDiffSpecification(const QTextBlock &inBlock) const -{ - // "+++ /depot/.../mainwindow.cpp<tab>(revision 3)" - // Go back chunks - const QString diffIndicator = QLatin1String("+++ "); - for (QTextBlock block = inBlock; block.isValid() ; block = block.previous()) { - QString diffFileName = block.text(); - if (diffFileName.startsWith(diffIndicator)) { - diffFileName.remove(0, diffIndicator.size()); - const int tabIndex = diffFileName.lastIndexOf(QLatin1Char('\t')); - if (tabIndex != -1) - diffFileName.truncate(tabIndex); - const QString rc = findDiffFile(diffFileName); - if (Subversion::Constants::debug) - qDebug() << Q_FUNC_INFO << diffFileName << rc << source(); - return rc; - } - } - return QString(); -} - QStringList SubversionEditor::annotationPreviousVersions(const QString &v) const { bool ok; diff --git a/src/plugins/subversion/subversioneditor.h b/src/plugins/subversion/subversioneditor.h index f2ec7843677e720c292ce2a0c0d5f04751d0c22a..9d64b061fd51bac1a689d1643d7494e4cff6f1b6 100644 --- a/src/plugins/subversion/subversioneditor.h +++ b/src/plugins/subversion/subversioneditor.h @@ -48,9 +48,7 @@ public: private: QSet<QString> annotationChanges() const; QString changeUnderCursor(const QTextCursor &) const; - QRegExp diffFilePattern() const; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const; - QString fileNameFromDiffSpecification(const QTextBlock &diffFileName) const; QStringList annotationPreviousVersions(const QString &) const; mutable QRegExp m_changeNumberPattern; diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 5bb6533c58ad00668d308513687c042f6e9c304a..9b663950ad438f4c68756f822463b532c9587536 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -77,6 +77,10 @@ #include <QInputDialog> #include <limits.h> +#ifdef WITH_TESTS +#include <QTest> +#endif + namespace Subversion { namespace Internal { @@ -1389,6 +1393,42 @@ SubversionControl *SubversionPlugin::subVersionControl() const return static_cast<SubversionControl *>(versionControl()); } +#ifdef WITH_TESTS +void SubversionPlugin::testDiffFileResolving_data() +{ + QTest::addColumn<QByteArray>("header"); + QTest::addColumn<QByteArray>("fileName"); + + QTest::newRow("New") << QByteArray( + "Index: src/plugins/subversion/subversioneditor.cpp\n" + "===================================================================\n" + "--- src/plugins/subversion/subversioneditor.cpp\t(revision 0)\n" + "+++ src/plugins/subversion/subversioneditor.cpp\t(revision 0)\n" + "@@ -0,0 +125 @@\n\n") + << QByteArray("src/plugins/subversion/subversioneditor.cpp"); + QTest::newRow("Deleted") << QByteArray( + "Index: src/plugins/subversion/subversioneditor.cpp\n" + "===================================================================\n" + "--- src/plugins/subversion/subversioneditor.cpp\t(revision 42)\n" + "+++ src/plugins/subversion/subversioneditor.cpp\t(working copy)\n" + "@@ -1,125 +0,0 @@\n\n") + << QByteArray("src/plugins/subversion/subversioneditor.cpp"); + QTest::newRow("Normal") << QByteArray( + "Index: src/plugins/subversion/subversioneditor.cpp\n" + "===================================================================\n" + "--- src/plugins/subversion/subversioneditor.cpp\t(revision 42)\n" + "+++ src/plugins/subversion/subversioneditor.cpp\t(working copy)\n" + "@@ -120,7 +120,7 @@\n\n") + << QByteArray("src/plugins/subversion/subversioneditor.cpp"); +} + +void SubversionPlugin::testDiffFileResolving() +{ + SubversionEditor editor(editorParameters + 3, 0); + VcsBase::VcsBaseEditorWidget::testDiffFileResolving(&editor); +} +#endif + } // Internal } // Subversion diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h index b3760d1e4c8a2e03bce1a22c47793d23afdb9a8d..c82851de013fece1186177684e5aa2544b832a4b 100644 --- a/src/plugins/subversion/subversionplugin.h +++ b/src/plugins/subversion/subversionplugin.h @@ -136,6 +136,10 @@ private slots: void diffRepository(); void statusRepository(); void updateRepository(); +#ifdef WITH_TESTS + void testDiffFileResolving_data(); + void testDiffFileResolving(); +#endif protected: void updateActions(VcsBase::VcsBasePlugin::ActionState); diff --git a/src/plugins/vcsbase/diffhighlighter.cpp b/src/plugins/vcsbase/diffhighlighter.cpp index 278b32a1388b6052add1cda51e83c10d1b734c73..463449e0dcdd9497b9a85981e1b15aad5e042803 100644 --- a/src/plugins/vcsbase/diffhighlighter.cpp +++ b/src/plugins/vcsbase/diffhighlighter.cpp @@ -116,7 +116,7 @@ DiffFormats DiffHighlighterPrivate::analyzeLine(const QString &text) const { // Do not match on git "--- a/" as a deleted line, check // file first - if (m_filePattern.exactMatch(text)) + if (m_filePattern.indexIn(text) == 0) return DiffFileFormat; if (text.startsWith(m_diffInIndicator)) return DiffInFormat; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 1a25ad7a438799110774600e0db5260a372a963d..2999b7c939dbca6325be8493fe7bdc6739ee1399 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -668,17 +668,23 @@ VcsBaseEditorWidget::VcsBaseEditorWidget(const VcsBaseEditorParameters *type, QW setMimeType(QLatin1String(d->m_parameters->mimeType)); } +void VcsBaseEditorWidget::setDiffFilePattern(const QRegExp &pattern) +{ + QTC_ASSERT(pattern.isValid() && pattern.captureCount() >= 1, return); + d->m_diffFilePattern = pattern; +} + void VcsBaseEditorWidget::init() { switch (d->m_parameters->type) { case RegularCommandOutput: case LogOutput: + break; case AnnotateOutput: // Annotation highlighting depends on contents, which is set later on connect(this, SIGNAL(textChanged()), this, SLOT(slotActivateAnnotation())); break; case DiffOutput: { - d->m_diffFilePattern = diffFilePattern(); DiffHighlighter *dh = new DiffHighlighter(d->m_diffFilePattern); setCodeFoldingSupported(true); baseTextDocument()->setSyntaxHighlighter(dh); @@ -1429,6 +1435,20 @@ bool VcsBaseEditorWidget::applyDiffChunk(const DiffChunk &dc, bool revert) const return VcsBasePlugin::runPatch(dc.asPatch(), QString(), 0, revert); } +QString VcsBaseEditorWidget::fileNameFromDiffSpecification(const QTextBlock &inBlock) const +{ + // Go back chunks + for (QTextBlock block = inBlock; block.isValid(); block = block.previous()) { + const QString line = block.text(); + if (d->m_diffFilePattern.indexIn(line) != -1) { + QString cap = d->m_diffFilePattern.cap(1); + if (!cap.isEmpty()) + return findDiffFile(cap); + } + } + return QString(); +} + QString VcsBaseEditorWidget::decorateVersion(const QString &revision) const { return revision; @@ -1502,4 +1522,18 @@ Core::IEditor* VcsBaseEditorWidget::locateEditorByTag(const QString &tag) } // namespace VcsBase +#if WITH_TESTS +#include <QTest> + +void VcsBase::VcsBaseEditorWidget::testDiffFileResolving(VcsBaseEditorWidget *editor) +{ + QFETCH(QByteArray, header); + QFETCH(QByteArray, fileName); + QTextDocument doc(QString::fromLatin1(header)); + editor->init(); + QTextBlock block = doc.lastBlock(); + QVERIFY(editor->fileNameFromDiffSpecification(block).endsWith(QString::fromLatin1(fileName))); +} +#endif + #include "vcsbaseeditor.moc" diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index 88b61834ff74cbea9932316ffffa9d155ee3fb3f..9cd0cbb1c2500c36ae797134a765321745a4bf84 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -38,6 +38,7 @@ QT_BEGIN_NAMESPACE class QAction; +class QRegExp; class QTextCodec; class QTextCursor; QT_END_NAMESPACE @@ -99,6 +100,9 @@ protected: // virtual functions). explicit VcsBaseEditorWidget(const VcsBaseEditorParameters *type, QWidget *parent); + // Pattern for diff header. File name must be in the first capture group + void setDiffFilePattern(const QRegExp &pattern); + public: void init(); @@ -180,6 +184,10 @@ public: bool setConfigurationWidget(QWidget *w); QWidget *configurationWidget() const; + // Returns a local file name from the diff file specification + // (text cursor at position above change hunk) + QString fileNameFromDiffSpecification(const QTextBlock &inBlock) const; + /* Tagging editors: Sometimes, an editor should be re-used, for example, when showing * a diff of the same file with different diff-options. In order to be able to find * the editor, they get a 'tag' containing type and parameters (dynamic property string). */ @@ -187,7 +195,6 @@ public: static Core::IEditor* locateEditorByTag(const QString &tag); static QString editorTag(EditorContentType t, const QString &workingDirectory, const QStringList &files, const QString &revision = QString()); - signals: // These signals also exist in the opaque editable (IEditor) that is // handled by the editor manager for convenience. They are emitted @@ -227,25 +234,20 @@ protected: /* A helper that can be used to locate a file in a diff in case it * is relative. Tries to derive the directory from base directory, * source and version control. */ - QString findDiffFile(const QString &f) const; + virtual QString findDiffFile(const QString &f) const; virtual bool canApplyDiffChunk(const DiffChunk &dc) const; // Revert a patch chunk. Default implementation uses patch.exe virtual bool applyDiffChunk(const DiffChunk &dc, bool revert = false) const; -private: // Implement to return a set of change identifiers in // annotation mode virtual QSet<QString> annotationChanges() const = 0; // Implement to identify a change number at the cursor position virtual QString changeUnderCursor(const QTextCursor &) const = 0; // Factory functions for highlighters - virtual QRegExp diffFilePattern() const = 0; virtual BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes, const QColor &bg) const = 0; - // Implement to return a local file name from the diff file specification - // (text cursor at position above change hunk) - virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const = 0; // Implement to return decorated annotation change for "Annotate version" virtual QString decorateVersion(const QString &revision) const; // Implement to return the previous version[s] of an annotation change @@ -253,6 +255,8 @@ private: virtual QStringList annotationPreviousVersions(const QString &revision) const; // Implement to validate revisions virtual bool isValidRevision(const QString &revision) const; + +private: // cut out chunk and determine file name. DiffChunk diffChunk(QTextCursor cursor) const; @@ -260,6 +264,11 @@ private: friend class Internal::ChangeTextCursorHandler; Internal::VcsBaseEditorWidgetPrivate *const d; + +#if WITH_TESTS +public: + static void testDiffFileResolving(VcsBaseEditorWidget *editor); +#endif }; } // namespace VcsBase