forked from qt-creator/qt-creator
Replace QRegExp with QRegularExpression
Use QStringRef where possible. Speedup readGitPatch() approximately 2 times. Change-Id: I7bd09d7ac768331b0600456e48c44cfc72b7001d Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -1298,6 +1298,53 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data()
|
||||
QTest::newRow("Dirty submodule") << patch
|
||||
<< fileDataList7;
|
||||
|
||||
//////////////
|
||||
patch = _("diff --git a/demos/arthurplugin/arthurplugin.pro b/demos/arthurplugin/arthurplugin.pro\n"
|
||||
"new file mode 100644\n"
|
||||
"index 0000000..c5132b4\n"
|
||||
"--- /dev/null\n"
|
||||
"+++ b/demos/arthurplugin/arthurplugin.pro\n"
|
||||
"@@ -0,0 +1 @@\n"
|
||||
"+XXX\n"
|
||||
"diff --git a/demos/arthurplugin/bg1.jpg b/demos/arthurplugin/bg1.jpg\n"
|
||||
"new file mode 100644\n"
|
||||
"index 0000000..dfc7cee\n"
|
||||
"Binary files /dev/null and b/demos/arthurplugin/bg1.jpg differ\n"
|
||||
"diff --git a/demos/arthurplugin/flower.jpg b/demos/arthurplugin/flower.jpg\n"
|
||||
"new file mode 100644\n"
|
||||
"index 0000000..f8e022c\n"
|
||||
"Binary files /dev/null and b/demos/arthurplugin/flower.jpg differ\n"
|
||||
);
|
||||
|
||||
fileData1 = FileData();
|
||||
fileData1.leftFileInfo = DiffFileInfo(_("demos/arthurplugin/arthurplugin.pro"), _("0000000"));
|
||||
fileData1.rightFileInfo = DiffFileInfo(_("demos/arthurplugin/arthurplugin.pro"), _("c5132b4"));
|
||||
fileData1.fileOperation = FileData::NewFile;
|
||||
chunkData1 = ChunkData();
|
||||
chunkData1.leftStartingLineNumber = -1;
|
||||
chunkData1.rightStartingLineNumber = 0;
|
||||
rows1.clear();
|
||||
rows1 << RowData(TextLineData::Separator, _("XXX"));
|
||||
rows1 << RowData(TextLineData::Separator, TextLineData(TextLineData::TextLine));
|
||||
chunkData1.rows = rows1;
|
||||
fileData1.chunks << chunkData1;
|
||||
fileData2 = FileData();
|
||||
fileData2.leftFileInfo = DiffFileInfo(_("demos/arthurplugin/bg1.jpg"), _("0000000"));
|
||||
fileData2.rightFileInfo = DiffFileInfo(_("demos/arthurplugin/bg1.jpg"), _("dfc7cee"));
|
||||
fileData2.fileOperation = FileData::NewFile;
|
||||
fileData2.binaryFiles = true;
|
||||
fileData3 = FileData();
|
||||
fileData3.leftFileInfo = DiffFileInfo(_("demos/arthurplugin/flower.jpg"), _("0000000"));
|
||||
fileData3.rightFileInfo = DiffFileInfo(_("demos/arthurplugin/flower.jpg"), _("f8e022c"));
|
||||
fileData3.fileOperation = FileData::NewFile;
|
||||
fileData3.binaryFiles = true;
|
||||
|
||||
QList<FileData> fileDataList8;
|
||||
fileDataList8 << fileData1 << fileData2 << fileData3;
|
||||
|
||||
QTest::newRow("Binary files") << patch
|
||||
<< fileDataList8;
|
||||
|
||||
//////////////
|
||||
|
||||
// Subversion New
|
||||
@@ -1313,10 +1360,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data()
|
||||
chunkData1.leftStartingLineNumber = -1;
|
||||
chunkData1.rightStartingLineNumber = 124;
|
||||
fileData1.chunks << chunkData1;
|
||||
QList<FileData> fileDataList8;
|
||||
fileDataList8 << fileData1;
|
||||
QList<FileData> fileDataList9;
|
||||
fileDataList9 << fileData1;
|
||||
QTest::newRow("Subversion New") << patch
|
||||
<< fileDataList8;
|
||||
<< fileDataList9;
|
||||
|
||||
//////////////
|
||||
|
||||
@@ -1333,10 +1380,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data()
|
||||
chunkData1.leftStartingLineNumber = 0;
|
||||
chunkData1.rightStartingLineNumber = -1;
|
||||
fileData1.chunks << chunkData1;
|
||||
QList<FileData> fileDataList9;
|
||||
fileDataList9 << fileData1;
|
||||
QList<FileData> fileDataList10;
|
||||
fileDataList10 << fileData1;
|
||||
QTest::newRow("Subversion Deleted") << patch
|
||||
<< fileDataList9;
|
||||
<< fileDataList10;
|
||||
|
||||
//////////////
|
||||
|
||||
@@ -1353,10 +1400,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch_data()
|
||||
chunkData1.leftStartingLineNumber = 119;
|
||||
chunkData1.rightStartingLineNumber = 119;
|
||||
fileData1.chunks << chunkData1;
|
||||
QList<FileData> fileDataList10;
|
||||
fileDataList10 << fileData1;
|
||||
QList<FileData> fileDataList11;
|
||||
fileDataList11 << fileData1;
|
||||
QTest::newRow("Subversion Normal") << patch
|
||||
<< fileDataList10;
|
||||
<< fileDataList11;
|
||||
}
|
||||
|
||||
void DiffEditor::Internal::DiffEditorPlugin::testReadPatch()
|
||||
@@ -1365,10 +1412,10 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch()
|
||||
QFETCH(QList<FileData>, fileDataList);
|
||||
|
||||
bool ok;
|
||||
QList<FileData> result = DiffUtils::readPatch(sourcePatch, &ok);
|
||||
const QList<FileData> &result = DiffUtils::readPatch(sourcePatch, &ok);
|
||||
|
||||
QVERIFY(ok);
|
||||
QCOMPARE(fileDataList.count(), result.count());
|
||||
QCOMPARE(result.count(), fileDataList.count());
|
||||
for (int i = 0; i < fileDataList.count(); i++) {
|
||||
const FileData &origFileData = fileDataList.at(i);
|
||||
const FileData &resultFileData = result.at(i);
|
||||
|
@@ -34,7 +34,7 @@ publication by Neil Fraser: http://neil.fraser.name/writing/diff/
|
||||
#include "differ.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
@@ -204,9 +204,9 @@ static QList<Diff> cleanupOverlaps(const QList<Diff> &diffList)
|
||||
|
||||
static int cleanupSemanticsScore(const QString &text1, const QString &text2)
|
||||
{
|
||||
const QRegExp blankLineEnd = QRegExp(QLatin1String("\\n\\r?\\n$"));
|
||||
const QRegExp blankLineStart = QRegExp(QLatin1String("^\\r?\\n\\r?\\n"));
|
||||
const QRegExp sentenceEnd = QRegExp(QLatin1String("\\. $"));
|
||||
const QRegularExpression blankLineEnd("\\n\\r?\\n$");
|
||||
const QRegularExpression blankLineStart("^\\r?\\n\\r?\\n");
|
||||
const QRegularExpression sentenceEnd("\\. $");
|
||||
|
||||
if (!text1.count() || !text2.count()) // Edges
|
||||
return 6;
|
||||
@@ -219,14 +219,14 @@ static int cleanupSemanticsScore(const QString &text1, const QString &text2)
|
||||
const bool whitespace2 = nonAlphaNumeric2 && char2.isSpace();
|
||||
const bool lineBreak1 = whitespace1 && char1.category() == QChar::Other_Control;
|
||||
const bool lineBreak2 = whitespace2 && char2.category() == QChar::Other_Control;
|
||||
const bool blankLine1 = lineBreak1 && blankLineEnd.indexIn(text1) != -1;
|
||||
const bool blankLine2 = lineBreak2 && blankLineStart.indexIn(text2) != -1;
|
||||
const bool blankLine1 = lineBreak1 && blankLineEnd.match(text1).hasMatch();
|
||||
const bool blankLine2 = lineBreak2 && blankLineStart.match(text2).hasMatch();
|
||||
|
||||
if (blankLine1 || blankLine2) // Blank lines
|
||||
return 5;
|
||||
if (lineBreak1 || lineBreak2) // Line breaks
|
||||
return 4;
|
||||
if (sentenceEnd.indexIn(text1) != -1) // End of sentence
|
||||
if (sentenceEnd.match(text1).hasMatch()) // End of sentence
|
||||
return 3;
|
||||
if (whitespace1 || whitespace2) // Whitespaces
|
||||
return 2;
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "diffutils.h"
|
||||
#include "differ.h"
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include "texteditor/fontsettings.h"
|
||||
@@ -519,14 +519,11 @@ QString DiffUtils::makePatch(const QList<FileData> &fileDataList, unsigned forma
|
||||
return diffText;
|
||||
}
|
||||
|
||||
static QList<RowData> readLines(const QString &patch,
|
||||
static QList<RowData> readLines(QStringRef patch,
|
||||
bool lastChunk,
|
||||
bool *lastChunkAtTheEndOfFile,
|
||||
bool *ok)
|
||||
{
|
||||
// const QRegExp lineRegExp(QLatin1String("(?:\\n)" // beginning of the line
|
||||
// "([ -\\+\\\\])([^\\n]*)" // -, +, \\ or space, followed by any no-newline character
|
||||
// "(?:\\n|$)")); // end of line or file
|
||||
QList<Diff> diffList;
|
||||
|
||||
const QChar newLine = QLatin1Char('\n');
|
||||
@@ -539,16 +536,16 @@ static QList<RowData> readLines(const QString &patch,
|
||||
int noNewLineInDelete = -1;
|
||||
int noNewLineInInsert = -1;
|
||||
|
||||
const QStringList lines = patch.split(newLine);
|
||||
const QVector<QStringRef> lines = patch.split(newLine);
|
||||
int i;
|
||||
for (i = 0; i < lines.count(); i++) {
|
||||
const QString line = lines.at(i);
|
||||
QStringRef line = lines.at(i);
|
||||
if (line.isEmpty()) { // need to have at least one character (1 column)
|
||||
if (lastChunk)
|
||||
i = lines.count(); // pretend as we've read all the lines (we just ignore the rest)
|
||||
break;
|
||||
}
|
||||
QChar firstCharacter = line.at(0);
|
||||
const QChar firstCharacter = line.at(0);
|
||||
if (firstCharacter == QLatin1Char('\\')) { // no new line marker
|
||||
if (!lastChunk) // can only appear in last chunk of the file
|
||||
break;
|
||||
@@ -695,11 +692,11 @@ static QList<RowData> readLines(const QString &patch,
|
||||
outputRightDiffList).rows;
|
||||
}
|
||||
|
||||
static QList<ChunkData> readChunks(const QString &patch,
|
||||
static QList<ChunkData> readChunks(QStringRef patch,
|
||||
bool *lastChunkAtTheEndOfFile,
|
||||
bool *ok)
|
||||
{
|
||||
const QRegExp chunkRegExp(QLatin1String(
|
||||
const QRegularExpression chunkRegExp(
|
||||
// beginning of the line
|
||||
"(?:\\n|^)"
|
||||
// @@ -leftPos[,leftCount] +rightPos[,rightCount] @@
|
||||
@@ -707,21 +704,22 @@ static QList<ChunkData> readChunks(const QString &patch,
|
||||
// optional hint (e.g. function name)
|
||||
"(\\ +[^\\n]*)?"
|
||||
// end of line (need to be followed by text line)
|
||||
"\\n"));
|
||||
"\\n");
|
||||
|
||||
bool readOk = false;
|
||||
|
||||
QList<ChunkData> chunkDataList;
|
||||
|
||||
int pos = chunkRegExp.indexIn(patch);
|
||||
if (pos == 0) {
|
||||
QRegularExpressionMatch match = chunkRegExp.match(patch);
|
||||
if (match.hasMatch() && match.capturedStart() == 0) {
|
||||
int endOfLastChunk = 0;
|
||||
do {
|
||||
const int leftStartingPos = chunkRegExp.cap(1).toInt();
|
||||
const int rightStartingPos = chunkRegExp.cap(2).toInt();
|
||||
const QString contextInfo = chunkRegExp.cap(3);
|
||||
const int pos = match.capturedStart();
|
||||
const int leftStartingPos = match.capturedRef(1).toInt();
|
||||
const int rightStartingPos = match.capturedRef(2).toInt();
|
||||
const QString contextInfo = match.captured(3);
|
||||
if (endOfLastChunk > 0) {
|
||||
const QString lines = patch.mid(endOfLastChunk,
|
||||
QStringRef lines = patch.mid(endOfLastChunk,
|
||||
pos - endOfLastChunk);
|
||||
chunkDataList.last().rows = readLines(lines,
|
||||
false,
|
||||
@@ -730,17 +728,17 @@ static QList<ChunkData> readChunks(const QString &patch,
|
||||
if (!readOk)
|
||||
break;
|
||||
}
|
||||
pos += chunkRegExp.matchedLength();
|
||||
endOfLastChunk = pos;
|
||||
endOfLastChunk = match.capturedEnd();
|
||||
ChunkData chunkData;
|
||||
chunkData.leftStartingLineNumber = leftStartingPos - 1;
|
||||
chunkData.rightStartingLineNumber = rightStartingPos - 1;
|
||||
chunkData.contextInfo = contextInfo;
|
||||
chunkDataList.append(chunkData);
|
||||
} while ((pos = chunkRegExp.indexIn(patch, pos, QRegExp::CaretAtOffset)) != -1);
|
||||
match = chunkRegExp.match(patch, endOfLastChunk);
|
||||
} while (match.hasMatch());
|
||||
|
||||
if (endOfLastChunk > 0) {
|
||||
const QString lines = patch.mid(endOfLastChunk);
|
||||
QStringRef lines = patch.mid(endOfLastChunk);
|
||||
chunkDataList.last().rows = readLines(lines,
|
||||
true,
|
||||
lastChunkAtTheEndOfFile,
|
||||
@@ -754,43 +752,50 @@ static QList<ChunkData> readChunks(const QString &patch,
|
||||
return chunkDataList;
|
||||
}
|
||||
|
||||
static FileData readDiffHeaderAndChunks(const QString &headerAndChunks,
|
||||
static FileData readDiffHeaderAndChunks(QStringRef headerAndChunks,
|
||||
bool *ok)
|
||||
{
|
||||
QString patch = headerAndChunks;
|
||||
QStringRef patch = headerAndChunks;
|
||||
FileData fileData;
|
||||
bool readOk = false;
|
||||
|
||||
const QRegExp leftFileRegExp(QLatin1String(
|
||||
const QRegularExpression leftFileRegExp(
|
||||
"(?:\\n|^)-{3} " // "--- "
|
||||
"([^\\t\\n]+)" // "fileName1"
|
||||
"(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...)
|
||||
const QRegExp rightFileRegExp(QLatin1String(
|
||||
"(?:\\t[^\\n]*)*\\n"); // optionally followed by: \t anything \t anything ...)
|
||||
const QRegularExpression rightFileRegExp(
|
||||
"^\\+{3} " // "+++ "
|
||||
"([^\\t\\n]+)" // "fileName2"
|
||||
"(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...)
|
||||
const QRegExp binaryRegExp(QLatin1String("^Binary files ([^\\t\\n]+) and ([^\\t\\n]+) differ$"));
|
||||
"(?:\\t[^\\n]*)*\\n"); // optionally followed by: \t anything \t anything ...)
|
||||
const QRegularExpression binaryRegExp(
|
||||
"^Binary files ([^\\t\\n]+) and ([^\\t\\n]+) differ$");
|
||||
|
||||
// followed either by leftFileRegExp or by binaryRegExp
|
||||
if (leftFileRegExp.indexIn(patch) == 0) {
|
||||
patch.remove(0, leftFileRegExp.matchedLength());
|
||||
fileData.leftFileInfo.fileName = leftFileRegExp.cap(1);
|
||||
// followed either by leftFileRegExp
|
||||
const QRegularExpressionMatch leftMatch = leftFileRegExp.match(patch);
|
||||
if (leftMatch.hasMatch() && leftMatch.capturedStart() == 0) {
|
||||
patch = patch.mid(leftMatch.capturedEnd());
|
||||
fileData.leftFileInfo.fileName = leftMatch.captured(1);
|
||||
|
||||
// followed by rightFileRegExp
|
||||
if (rightFileRegExp.indexIn(patch) == 0) {
|
||||
patch.remove(0, rightFileRegExp.matchedLength());
|
||||
fileData.rightFileInfo.fileName = rightFileRegExp.cap(1);
|
||||
const QRegularExpressionMatch rightMatch = rightFileRegExp.match(patch);
|
||||
if (rightMatch.hasMatch() && rightMatch.capturedStart() == 0) {
|
||||
patch = patch.mid(rightMatch.capturedEnd());
|
||||
fileData.rightFileInfo.fileName = rightMatch.captured(1);
|
||||
|
||||
fileData.chunks = readChunks(patch,
|
||||
&fileData.lastChunkAtTheEndOfFile,
|
||||
&readOk);
|
||||
}
|
||||
} else if (binaryRegExp.indexIn(patch) == 0) {
|
||||
fileData.leftFileInfo.fileName = binaryRegExp.cap(1);
|
||||
fileData.rightFileInfo.fileName = binaryRegExp.cap(2);
|
||||
} else {
|
||||
// or by binaryRegExp
|
||||
const QRegularExpressionMatch binaryMatch = binaryRegExp.match(patch);
|
||||
if (binaryMatch.hasMatch() && binaryMatch.capturedStart() == 0) {
|
||||
fileData.leftFileInfo.fileName = binaryMatch.captured(1);
|
||||
fileData.rightFileInfo.fileName = binaryMatch.captured(2);
|
||||
fileData.binaryFiles = true;
|
||||
readOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
*ok = readOk;
|
||||
@@ -802,10 +807,10 @@ static FileData readDiffHeaderAndChunks(const QString &headerAndChunks,
|
||||
|
||||
}
|
||||
|
||||
static QList<FileData> readDiffPatch(const QString &patch,
|
||||
static QList<FileData> readDiffPatch(QStringRef patch,
|
||||
bool *ok)
|
||||
{
|
||||
const QRegExp diffRegExp(QLatin1String("(?:\\n|^)" // new line of the beginning of a patch
|
||||
const QRegularExpression diffRegExp("(?:\\n|^)" // new line of the beginning of a patch
|
||||
"(" // either
|
||||
"-{3} " // ---
|
||||
"[^\\t\\n]+" // filename1
|
||||
@@ -819,19 +824,20 @@ static QList<FileData> readDiffPatch(const QString &patch,
|
||||
" and "
|
||||
"[^\\t\\n]+" // filename2
|
||||
" differ"
|
||||
")")); // end of or
|
||||
")"); // end of or
|
||||
|
||||
bool readOk = false;
|
||||
|
||||
QList<FileData> fileDataList;
|
||||
|
||||
int pos = diffRegExp.indexIn(patch);
|
||||
if (pos >= 0) { // git style patch
|
||||
QRegularExpressionMatch diffMatch = diffRegExp.match(patch);
|
||||
if (diffMatch.hasMatch()) {
|
||||
readOk = true;
|
||||
int lastPos = -1;
|
||||
do {
|
||||
int pos = diffMatch.capturedStart();
|
||||
if (lastPos >= 0) {
|
||||
const QString headerAndChunks = patch.mid(lastPos,
|
||||
QStringRef headerAndChunks = patch.mid(lastPos,
|
||||
pos - lastPos);
|
||||
|
||||
const FileData fileData = readDiffHeaderAndChunks(headerAndChunks,
|
||||
@@ -843,11 +849,12 @@ static QList<FileData> readDiffPatch(const QString &patch,
|
||||
fileDataList.append(fileData);
|
||||
}
|
||||
lastPos = pos;
|
||||
pos += diffRegExp.matchedLength();
|
||||
} while ((pos = diffRegExp.indexIn(patch, pos)) != -1);
|
||||
pos = diffMatch.capturedEnd();
|
||||
diffMatch = diffRegExp.match(patch, pos);
|
||||
} while (diffMatch.hasMatch());
|
||||
|
||||
if (lastPos >= 0 && readOk) {
|
||||
const QString headerAndChunks = patch.mid(lastPos,
|
||||
if (readOk) {
|
||||
QStringRef headerAndChunks = patch.mid(lastPos,
|
||||
patch.count() - lastPos - 1);
|
||||
|
||||
const FileData fileData = readDiffHeaderAndChunks(headerAndChunks,
|
||||
@@ -872,7 +879,7 @@ static bool fileNameEnd(const QChar &c)
|
||||
return c == QLatin1Char('\n') || c == QLatin1Char('\t');
|
||||
}
|
||||
|
||||
static FileData readGitHeaderAndChunks(const QString &headerAndChunks,
|
||||
static FileData readGitHeaderAndChunks(QStringRef headerAndChunks,
|
||||
const QString &fileName,
|
||||
bool *ok)
|
||||
{
|
||||
@@ -880,41 +887,52 @@ static FileData readGitHeaderAndChunks(const QString &headerAndChunks,
|
||||
fileData.leftFileInfo.fileName = fileName;
|
||||
fileData.rightFileInfo.fileName = fileName;
|
||||
|
||||
QString patch = headerAndChunks;
|
||||
QStringRef patch = headerAndChunks;
|
||||
bool readOk = false;
|
||||
|
||||
const QString devNull(QLatin1String("/dev/null"));
|
||||
|
||||
// will be followed by: index 0000000..shasha, file "a" replaced by "/dev/null", @@ -0,0 +m,n @@
|
||||
const QRegExp newFileMode(QLatin1String("^new file mode \\d+\\n")); // new file mode octal
|
||||
// new file mode octal
|
||||
const QRegularExpression newFileMode("^new file mode \\d+\\n");
|
||||
|
||||
// will be followed by: index shasha..0000000, file "b" replaced by "/dev/null", @@ -m,n +0,0 @@
|
||||
const QRegExp deletedFileMode(QLatin1String("^deleted file mode \\d+\\n")); // deleted file mode octal
|
||||
// deleted file mode octal
|
||||
const QRegularExpression deletedFileMode("^deleted file mode \\d+\\n");
|
||||
|
||||
const QRegExp modeChangeRegExp(QLatin1String("^old mode \\d+\\nnew mode \\d+\\n"));
|
||||
const QRegularExpression modeChangeRegExp("^old mode \\d+\\nnew mode \\d+\\n");
|
||||
|
||||
const QRegExp indexRegExp(QLatin1String("^index (\\w+)\\.{2}(\\w+)(?: \\d+)?(\\n|$)")); // index cap1..cap2(optionally: octal)
|
||||
// index cap1..cap2(optionally: octal)
|
||||
const QRegularExpression indexRegExp("^index (\\w+)\\.{2}(\\w+)(?: \\d+)?(\\n|$)");
|
||||
|
||||
QString leftFileName = QLatin1String("a/") + fileName;
|
||||
QString rightFileName = QLatin1String("b/") + fileName;
|
||||
|
||||
if (newFileMode.indexIn(patch) == 0) {
|
||||
const QRegularExpressionMatch newFileMatch = newFileMode.match(patch);
|
||||
if (newFileMatch.hasMatch() && newFileMatch.capturedStart() == 0) {
|
||||
fileData.fileOperation = FileData::NewFile;
|
||||
leftFileName = devNull;
|
||||
patch.remove(0, newFileMode.matchedLength());
|
||||
} else if (deletedFileMode.indexIn(patch) == 0) {
|
||||
patch = patch.mid(newFileMatch.capturedEnd());
|
||||
} else {
|
||||
const QRegularExpressionMatch deletedFileMatch = deletedFileMode.match(patch);
|
||||
if (deletedFileMatch.hasMatch() && deletedFileMatch.capturedStart() == 0) {
|
||||
fileData.fileOperation = FileData::DeleteFile;
|
||||
rightFileName = devNull;
|
||||
patch.remove(0, deletedFileMode.matchedLength());
|
||||
} else if (modeChangeRegExp.indexIn(patch) == 0) {
|
||||
patch.remove(0, modeChangeRegExp.matchedLength());
|
||||
patch = patch.mid(deletedFileMatch.capturedEnd());
|
||||
} else {
|
||||
const QRegularExpressionMatch modeChangeMatch = modeChangeRegExp.match(patch);
|
||||
if (modeChangeMatch.hasMatch() && modeChangeMatch.capturedStart() == 0) {
|
||||
patch = patch.mid(modeChangeMatch.capturedEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (indexRegExp.indexIn(patch) == 0) {
|
||||
fileData.leftFileInfo.typeInfo = indexRegExp.cap(1);
|
||||
fileData.rightFileInfo.typeInfo = indexRegExp.cap(2);
|
||||
const QRegularExpressionMatch indexMatch = indexRegExp.match(patch);
|
||||
if (indexMatch.hasMatch() && indexMatch.capturedStart() == 0) {
|
||||
fileData.leftFileInfo.typeInfo = indexMatch.captured(1);
|
||||
fileData.rightFileInfo.typeInfo = indexMatch.captured(2);
|
||||
|
||||
patch.remove(0, indexRegExp.matchedLength());
|
||||
patch = patch.mid(indexMatch.capturedEnd());
|
||||
}
|
||||
|
||||
const QString binaryLine = QString::fromLatin1("Binary files ") + leftFileName
|
||||
@@ -927,14 +945,14 @@ static FileData readGitHeaderAndChunks(const QString &headerAndChunks,
|
||||
|| fileData.fileOperation == FileData::DeleteFile)) {
|
||||
readOk = true;
|
||||
} else if (patch.startsWith(leftStart) && fileNameEnd(leftFollow)) {
|
||||
patch.remove(0, patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1);
|
||||
patch = patch.mid(patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1);
|
||||
|
||||
const QString rightStart = QString::fromLatin1("+++ ") + rightFileName;
|
||||
QChar rightFollow = patch.count() > rightStart.count() ? patch.at(rightStart.count()) : QLatin1Char('\n');
|
||||
|
||||
// followed by rightFileRegExp
|
||||
if (patch.startsWith(rightStart) && fileNameEnd(rightFollow)) {
|
||||
patch.remove(0, patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1);
|
||||
patch = patch.mid(patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1);
|
||||
|
||||
fileData.chunks = readChunks(patch,
|
||||
&fileData.lastChunkAtTheEndOfFile,
|
||||
@@ -954,7 +972,7 @@ static FileData readGitHeaderAndChunks(const QString &headerAndChunks,
|
||||
return fileData;
|
||||
}
|
||||
|
||||
static FileData readCopyRenameChunks(const QString ©RenameChunks,
|
||||
static FileData readCopyRenameChunks(QStringRef copyRenameChunks,
|
||||
FileData::FileOperation fileOperation,
|
||||
const QString &leftFileName,
|
||||
const QString &rightFileName,
|
||||
@@ -965,24 +983,26 @@ static FileData readCopyRenameChunks(const QString ©RenameChunks,
|
||||
fileData.leftFileInfo.fileName = leftFileName;
|
||||
fileData.rightFileInfo.fileName = rightFileName;
|
||||
|
||||
QString patch = copyRenameChunks;
|
||||
QStringRef patch = copyRenameChunks;
|
||||
bool readOk = false;
|
||||
|
||||
const QRegExp indexRegExp(QLatin1String("^index (\\w+)\\.{2}(\\w+)(?: \\d+)?(\\n|$)")); // index cap1..cap2(optionally: octal)
|
||||
// index cap1..cap2(optionally: octal)
|
||||
const QRegularExpression indexRegExp("^index (\\w+)\\.{2}(\\w+)(?: \\d+)?(\\n|$)");
|
||||
|
||||
if (fileOperation == FileData::CopyFile || fileOperation == FileData::RenameFile) {
|
||||
if (indexRegExp.indexIn(patch) == 0) {
|
||||
fileData.leftFileInfo.typeInfo = indexRegExp.cap(1);
|
||||
fileData.rightFileInfo.typeInfo = indexRegExp.cap(2);
|
||||
const QRegularExpressionMatch indexMatch = indexRegExp.match(patch);
|
||||
if (indexMatch.hasMatch() && indexMatch.capturedStart() == 0) {
|
||||
fileData.leftFileInfo.typeInfo = indexMatch.captured(1);
|
||||
fileData.rightFileInfo.typeInfo = indexMatch.captured(2);
|
||||
|
||||
patch.remove(0, indexRegExp.matchedLength());
|
||||
patch = patch.mid(indexMatch.capturedEnd());
|
||||
|
||||
const QString leftStart = QString::fromLatin1("--- a/") + leftFileName;
|
||||
QChar leftFollow = patch.count() > leftStart.count() ? patch.at(leftStart.count()) : QLatin1Char('\n');
|
||||
|
||||
// followed by leftFileRegExp
|
||||
if (patch.startsWith(leftStart) && fileNameEnd(leftFollow)) {
|
||||
patch.remove(0, patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1);
|
||||
patch = patch.mid(patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1);
|
||||
|
||||
// followed by rightFileRegExp
|
||||
const QString rightStart = QString::fromLatin1("+++ b/") + rightFileName;
|
||||
@@ -990,7 +1010,7 @@ static FileData readCopyRenameChunks(const QString ©RenameChunks,
|
||||
|
||||
// followed by rightFileRegExp
|
||||
if (patch.startsWith(rightStart) && fileNameEnd(rightFollow)) {
|
||||
patch.remove(0, patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1);
|
||||
patch = patch.mid(patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1);
|
||||
|
||||
fileData.chunks = readChunks(patch,
|
||||
&fileData.lastChunkAtTheEndOfFile,
|
||||
@@ -1011,15 +1031,19 @@ static FileData readCopyRenameChunks(const QString ©RenameChunks,
|
||||
return fileData;
|
||||
}
|
||||
|
||||
static QList<FileData> readGitPatch(const QString &patch, bool *ok)
|
||||
static QList<FileData> readGitPatch(QStringRef patch, bool *ok)
|
||||
{
|
||||
const QRegExp simpleGitRegExp(QLatin1String("(?:\\n|^)diff --git a/([^\\n]+) b/\\1\\n")); // diff --git a/cap1 b/cap1
|
||||
|
||||
const QRegExp similarityRegExp(QLatin1String(
|
||||
"(?:\\n|^)diff --git a/([^\\n]+) b/([^\\n]+)\\n" // diff --git a/cap1 b/cap2
|
||||
const QRegularExpression simpleGitRegExp(
|
||||
"^diff --git a/([^\\n]+) b/\\1\\n" // diff --git a/cap1 b/cap1
|
||||
, QRegularExpression::MultilineOption);
|
||||
|
||||
const QRegularExpression similarityRegExp(
|
||||
"^diff --git a/([^\\n]+) b/([^\\n]+)\\n" // diff --git a/cap1 b/cap2
|
||||
"(?:dis)?similarity index \\d{1,3}%\\n" // similarity / dissimilarity index xxx% (100% max)
|
||||
"(copy|rename) from \\1\\n" // copy / rename from cap1
|
||||
"\\3 to \\2\\n")); // copy / rename (cap3) to cap2
|
||||
"\\3 to \\2\\n" // copy / rename (cap3) to cap2
|
||||
, QRegularExpression::MultilineOption);
|
||||
|
||||
bool readOk = false;
|
||||
|
||||
@@ -1027,20 +1051,46 @@ static QList<FileData> readGitPatch(const QString &patch, bool *ok)
|
||||
|
||||
bool simpleGitMatched;
|
||||
int pos = 0;
|
||||
QRegularExpressionMatch simpleGitMatch = simpleGitRegExp.match(patch);
|
||||
QRegularExpressionMatch similarityMatch = similarityRegExp.match(patch);
|
||||
auto calculateGitMatchAndPosition = [&]() {
|
||||
const int simpleGitPos = simpleGitRegExp.indexIn(patch, pos, QRegExp::CaretAtOffset);
|
||||
const int similarityPos = similarityRegExp.indexIn(patch, pos, QRegExp::CaretAtOffset);
|
||||
if (simpleGitPos < 0) {
|
||||
pos = similarityPos;
|
||||
simpleGitMatched = false;
|
||||
if (pos > 0) { // don't advance in the initial call
|
||||
if (simpleGitMatch.hasMatch() && similarityMatch.hasMatch()) {
|
||||
const int simpleGitPos = simpleGitMatch.capturedStart();
|
||||
const int similarityPos = similarityMatch.capturedStart();
|
||||
if (simpleGitPos <= similarityPos)
|
||||
simpleGitMatch = simpleGitRegExp.match(patch, simpleGitMatch.capturedEnd() - 1); // advance only simpleGit
|
||||
else
|
||||
similarityMatch = similarityRegExp.match(patch, similarityMatch.capturedEnd() - 1); // advance only similarity
|
||||
} else if (simpleGitMatch.hasMatch()) {
|
||||
simpleGitMatch = simpleGitRegExp.match(patch, simpleGitMatch.capturedEnd() - 1);
|
||||
} else if (similarityMatch.hasMatch()) {
|
||||
similarityMatch = similarityRegExp.match(patch, similarityMatch.capturedEnd() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (simpleGitMatch.hasMatch() && similarityMatch.hasMatch()) {
|
||||
const int simpleGitPos = simpleGitMatch.capturedStart();
|
||||
const int similarityPos = similarityMatch.capturedStart();
|
||||
pos = qMin(simpleGitPos, similarityPos);
|
||||
simpleGitMatched = (pos == simpleGitPos);
|
||||
return;
|
||||
} else if (similarityPos < 0) {
|
||||
pos = simpleGitPos;
|
||||
}
|
||||
|
||||
if (simpleGitMatch.hasMatch()) {
|
||||
pos = simpleGitMatch.capturedStart();
|
||||
simpleGitMatched = true;
|
||||
return;
|
||||
}
|
||||
pos = qMin(simpleGitPos, similarityPos);
|
||||
simpleGitMatched = (pos == simpleGitPos);
|
||||
|
||||
if (similarityMatch.hasMatch()) {
|
||||
pos = similarityMatch.capturedStart();
|
||||
simpleGitMatched = false;
|
||||
return;
|
||||
}
|
||||
|
||||
pos = -1;
|
||||
simpleGitMatched = true;
|
||||
};
|
||||
|
||||
// Set both pos and simpleGitMatched according to the first match:
|
||||
@@ -1052,61 +1102,15 @@ static QList<FileData> readGitPatch(const QString &patch, bool *ok)
|
||||
QString lastLeftFileName;
|
||||
QString lastRightFileName;
|
||||
FileData::FileOperation lastOperation = FileData::ChangeFile;
|
||||
do {
|
||||
if (endOfLastHeader > 0) {
|
||||
const QString headerAndChunks = patch.mid(endOfLastHeader,
|
||||
pos - endOfLastHeader);
|
||||
|
||||
FileData fileData;
|
||||
if (lastOperation == FileData::ChangeFile) {
|
||||
fileData = readGitHeaderAndChunks(headerAndChunks,
|
||||
lastLeftFileName,
|
||||
&readOk);
|
||||
} else {
|
||||
fileData = readCopyRenameChunks(headerAndChunks,
|
||||
lastOperation,
|
||||
lastLeftFileName,
|
||||
lastRightFileName,
|
||||
&readOk);
|
||||
}
|
||||
if (!readOk)
|
||||
break;
|
||||
|
||||
fileDataList.append(fileData);
|
||||
}
|
||||
|
||||
if (simpleGitMatched) {
|
||||
const QString fileName = simpleGitRegExp.cap(1);
|
||||
pos += simpleGitRegExp.matchedLength();
|
||||
endOfLastHeader = pos;
|
||||
lastLeftFileName = fileName;
|
||||
lastRightFileName = fileName;
|
||||
lastOperation = FileData::ChangeFile;
|
||||
} else {
|
||||
lastLeftFileName = similarityRegExp.cap(1);
|
||||
lastRightFileName = similarityRegExp.cap(2);
|
||||
const QString operation = similarityRegExp.cap(3);
|
||||
pos += similarityRegExp.matchedLength();
|
||||
endOfLastHeader = pos;
|
||||
if (operation == QLatin1String("copy"))
|
||||
lastOperation = FileData::CopyFile;
|
||||
else if (operation == QLatin1String("rename"))
|
||||
lastOperation = FileData::RenameFile;
|
||||
else
|
||||
break; // either copy or rename, otherwise broken
|
||||
}
|
||||
|
||||
// give both pos and simpleGitMatched a new value for the next match
|
||||
calculateGitMatchAndPosition();
|
||||
} while (pos != -1);
|
||||
|
||||
auto collectFileData = [&]() {
|
||||
if (endOfLastHeader > 0 && readOk) {
|
||||
const QString headerAndChunks = patch.mid(endOfLastHeader,
|
||||
patch.count() - endOfLastHeader - 1);
|
||||
const int end = pos < 0 ? patch.count() : pos;
|
||||
QStringRef headerAndChunks = patch.mid(endOfLastHeader,
|
||||
qMax(end - endOfLastHeader - 1, 0));
|
||||
|
||||
FileData fileData;
|
||||
if (lastOperation == FileData::ChangeFile) {
|
||||
|
||||
fileData = readGitHeaderAndChunks(headerAndChunks,
|
||||
lastLeftFileName,
|
||||
&readOk);
|
||||
@@ -1120,6 +1124,39 @@ static QList<FileData> readGitPatch(const QString &patch, bool *ok)
|
||||
if (readOk)
|
||||
fileDataList.append(fileData);
|
||||
}
|
||||
};
|
||||
|
||||
do {
|
||||
collectFileData();
|
||||
if (!readOk)
|
||||
break;
|
||||
|
||||
if (simpleGitMatched) {
|
||||
const QString fileName = simpleGitMatch.captured(1);
|
||||
pos = simpleGitMatch.capturedEnd();
|
||||
lastLeftFileName = fileName;
|
||||
lastRightFileName = fileName;
|
||||
lastOperation = FileData::ChangeFile;
|
||||
} else {
|
||||
lastLeftFileName = similarityMatch.captured(1);
|
||||
lastRightFileName = similarityMatch.captured(2);
|
||||
const QString operation = similarityMatch.captured(3);
|
||||
pos = similarityMatch.capturedEnd();
|
||||
if (operation == QLatin1String("copy"))
|
||||
lastOperation = FileData::CopyFile;
|
||||
else if (operation == QLatin1String("rename"))
|
||||
lastOperation = FileData::RenameFile;
|
||||
else
|
||||
break; // either copy or rename, otherwise broken
|
||||
}
|
||||
endOfLastHeader = pos;
|
||||
|
||||
// give both pos and simpleGitMatched a new value for the next match
|
||||
calculateGitMatchAndPosition();
|
||||
} while (pos != -1);
|
||||
|
||||
if (readOk)
|
||||
collectFileData();
|
||||
}
|
||||
|
||||
if (ok)
|
||||
@@ -1137,12 +1174,12 @@ QList<FileData> DiffUtils::readPatch(const QString &patch, bool *ok)
|
||||
|
||||
QList<FileData> fileDataList;
|
||||
|
||||
QString croppedPatch = patch;
|
||||
QStringRef croppedPatch(&patch);
|
||||
// Crop e.g. "-- \n2.10.2.windows.1\n\n" at end of file
|
||||
const QRegExp formatPatchEndingRegExp(QLatin1String("(\\n-- \\n\\S*\\n\\n$)"));
|
||||
const int pos = formatPatchEndingRegExp.indexIn(patch);
|
||||
if (pos != -1)
|
||||
croppedPatch = patch.left(pos + 1); // crop the ending for git format-patch
|
||||
const QRegularExpression formatPatchEndingRegExp("(\\n-- \\n\\S*\\n\\n$)");
|
||||
const QRegularExpressionMatch match = formatPatchEndingRegExp.match(croppedPatch);
|
||||
if (match.hasMatch())
|
||||
croppedPatch = croppedPatch.left(match.capturedStart() + 1);
|
||||
|
||||
fileDataList = readGitPatch(croppedPatch, &readOk);
|
||||
if (!readOk)
|
||||
|
Reference in New Issue
Block a user