# # # patch "guitone/guitone.pro" # from [c3cd9a2364eac94fa842a67541f29c2fb8174a1c] # to [c39c04b1068a4e5016cbd856f6969e2dadbe7e52] # # patch "guitone/src/util/DiffParser.cpp" # from [58f392cedbb7c449253eba29f00e1063480efb6d] # to [35ce7ecf73aa3b9e687a7e3056f9f2722f8dcf5b] # # patch "guitone/src/util/DiffParser.h" # from [2365a3bdb7d636f351b969ff3e329bf8d215d318] # to [d2f98e7daeae0b9a95d9288c577ab703f093e2ed] # ============================================================ --- guitone/guitone.pro c3cd9a2364eac94fa842a67541f29c2fb8174a1c +++ guitone/guitone.pro c39c04b1068a4e5016cbd856f6969e2dadbe7e52 @@ -25,7 +25,8 @@ HEADERS += src/view/Guitone.h \ src/model/Graph.h \ src/util/IconProvider.h \ src/util/StanzaParser.h \ - src/util/Settings.h + src/util/Settings.h \ + src/util/DiffParser.h SOURCES += src/view/Guitone.cpp \ src/view/TreeView.cpp \ src/view/Splitter.cpp \ @@ -47,6 +48,7 @@ SOURCES += src/view/Guitone.cpp \ src/util/IconProvider.cpp \ src/util/StanzaParser.cpp \ src/util/Settings.cpp \ + src/util/DiffParser.cpp \ src/main.cpp FORMS += res/dialogs/switch_workspace.ui \ res/dialogs/preferences.ui \ ============================================================ --- guitone/src/util/DiffParser.cpp 58f392cedbb7c449253eba29f00e1063480efb6d +++ guitone/src/util/DiffParser.cpp 35ce7ecf73aa3b9e687a7e3056f9f2722f8dcf5b @@ -20,6 +20,9 @@ #include "DiffParser.h" +#include +#include + DiffParser::DiffParser(const QString & input) { parse(input); @@ -31,37 +34,45 @@ void DiffParser::parse(const QString & i { if (input.length() == 0) return; - QStringList lines = input.split(QRegExp("/[\n\r]+/")); + QStringList lines = input.split(QRegExp("/[\\n\\r]+/")); QString curFile; Diff * curDiff; DiffHunk * curHunk; - int leftStart = 0, leftLines = 0, rightStart = 0, rightLines = 0; + DiffLines * curLine; + int leftLinesCount = 0, rightLinesCount = 0; for (int i=0, s=lines.size(); i 0); - QChar firstChar = line.at(0); - if (firstChar == '=') + QChar curChar = line.at(0); + QChar lastChar = ' ', nextChar = ' '; + if (i > 0) lastChar = lines.at(i-1).at(0); + if (i < s-1) nextChar = lines.at(i+1).at(0); + + // + // parse file diff separators, setup new DiffFile object + // + if (curChar == '=') { QString nextLine(lines.at(++i)); // check if this is a binary - QRegExp rx = QRegExp("/^#\s(.+)\sis binary/"); + QRegExp rx = QRegExp("/^#\\s(.+)\\sis binary/"); if (rx.indexIn(nextLine) != -1) { curDiff->is_binary = true; - fileDiffs->insert(regex.cap(1), &curDiff); + fileDiffs.insert(rx.cap(1), curDiff); continue; } // then this should be a normal file diff - QRegExp rx = QRegExp("/^---\s(.+)\s+\w{40}/"); + rx = QRegExp("/^---\\s(.+)\\s+\\w{40}/"); Q_ASSERT(rx.indexIn(nextLine) > -1); - curFile = rx.at(1); + curFile = rx.cap(1); // create a new diff curDiff = new Diff(); @@ -71,42 +82,186 @@ void DiffParser::parse(const QString & i continue; } - if (firstChar == '@') + // + // parse hunk lines, setup new hunk object + // + if (curChar == '@') { - QRegExp rx = QRegExp("/^@@\s+\-(\d+)(,?)(\d*)\s+\+(\d+)(,?)(\d*)\s+@@/"); + QString nextLine(lines.at(++i)); + + QRegExp rx = QRegExp("/^@@\\s+\\-(\\d+)(,?)(\\d*)\\s+\\+(\\d+)(,?)(\\d*)\\s+@@/"); Q_ASSERT(rx.indexIn(nextLine) > -1); QStringList list = rx.capturedTexts(); Q_ASSERT(list.size() >= 2); + // create a new Hunk + curHunk = new DiffHunk(); + curDiff->hunks.push_back(curHunk); + // extract line numbers and positions - leftStart = list.at(1).toInt(); + curHunk->leftStart = list.at(1).toInt(); if (list.at(2) == ",") - leftLines = list.at(3).toInt(); + curHunk->leftCount = list.at(3).toInt(); else - leftLines = 1; - rightStart = list.at(4).toInt(); + curHunk->leftCount = 1; + + curHunk->rightStart = list.at(4).toInt(); if (list.at(5) == ",") - rightLines = list.at(6).toInt(); + curHunk->rightCount = list.at(6).toInt(); else - rightLines = 1; + curHunk->rightCount = 1; - // create a new Hunk - curHunk = new DiffHunk(); - curDiff->hunks.push_back(curHunk); + curLine = 0; - // now skip all unchanged lines up to the first change - minStart = leftStart > rightStart ? rightStart : leftStart; - i += minStart; + continue; + } + + // unchanged lines are simply skipped, but counted for both sides + if (curChar == ' ') + { + leftLinesCount++; + rightLinesCount++; + continue; + } + + // + // Possible cases to handle + // + // " basic" + // "+new" + // + // and + // + // "-old" + // "+new" + // + // and + // + // "+new" + // "+new" + // + if (curChar == '+') + { + // create linked dummy item + if (lastChar == ' ') + { + DiffLines * lastLine = new DiffLines(); + lastLine->startPos = leftLinesCount; + lastLine->changeLen = 0; + lastLine->state = DiffLines::Removed; + + curHunk->lines.push_back(lastLine); + curLine = new DiffLines(); + curHunk->lines.push_back(curLine); + + curLine->startPos = rightLinesCount; + curLine->changeLen = 1; + curLine->contents.push_back(line.mid(1)); + + lastLine->friendLines = curLine; + curLine->friendLines = lastLine; + + leftLinesCount++; + continue; + } - continue; + if (lastChar == '+') + { + curLine->contents.push_back(line.mid(1)); + curLine->changeLen++; + leftLinesCount++; + continue; + } + + if (lastChar == '-') + { + curLine = new DiffLines(); + curHunk->lines.push_back(curLine); + + curLine->startPos = rightLinesCount; + curLine->changeLen = 1; + curLine->state = DiffLines::Added; + curLine->contents.push_back(line.mid(1)); + + DiffLines * lastLine = curHunk->lines.last(); + Q_ASSERT(lastLine); + curLine->friendLines = lastLine; + lastLine->friendLines = curLine; + + leftLinesCount++; + continue; + } + + qWarning("unknown last char %c", lastChar.toLatin1()); } + + // + // Possible cases to handle + // + // "-old" + // " basic" + // + // and + // + // "-old" + // "+new" (already handled above) + // + // and + // + // "-old" + // "-old" + // + if (curChar == '-') + { + // create linked dummy item + if (nextChar == ' ') + { + DiffLines * nextLine = new DiffLines(); + nextLine->startPos = rightLinesCount; + nextLine->changeLen = 0; + nextLine->state = DiffLines::Added; + + curLine = new DiffLines(); + curHunk->lines.push_back(curLine); + + curHunk->lines.push_back(nextLine); + + curLine->startPos = leftLinesCount; + curLine->changeLen = 1; + curLine->contents.push_back(line.mid(1)); + + nextLine->friendLines = curLine; + curLine->friendLines = nextLine; + + rightLinesCount++; + continue; + } + + if (nextChar == '+') + { + // this case is already handled above + curLine->contents.push_back(line.mid(1)); + curLine->changeLen++; + rightLinesCount++; + continue; + } + + if (nextChar == '-') + { + // this case is already handled above + curLine->changeLen++; + rightLinesCount++; + continue; + } + + qWarning("unknown next char %c", lastChar.toLatin1()); + } - // TODO: parse single lines - // TODO: what if more than a single add/remove/add-remove comes up? + qWarning("unknown current char %c", curChar.toLatin1()); } } -Diff DiffParser::getDiff(const QString & filename) const +Diff* DiffParser::getDiff(const QString & filename) { Q_ASSERT(fileDiffs.contains(filename)); return fileDiffs.value(filename); ============================================================ --- guitone/src/util/DiffParser.h 2365a3bdb7d636f351b969ff3e329bf8d215d318 +++ guitone/src/util/DiffParser.h d2f98e7daeae0b9a95d9288c577ab703f093e2ed @@ -21,19 +21,34 @@ #ifndef DIFF_PARSER_H #define DIFF_PARSER_H -#include +#include +#include +#include +#include -typedef struct { - int lineno; - int linecount; - enum state{ADDED, REMOVED}; - QString content; -} DiffHunk; +struct DiffLines +{ + enum State {Added, Removed} state; + int startPos; + int changeLen; + QVector contents; + DiffLines * friendLines; +}; -typedef struct { +struct DiffHunk +{ + QVector lines; + int leftStart; + int leftCount; + int rightStart; + int rightCount; +}; + +struct Diff +{ QVector hunks; bool is_binary; -} Diff; +}; class DiffParser : public QObject { @@ -41,7 +56,7 @@ public: public: DiffParser(const QString &); ~DiffParser(); - Diff getDiff(const QString &) const; + Diff* getDiff(const QString &); private: void parse(const QString &); QMap fileDiffs;