forked from qt-creator/qt-creator
Move internal structures and some functions into diffutils.h
Change-Id: Ia55e556fdb8de3a2aeebf768ad9db66d840766f2 Reviewed-by: Jarek Kobus <jaroslaw.kobus@digia.com>
This commit is contained in:
@@ -11,6 +11,7 @@ HEADERS += diffeditor_global.h \
|
|||||||
diffeditormanager.h \
|
diffeditormanager.h \
|
||||||
diffeditorplugin.h \
|
diffeditorplugin.h \
|
||||||
differ.h \
|
differ.h \
|
||||||
|
diffutils.h \
|
||||||
sidebysidediffeditorwidget.h
|
sidebysidediffeditorwidget.h
|
||||||
|
|
||||||
SOURCES += diffeditor.cpp \
|
SOURCES += diffeditor.cpp \
|
||||||
@@ -21,6 +22,7 @@ SOURCES += diffeditor.cpp \
|
|||||||
diffeditormanager.cpp \
|
diffeditormanager.cpp \
|
||||||
diffeditorplugin.cpp \
|
diffeditorplugin.cpp \
|
||||||
differ.cpp \
|
differ.cpp \
|
||||||
|
diffutils.cpp \
|
||||||
sidebysidediffeditorwidget.cpp
|
sidebysidediffeditorwidget.cpp
|
||||||
|
|
||||||
RESOURCES +=
|
RESOURCES +=
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ QtcPlugin {
|
|||||||
"diffeditorplugin.h",
|
"diffeditorplugin.h",
|
||||||
"differ.cpp",
|
"differ.cpp",
|
||||||
"differ.h",
|
"differ.h",
|
||||||
|
"diffutils.cpp",
|
||||||
|
"diffutils.h",
|
||||||
"sidebysidediffeditorwidget.cpp",
|
"sidebysidediffeditorwidget.cpp",
|
||||||
"sidebysidediffeditorwidget.h",
|
"sidebysidediffeditorwidget.h",
|
||||||
]
|
]
|
||||||
|
|||||||
351
src/plugins/diffeditor/diffutils.cpp
Normal file
351
src/plugins/diffeditor/diffutils.cpp
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "diffutils.h"
|
||||||
|
#include "differ.h"
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace DiffEditor {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
static QList<TextLineData> assemblyRows(const QStringList &lines,
|
||||||
|
const QMap<int, int> &lineSpans)
|
||||||
|
{
|
||||||
|
QList<TextLineData> data;
|
||||||
|
|
||||||
|
const int lineCount = lines.count();
|
||||||
|
for (int i = 0; i <= lineCount; i++) {
|
||||||
|
for (int j = 0; j < lineSpans.value(i); j++)
|
||||||
|
data.append(TextLineData(TextLineData::Separator));
|
||||||
|
if (i < lineCount)
|
||||||
|
data.append(lines.at(i));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool lastLinesEqual(const QStringList &leftLines,
|
||||||
|
const QStringList &rightLines)
|
||||||
|
{
|
||||||
|
const bool leftLineEqual = leftLines.count()
|
||||||
|
? leftLines.last().isEmpty()
|
||||||
|
: true;
|
||||||
|
const bool rightLineEqual = rightLines.count()
|
||||||
|
? rightLines.last().isEmpty()
|
||||||
|
: true;
|
||||||
|
return leftLineEqual && rightLineEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleLine(const QStringList &newLines,
|
||||||
|
int line,
|
||||||
|
QStringList *lines,
|
||||||
|
int *lineNumber,
|
||||||
|
int *charNumber)
|
||||||
|
{
|
||||||
|
if (line < newLines.count()) {
|
||||||
|
const QString text = newLines.at(line);
|
||||||
|
if (lines->isEmpty() || line > 0) {
|
||||||
|
if (line > 0)
|
||||||
|
++*lineNumber;
|
||||||
|
lines->append(text);
|
||||||
|
} else {
|
||||||
|
lines->last() += text;
|
||||||
|
}
|
||||||
|
*charNumber += text.count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDifference(const QString &text,
|
||||||
|
QStringList *lines,
|
||||||
|
QMap<int, int> *changedPositions,
|
||||||
|
int *lineNumber,
|
||||||
|
int *charNumber)
|
||||||
|
{
|
||||||
|
const int oldPosition = *lineNumber + *charNumber;
|
||||||
|
const QStringList newLeftLines = text.split(QLatin1Char('\n'));
|
||||||
|
for (int line = 0; line < newLeftLines.count(); ++line)
|
||||||
|
handleLine(newLeftLines, line, lines, lineNumber, charNumber);
|
||||||
|
const int newPosition = *lineNumber + *charNumber;
|
||||||
|
changedPositions->insert(oldPosition, newPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* leftDiffList can contain only deletions and equalities,
|
||||||
|
* while rightDiffList can contain only insertions and equalities.
|
||||||
|
* The number of equalities on both lists must be the same.
|
||||||
|
*/
|
||||||
|
ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
|
||||||
|
const QList<Diff> &rightDiffList)
|
||||||
|
{
|
||||||
|
ChunkData chunkData;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
QStringList leftLines;
|
||||||
|
QStringList rightLines;
|
||||||
|
|
||||||
|
// <line number, span count>
|
||||||
|
QMap<int, int> leftSpans;
|
||||||
|
QMap<int, int> rightSpans;
|
||||||
|
// <left line number, right line number>
|
||||||
|
QMap<int, int> equalLines;
|
||||||
|
|
||||||
|
int leftLineNumber = 0;
|
||||||
|
int rightLineNumber = 0;
|
||||||
|
int leftCharNumber = 0;
|
||||||
|
int rightCharNumber = 0;
|
||||||
|
int leftLineAligned = -1;
|
||||||
|
int rightLineAligned = -1;
|
||||||
|
bool lastLineEqual = true;
|
||||||
|
|
||||||
|
while (i <= leftDiffList.count() && j <= rightDiffList.count()) {
|
||||||
|
const Diff leftDiff = i < leftDiffList.count()
|
||||||
|
? leftDiffList.at(i)
|
||||||
|
: Diff(Diff::Equal);
|
||||||
|
const Diff rightDiff = j < rightDiffList.count()
|
||||||
|
? rightDiffList.at(j)
|
||||||
|
: Diff(Diff::Equal);
|
||||||
|
|
||||||
|
if (leftDiff.command == Diff::Delete) {
|
||||||
|
// process delete
|
||||||
|
handleDifference(leftDiff.text, &leftLines, &chunkData.changedLeftPositions, &leftLineNumber, &leftCharNumber);
|
||||||
|
lastLineEqual = lastLinesEqual(leftLines, rightLines);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (rightDiff.command == Diff::Insert) {
|
||||||
|
// process insert
|
||||||
|
handleDifference(rightDiff.text, &rightLines, &chunkData.changedRightPositions, &rightLineNumber, &rightCharNumber);
|
||||||
|
lastLineEqual = lastLinesEqual(leftLines, rightLines);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (leftDiff.command == Diff::Equal && rightDiff.command == Diff::Equal) {
|
||||||
|
// process equal
|
||||||
|
const QStringList newLeftLines = leftDiff.text.split(QLatin1Char('\n'));
|
||||||
|
const QStringList newRightLines = rightDiff.text.split(QLatin1Char('\n'));
|
||||||
|
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
|
while (line < qMax(newLeftLines.count(), newRightLines.count())) {
|
||||||
|
handleLine(newLeftLines, line, &leftLines, &leftLineNumber, &leftCharNumber);
|
||||||
|
handleLine(newRightLines, line, &rightLines, &rightLineNumber, &rightCharNumber);
|
||||||
|
|
||||||
|
const int commonLineCount = qMin(newLeftLines.count(), newRightLines.count());
|
||||||
|
if (line < commonLineCount) {
|
||||||
|
// try to align
|
||||||
|
const int leftDifference = leftLineNumber - leftLineAligned;
|
||||||
|
const int rightDifference = rightLineNumber - rightLineAligned;
|
||||||
|
|
||||||
|
if (leftDifference && rightDifference) {
|
||||||
|
bool doAlign = true;
|
||||||
|
if (line == 0 // omit alignment when first lines of equalities are empty
|
||||||
|
&& (newLeftLines.at(0).isEmpty() || newRightLines.at(0).isEmpty())) {
|
||||||
|
doAlign = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == commonLineCount - 1) {
|
||||||
|
// omit alignment when last lines of equalities are empty
|
||||||
|
if (leftLines.last().isEmpty() || rightLines.last().isEmpty())
|
||||||
|
doAlign = false;
|
||||||
|
|
||||||
|
// unless it's the last dummy line (don't omit in that case)
|
||||||
|
if (i == leftDiffList.count() && j == rightDiffList.count())
|
||||||
|
doAlign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doAlign) {
|
||||||
|
// align here
|
||||||
|
leftLineAligned = leftLineNumber;
|
||||||
|
rightLineAligned = rightLineNumber;
|
||||||
|
|
||||||
|
// insert separators if needed
|
||||||
|
if (rightDifference > leftDifference)
|
||||||
|
leftSpans.insert(leftLineNumber, rightDifference - leftDifference);
|
||||||
|
else if (leftDifference > rightDifference)
|
||||||
|
rightSpans.insert(rightLineNumber, leftDifference - rightDifference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if lines are equal
|
||||||
|
if ((line < commonLineCount - 1) // before the last common line in equality
|
||||||
|
|| (line == commonLineCount - 1 // or the last common line in equality
|
||||||
|
&& i == leftDiffList.count() // and it's the last iteration
|
||||||
|
&& j == rightDiffList.count())) {
|
||||||
|
if (line > 0 || lastLineEqual)
|
||||||
|
equalLines.insert(leftLineNumber, rightLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line > 0)
|
||||||
|
lastLineEqual = true;
|
||||||
|
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<TextLineData> leftData = assemblyRows(leftLines,
|
||||||
|
leftSpans);
|
||||||
|
QList<TextLineData> rightData = assemblyRows(rightLines,
|
||||||
|
rightSpans);
|
||||||
|
|
||||||
|
// fill ending separators
|
||||||
|
for (int i = leftData.count(); i < rightData.count(); i++)
|
||||||
|
leftData.append(TextLineData(TextLineData::Separator));
|
||||||
|
for (int i = rightData.count(); i < leftData.count(); i++)
|
||||||
|
rightData.append(TextLineData(TextLineData::Separator));
|
||||||
|
|
||||||
|
const int visualLineCount = leftData.count();
|
||||||
|
int leftLine = -1;
|
||||||
|
int rightLine = -1;
|
||||||
|
for (int i = 0; i < visualLineCount; i++) {
|
||||||
|
const TextLineData &leftTextLine = leftData.at(i);
|
||||||
|
const TextLineData &rightTextLine = rightData.at(i);
|
||||||
|
RowData row(leftTextLine, rightTextLine);
|
||||||
|
|
||||||
|
if (leftTextLine.textLineType == TextLineData::TextLine)
|
||||||
|
++leftLine;
|
||||||
|
if (rightTextLine.textLineType == TextLineData::TextLine)
|
||||||
|
++rightLine;
|
||||||
|
if (equalLines.value(leftLine, -1) == rightLine)
|
||||||
|
row.equal = true;
|
||||||
|
|
||||||
|
chunkData.rows.append(row);
|
||||||
|
}
|
||||||
|
return chunkData;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileData calculateContextData(const ChunkData &originalData, int contextLinesNumber)
|
||||||
|
{
|
||||||
|
if (contextLinesNumber < 0)
|
||||||
|
return FileData(originalData);
|
||||||
|
|
||||||
|
const int joinChunkThreshold = 1;
|
||||||
|
|
||||||
|
FileData fileData;
|
||||||
|
QMap<int, bool> hiddenRows;
|
||||||
|
int i = 0;
|
||||||
|
while (i < originalData.rows.count()) {
|
||||||
|
const RowData &row = originalData.rows[i];
|
||||||
|
if (row.equal) {
|
||||||
|
// count how many equal
|
||||||
|
int equalRowStart = i;
|
||||||
|
i++;
|
||||||
|
while (i < originalData.rows.count()) {
|
||||||
|
const RowData originalRow = originalData.rows.at(i);
|
||||||
|
if (!originalRow.equal)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const bool first = equalRowStart == 0; // includes first line?
|
||||||
|
const bool last = i == originalData.rows.count(); // includes last line?
|
||||||
|
|
||||||
|
const int firstLine = first ? 0 : equalRowStart + contextLinesNumber;
|
||||||
|
const int lastLine = last ? originalData.rows.count() : i - contextLinesNumber;
|
||||||
|
|
||||||
|
if (firstLine < lastLine - joinChunkThreshold) {
|
||||||
|
for (int j = firstLine; j < lastLine; j++) {
|
||||||
|
hiddenRows.insert(j, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// iterate to the next row
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
int leftCharCounter = 0;
|
||||||
|
int rightCharCounter = 0;
|
||||||
|
QMap<int, int>::ConstIterator leftChangedIt = originalData.changedLeftPositions.constBegin();
|
||||||
|
QMap<int, int>::ConstIterator rightChangedIt = originalData.changedRightPositions.constBegin();
|
||||||
|
const QMap<int, int>::ConstIterator leftChangedItEnd = originalData.changedLeftPositions.constEnd();
|
||||||
|
const QMap<int, int>::ConstIterator rightChangedItEnd = originalData.changedRightPositions.constEnd();
|
||||||
|
while (i < originalData.rows.count()) {
|
||||||
|
if (!hiddenRows.contains(i)) {
|
||||||
|
ChunkData chunkData;
|
||||||
|
int leftOffset = leftCharCounter;
|
||||||
|
int rightOffset = rightCharCounter;
|
||||||
|
chunkData.contextChunk = false;
|
||||||
|
while (i < originalData.rows.count()) {
|
||||||
|
if (hiddenRows.contains(i))
|
||||||
|
break;
|
||||||
|
RowData rowData = originalData.rows.at(i);
|
||||||
|
chunkData.rows.append(rowData);
|
||||||
|
|
||||||
|
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
||||||
|
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
|
||||||
|
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
||||||
|
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (leftChangedIt != leftChangedItEnd) {
|
||||||
|
if (leftChangedIt.key() < leftOffset
|
||||||
|
|| leftChangedIt.key() > leftCharCounter)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const int startPos = leftChangedIt.key();
|
||||||
|
const int endPos = leftChangedIt.value();
|
||||||
|
chunkData.changedLeftPositions.insert(startPos - leftOffset, endPos - leftOffset);
|
||||||
|
leftChangedIt++;
|
||||||
|
}
|
||||||
|
while (rightChangedIt != rightChangedItEnd) {
|
||||||
|
if (rightChangedIt.key() < rightOffset
|
||||||
|
|| rightChangedIt.key() > rightCharCounter)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const int startPos = rightChangedIt.key();
|
||||||
|
const int endPos = rightChangedIt.value();
|
||||||
|
chunkData.changedRightPositions.insert(startPos - rightOffset, endPos - rightOffset);
|
||||||
|
rightChangedIt++;
|
||||||
|
}
|
||||||
|
fileData.chunks.append(chunkData);
|
||||||
|
} else {
|
||||||
|
ChunkData chunkData;
|
||||||
|
chunkData.contextChunk = true;
|
||||||
|
while (i < originalData.rows.count()) {
|
||||||
|
if (!hiddenRows.contains(i))
|
||||||
|
break;
|
||||||
|
RowData rowData = originalData.rows.at(i);
|
||||||
|
chunkData.rows.append(rowData);
|
||||||
|
|
||||||
|
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
||||||
|
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
|
||||||
|
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
||||||
|
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
fileData.chunks.append(chunkData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileData;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace DiffEditor
|
||||||
96
src/plugins/diffeditor/diffutils.h
Normal file
96
src/plugins/diffeditor/diffutils.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef DIFFUTILS_H
|
||||||
|
#define DIFFUTILS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include "diffeditorcontroller.h"
|
||||||
|
|
||||||
|
namespace DiffEditor {
|
||||||
|
|
||||||
|
class Diff;
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class TextLineData {
|
||||||
|
public:
|
||||||
|
enum TextLineType {
|
||||||
|
TextLine,
|
||||||
|
Separator,
|
||||||
|
Invalid
|
||||||
|
};
|
||||||
|
TextLineData() : textLineType(Invalid) {}
|
||||||
|
TextLineData(const QString &txt) : textLineType(TextLine), text(txt) {}
|
||||||
|
TextLineData(TextLineType t) : textLineType(t) {}
|
||||||
|
TextLineType textLineType;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RowData {
|
||||||
|
public:
|
||||||
|
RowData() : equal(false) {}
|
||||||
|
RowData(const TextLineData &l)
|
||||||
|
: leftLine(l), rightLine(l), equal(true) {}
|
||||||
|
RowData(const TextLineData &l, const TextLineData &r)
|
||||||
|
: leftLine(l), rightLine(r), equal(false) {}
|
||||||
|
TextLineData leftLine;
|
||||||
|
TextLineData rightLine;
|
||||||
|
bool equal;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChunkData {
|
||||||
|
public:
|
||||||
|
ChunkData() : contextChunk(false) {}
|
||||||
|
QList<RowData> rows;
|
||||||
|
bool contextChunk;
|
||||||
|
// start position, end position, TextLineData::Separator lines not taken into account
|
||||||
|
QMap<int, int> changedLeftPositions; // counting from the beginning of the chunk
|
||||||
|
QMap<int, int> changedRightPositions; // counting from the beginning of the chunk
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileData {
|
||||||
|
public:
|
||||||
|
FileData() {}
|
||||||
|
FileData(const ChunkData &chunkData) { chunks.append(chunkData); }
|
||||||
|
QList<ChunkData> chunks;
|
||||||
|
DiffEditorController::DiffFileInfo leftFileInfo;
|
||||||
|
DiffEditorController::DiffFileInfo rightFileInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
|
||||||
|
const QList<Diff> &rightDiffList);
|
||||||
|
FileData calculateContextData(const ChunkData &originalData,
|
||||||
|
int contextLinesNumber);
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace DiffEditor
|
||||||
|
|
||||||
|
#endif // DIFFUTILS_H
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "sidebysidediffeditorwidget.h"
|
#include "sidebysidediffeditorwidget.h"
|
||||||
#include "diffeditorguicontroller.h"
|
#include "diffeditorguicontroller.h"
|
||||||
|
#include "diffutils.h"
|
||||||
|
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
@@ -66,260 +67,7 @@ using namespace TextEditor;
|
|||||||
|
|
||||||
namespace DiffEditor {
|
namespace DiffEditor {
|
||||||
|
|
||||||
class TextLineData {
|
using namespace Internal;
|
||||||
public:
|
|
||||||
enum TextLineType {
|
|
||||||
TextLine,
|
|
||||||
Separator,
|
|
||||||
Invalid
|
|
||||||
};
|
|
||||||
TextLineData() : textLineType(Invalid) {}
|
|
||||||
TextLineData(const QString &txt) : textLineType(TextLine), text(txt) {}
|
|
||||||
TextLineData(TextLineType t) : textLineType(t) {}
|
|
||||||
TextLineType textLineType;
|
|
||||||
QString text;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RowData {
|
|
||||||
public:
|
|
||||||
RowData() : equal(false) {}
|
|
||||||
RowData(const TextLineData &l)
|
|
||||||
: leftLine(l), rightLine(l), equal(true) {}
|
|
||||||
RowData(const TextLineData &l, const TextLineData &r)
|
|
||||||
: leftLine(l), rightLine(r), equal(false) {}
|
|
||||||
TextLineData leftLine;
|
|
||||||
TextLineData rightLine;
|
|
||||||
bool equal;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ChunkData {
|
|
||||||
public:
|
|
||||||
ChunkData() : contextChunk(false) {}
|
|
||||||
QList<RowData> rows;
|
|
||||||
bool contextChunk;
|
|
||||||
// start position, end position, TextLineData::Separator lines not taken into account
|
|
||||||
QMap<int, int> changedLeftPositions; // counting from the beginning of the chunk
|
|
||||||
QMap<int, int> changedRightPositions; // counting from the beginning of the chunk
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileData {
|
|
||||||
public:
|
|
||||||
FileData() {}
|
|
||||||
FileData(const ChunkData &chunkData) { chunks.append(chunkData); }
|
|
||||||
QList<ChunkData> chunks;
|
|
||||||
DiffEditorController::DiffFileInfo leftFileInfo;
|
|
||||||
DiffEditorController::DiffFileInfo rightFileInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////
|
|
||||||
|
|
||||||
static QList<TextLineData> assemblyRows(const QStringList &lines,
|
|
||||||
const QMap<int, int> &lineSpans)
|
|
||||||
{
|
|
||||||
QList<TextLineData> data;
|
|
||||||
|
|
||||||
const int lineCount = lines.count();
|
|
||||||
for (int i = 0; i <= lineCount; i++) {
|
|
||||||
for (int j = 0; j < lineSpans.value(i); j++)
|
|
||||||
data.append(TextLineData(TextLineData::Separator));
|
|
||||||
if (i < lineCount)
|
|
||||||
data.append(lines.at(i));
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleLine(const QStringList &newLines,
|
|
||||||
int line,
|
|
||||||
QStringList *lines,
|
|
||||||
int *lineNumber,
|
|
||||||
int *charNumber)
|
|
||||||
{
|
|
||||||
if (line < newLines.count()) {
|
|
||||||
const QString text = newLines.at(line);
|
|
||||||
if (lines->isEmpty() || line > 0) {
|
|
||||||
if (line > 0)
|
|
||||||
++*lineNumber;
|
|
||||||
lines->append(text);
|
|
||||||
} else {
|
|
||||||
lines->last() += text;
|
|
||||||
}
|
|
||||||
*charNumber += text.count();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDifference(const QString &text,
|
|
||||||
QStringList *lines,
|
|
||||||
QMap<int, int> *changedPositions,
|
|
||||||
int *lineNumber,
|
|
||||||
int *charNumber)
|
|
||||||
{
|
|
||||||
const int oldPosition = *lineNumber + *charNumber;
|
|
||||||
const QStringList newLeftLines = text.split(QLatin1Char('\n'));
|
|
||||||
for (int line = 0; line < newLeftLines.count(); ++line)
|
|
||||||
handleLine(newLeftLines, line, lines, lineNumber, charNumber);
|
|
||||||
const int newPosition = *lineNumber + *charNumber;
|
|
||||||
changedPositions->insert(oldPosition, newPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool lastLinesEqual(const QStringList &leftLines,
|
|
||||||
const QStringList &rightLines)
|
|
||||||
{
|
|
||||||
const bool leftLineEqual = leftLines.count()
|
|
||||||
? leftLines.last().isEmpty()
|
|
||||||
: true;
|
|
||||||
const bool rightLineEqual = rightLines.count()
|
|
||||||
? rightLines.last().isEmpty()
|
|
||||||
: true;
|
|
||||||
return leftLineEqual && rightLineEqual;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* leftDiffList can contain only deletions and equalities,
|
|
||||||
* while rightDiffList can contain only insertions and equalities.
|
|
||||||
* The number of equalities on both lists must be the same.
|
|
||||||
*/
|
|
||||||
static ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
|
|
||||||
const QList<Diff> &rightDiffList)
|
|
||||||
{
|
|
||||||
ChunkData chunkData;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
QStringList leftLines;
|
|
||||||
QStringList rightLines;
|
|
||||||
|
|
||||||
// <line number, span count>
|
|
||||||
QMap<int, int> leftSpans;
|
|
||||||
QMap<int, int> rightSpans;
|
|
||||||
// <left line number, right line number>
|
|
||||||
QMap<int, int> equalLines;
|
|
||||||
|
|
||||||
int leftLineNumber = 0;
|
|
||||||
int rightLineNumber = 0;
|
|
||||||
int leftCharNumber = 0;
|
|
||||||
int rightCharNumber = 0;
|
|
||||||
int leftLineAligned = -1;
|
|
||||||
int rightLineAligned = -1;
|
|
||||||
bool lastLineEqual = true;
|
|
||||||
|
|
||||||
while (i <= leftDiffList.count() && j <= rightDiffList.count()) {
|
|
||||||
const Diff leftDiff = i < leftDiffList.count()
|
|
||||||
? leftDiffList.at(i)
|
|
||||||
: Diff(Diff::Equal);
|
|
||||||
const Diff rightDiff = j < rightDiffList.count()
|
|
||||||
? rightDiffList.at(j)
|
|
||||||
: Diff(Diff::Equal);
|
|
||||||
|
|
||||||
if (leftDiff.command == Diff::Delete) {
|
|
||||||
// process delete
|
|
||||||
handleDifference(leftDiff.text, &leftLines, &chunkData.changedLeftPositions, &leftLineNumber, &leftCharNumber);
|
|
||||||
lastLineEqual = lastLinesEqual(leftLines, rightLines);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (rightDiff.command == Diff::Insert) {
|
|
||||||
// process insert
|
|
||||||
handleDifference(rightDiff.text, &rightLines, &chunkData.changedRightPositions, &rightLineNumber, &rightCharNumber);
|
|
||||||
lastLineEqual = lastLinesEqual(leftLines, rightLines);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
if (leftDiff.command == Diff::Equal && rightDiff.command == Diff::Equal) {
|
|
||||||
// process equal
|
|
||||||
const QStringList newLeftLines = leftDiff.text.split(QLatin1Char('\n'));
|
|
||||||
const QStringList newRightLines = rightDiff.text.split(QLatin1Char('\n'));
|
|
||||||
|
|
||||||
int line = 0;
|
|
||||||
|
|
||||||
while (line < qMax(newLeftLines.count(), newRightLines.count())) {
|
|
||||||
handleLine(newLeftLines, line, &leftLines, &leftLineNumber, &leftCharNumber);
|
|
||||||
handleLine(newRightLines, line, &rightLines, &rightLineNumber, &rightCharNumber);
|
|
||||||
|
|
||||||
const int commonLineCount = qMin(newLeftLines.count(), newRightLines.count());
|
|
||||||
if (line < commonLineCount) {
|
|
||||||
// try to align
|
|
||||||
const int leftDifference = leftLineNumber - leftLineAligned;
|
|
||||||
const int rightDifference = rightLineNumber - rightLineAligned;
|
|
||||||
|
|
||||||
if (leftDifference && rightDifference) {
|
|
||||||
bool doAlign = true;
|
|
||||||
if (line == 0 // omit alignment when first lines of equalities are empty
|
|
||||||
&& (newLeftLines.at(0).isEmpty() || newRightLines.at(0).isEmpty())) {
|
|
||||||
doAlign = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line == commonLineCount - 1) {
|
|
||||||
// omit alignment when last lines of equalities are empty
|
|
||||||
if (leftLines.last().isEmpty() || rightLines.last().isEmpty())
|
|
||||||
doAlign = false;
|
|
||||||
|
|
||||||
// unless it's the last dummy line (don't omit in that case)
|
|
||||||
if (i == leftDiffList.count() && j == rightDiffList.count())
|
|
||||||
doAlign = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doAlign) {
|
|
||||||
// align here
|
|
||||||
leftLineAligned = leftLineNumber;
|
|
||||||
rightLineAligned = rightLineNumber;
|
|
||||||
|
|
||||||
// insert separators if needed
|
|
||||||
if (rightDifference > leftDifference)
|
|
||||||
leftSpans.insert(leftLineNumber, rightDifference - leftDifference);
|
|
||||||
else if (leftDifference > rightDifference)
|
|
||||||
rightSpans.insert(rightLineNumber, leftDifference - rightDifference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if lines are equal
|
|
||||||
if ((line < commonLineCount - 1) // before the last common line in equality
|
|
||||||
|| (line == commonLineCount - 1 // or the last common line in equality
|
|
||||||
&& i == leftDiffList.count() // and it's the last iteration
|
|
||||||
&& j == rightDiffList.count())) {
|
|
||||||
if (line > 0 || lastLineEqual)
|
|
||||||
equalLines.insert(leftLineNumber, rightLineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line > 0)
|
|
||||||
lastLineEqual = true;
|
|
||||||
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<TextLineData> leftData = assemblyRows(leftLines,
|
|
||||||
leftSpans);
|
|
||||||
QList<TextLineData> rightData = assemblyRows(rightLines,
|
|
||||||
rightSpans);
|
|
||||||
|
|
||||||
// fill ending separators
|
|
||||||
for (int i = leftData.count(); i < rightData.count(); i++)
|
|
||||||
leftData.append(TextLineData(TextLineData::Separator));
|
|
||||||
for (int i = rightData.count(); i < leftData.count(); i++)
|
|
||||||
rightData.append(TextLineData(TextLineData::Separator));
|
|
||||||
|
|
||||||
const int visualLineCount = leftData.count();
|
|
||||||
int leftLine = -1;
|
|
||||||
int rightLine = -1;
|
|
||||||
for (int i = 0; i < visualLineCount; i++) {
|
|
||||||
const TextLineData &leftTextLine = leftData.at(i);
|
|
||||||
const TextLineData &rightTextLine = rightData.at(i);
|
|
||||||
RowData row(leftTextLine, rightTextLine);
|
|
||||||
|
|
||||||
if (leftTextLine.textLineType == TextLineData::TextLine)
|
|
||||||
++leftLine;
|
|
||||||
if (rightTextLine.textLineType == TextLineData::TextLine)
|
|
||||||
++rightLine;
|
|
||||||
if (equalLines.value(leftLine, -1) == rightLine)
|
|
||||||
row.equal = true;
|
|
||||||
|
|
||||||
chunkData.rows.append(row);
|
|
||||||
}
|
|
||||||
return chunkData;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
|
|
||||||
@@ -1076,6 +824,7 @@ void SideBySideDiffEditorWidget::setDiff(const QList<DiffList> &diffList)
|
|||||||
m_diffList = diffList;
|
m_diffList = diffList;
|
||||||
m_originalChunkData.clear();
|
m_originalChunkData.clear();
|
||||||
m_contextFileData.clear();
|
m_contextFileData.clear();
|
||||||
|
const int contextLinesNumber = m_guiController ? m_guiController->contextLinesNumber() : 3;
|
||||||
|
|
||||||
for (int i = 0; i < m_diffList.count(); i++) {
|
for (int i = 0; i < m_diffList.count(); i++) {
|
||||||
const DiffList &dl = m_diffList.at(i);
|
const DiffList &dl = m_diffList.at(i);
|
||||||
@@ -1084,7 +833,7 @@ void SideBySideDiffEditorWidget::setDiff(const QList<DiffList> &diffList)
|
|||||||
handleWhitespaces(dl.diffList, &leftDiffs, &rightDiffs);
|
handleWhitespaces(dl.diffList, &leftDiffs, &rightDiffs);
|
||||||
ChunkData chunkData = calculateOriginalData(leftDiffs, rightDiffs);
|
ChunkData chunkData = calculateOriginalData(leftDiffs, rightDiffs);
|
||||||
m_originalChunkData.append(chunkData);
|
m_originalChunkData.append(chunkData);
|
||||||
FileData fileData = calculateContextData(chunkData);
|
FileData fileData = calculateContextData(chunkData, contextLinesNumber);
|
||||||
fileData.leftFileInfo = dl.leftFileInfo;
|
fileData.leftFileInfo = dl.leftFileInfo;
|
||||||
fileData.rightFileInfo = dl.rightFileInfo;
|
fileData.rightFileInfo = dl.rightFileInfo;
|
||||||
m_contextFileData.append(fileData);
|
m_contextFileData.append(fileData);
|
||||||
@@ -1110,10 +859,11 @@ void SideBySideDiffEditorWidget::handleWhitespaces(const QList<Diff> &input,
|
|||||||
void SideBySideDiffEditorWidget::setContextLinesNumber(int lines)
|
void SideBySideDiffEditorWidget::setContextLinesNumber(int lines)
|
||||||
{
|
{
|
||||||
Q_UNUSED(lines)
|
Q_UNUSED(lines)
|
||||||
|
const int contextLinesNumber = m_guiController ? m_guiController->contextLinesNumber() : 3;
|
||||||
|
|
||||||
for (int i = 0; i < m_contextFileData.count(); i++) {
|
for (int i = 0; i < m_contextFileData.count(); i++) {
|
||||||
const FileData oldFileData = m_contextFileData.at(i);
|
const FileData oldFileData = m_contextFileData.at(i);
|
||||||
FileData newFileData = calculateContextData(m_originalChunkData.at(i));
|
FileData newFileData = calculateContextData(m_originalChunkData.at(i), contextLinesNumber);
|
||||||
newFileData.leftFileInfo = oldFileData.leftFileInfo;
|
newFileData.leftFileInfo = oldFileData.leftFileInfo;
|
||||||
newFileData.rightFileInfo = oldFileData.rightFileInfo;
|
newFileData.rightFileInfo = oldFileData.rightFileInfo;
|
||||||
m_contextFileData[i] = newFileData;
|
m_contextFileData[i] = newFileData;
|
||||||
@@ -1147,112 +897,6 @@ void SideBySideDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
|
|||||||
m_rightEditor->centerCursor();
|
m_rightEditor->centerCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &originalData) const
|
|
||||||
{
|
|
||||||
const int contextLinesNumber = m_guiController ? m_guiController->contextLinesNumber() : 3;
|
|
||||||
if (contextLinesNumber < 0)
|
|
||||||
return FileData(originalData);
|
|
||||||
|
|
||||||
const int joinChunkThreshold = 1;
|
|
||||||
|
|
||||||
FileData fileData;
|
|
||||||
QMap<int, bool> hiddenRows;
|
|
||||||
int i = 0;
|
|
||||||
while (i < originalData.rows.count()) {
|
|
||||||
const RowData &row = originalData.rows[i];
|
|
||||||
if (row.equal) {
|
|
||||||
// count how many equal
|
|
||||||
int equalRowStart = i;
|
|
||||||
i++;
|
|
||||||
while (i < originalData.rows.count()) {
|
|
||||||
const RowData originalRow = originalData.rows.at(i);
|
|
||||||
if (!originalRow.equal)
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
const bool first = equalRowStart == 0; // includes first line?
|
|
||||||
const bool last = i == originalData.rows.count(); // includes last line?
|
|
||||||
|
|
||||||
const int firstLine = first ? 0 : equalRowStart + contextLinesNumber;
|
|
||||||
const int lastLine = last ? originalData.rows.count() : i - contextLinesNumber;
|
|
||||||
|
|
||||||
if (firstLine < lastLine - joinChunkThreshold) {
|
|
||||||
for (int j = firstLine; j < lastLine; j++) {
|
|
||||||
hiddenRows.insert(j, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// iterate to the next row
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
int leftCharCounter = 0;
|
|
||||||
int rightCharCounter = 0;
|
|
||||||
QMap<int, int>::ConstIterator leftChangedIt = originalData.changedLeftPositions.constBegin();
|
|
||||||
QMap<int, int>::ConstIterator rightChangedIt = originalData.changedRightPositions.constBegin();
|
|
||||||
const QMap<int, int>::ConstIterator leftChangedItEnd = originalData.changedLeftPositions.constEnd();
|
|
||||||
const QMap<int, int>::ConstIterator rightChangedItEnd = originalData.changedRightPositions.constEnd();
|
|
||||||
while (i < originalData.rows.count()) {
|
|
||||||
if (!hiddenRows.contains(i)) {
|
|
||||||
ChunkData chunkData;
|
|
||||||
int leftOffset = leftCharCounter;
|
|
||||||
int rightOffset = rightCharCounter;
|
|
||||||
chunkData.contextChunk = false;
|
|
||||||
while (i < originalData.rows.count()) {
|
|
||||||
if (hiddenRows.contains(i))
|
|
||||||
break;
|
|
||||||
RowData rowData = originalData.rows.at(i);
|
|
||||||
chunkData.rows.append(rowData);
|
|
||||||
|
|
||||||
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
|
||||||
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
|
|
||||||
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
|
||||||
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (leftChangedIt != leftChangedItEnd) {
|
|
||||||
if (leftChangedIt.key() < leftOffset
|
|
||||||
|| leftChangedIt.key() > leftCharCounter)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const int startPos = leftChangedIt.key();
|
|
||||||
const int endPos = leftChangedIt.value();
|
|
||||||
chunkData.changedLeftPositions.insert(startPos - leftOffset, endPos - leftOffset);
|
|
||||||
leftChangedIt++;
|
|
||||||
}
|
|
||||||
while (rightChangedIt != rightChangedItEnd) {
|
|
||||||
if (rightChangedIt.key() < rightOffset
|
|
||||||
|| rightChangedIt.key() > rightCharCounter)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const int startPos = rightChangedIt.key();
|
|
||||||
const int endPos = rightChangedIt.value();
|
|
||||||
chunkData.changedRightPositions.insert(startPos - rightOffset, endPos - rightOffset);
|
|
||||||
rightChangedIt++;
|
|
||||||
}
|
|
||||||
fileData.chunks.append(chunkData);
|
|
||||||
} else {
|
|
||||||
ChunkData chunkData;
|
|
||||||
chunkData.contextChunk = true;
|
|
||||||
while (i < originalData.rows.count()) {
|
|
||||||
if (!hiddenRows.contains(i))
|
|
||||||
break;
|
|
||||||
RowData rowData = originalData.rows.at(i);
|
|
||||||
chunkData.rows.append(rowData);
|
|
||||||
|
|
||||||
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
|
||||||
leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n'
|
|
||||||
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
|
||||||
rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n'
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
fileData.chunks.append(chunkData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fileData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SideBySideDiffEditorWidget::showDiff()
|
void SideBySideDiffEditorWidget::showDiff()
|
||||||
{
|
{
|
||||||
// TODO: remember the line number of the line in the middle
|
// TODO: remember the line number of the line in the middle
|
||||||
|
|||||||
@@ -46,11 +46,13 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
|
|
||||||
namespace DiffEditor {
|
namespace DiffEditor {
|
||||||
|
|
||||||
class DiffEditorGuiController;
|
class DiffEditorGuiController;
|
||||||
class SideDiffEditorWidget;
|
class SideDiffEditorWidget;
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
class ChunkData;
|
class ChunkData;
|
||||||
class FileData;
|
class FileData;
|
||||||
|
}
|
||||||
|
|
||||||
class DIFFEDITOR_EXPORT SideBySideDiffEditorWidget : public QWidget
|
class DIFFEDITOR_EXPORT SideBySideDiffEditorWidget : public QWidget
|
||||||
{
|
{
|
||||||
@@ -101,8 +103,7 @@ private:
|
|||||||
QList<QTextEdit::ExtraSelection> colorPositions(const QTextCharFormat &format,
|
QList<QTextEdit::ExtraSelection> colorPositions(const QTextCharFormat &format,
|
||||||
QTextCursor &cursor,
|
QTextCursor &cursor,
|
||||||
const QMap<int, int> &positions) const;
|
const QMap<int, int> &positions) const;
|
||||||
void colorDiff(const QList<FileData> &fileDataList);
|
void colorDiff(const QList<Internal::FileData> &fileDataList);
|
||||||
FileData calculateContextData(const ChunkData &originalData) const;
|
|
||||||
void showDiff();
|
void showDiff();
|
||||||
void synchronizeFoldings(SideDiffEditorWidget *source, SideDiffEditorWidget *destination);
|
void synchronizeFoldings(SideDiffEditorWidget *source, SideDiffEditorWidget *destination);
|
||||||
void jumpToOriginalFile(const QString &fileName, int lineNumber, int columnNumber);
|
void jumpToOriginalFile(const QString &fileName, int lineNumber, int columnNumber);
|
||||||
@@ -114,8 +115,8 @@ private:
|
|||||||
QSplitter *m_splitter;
|
QSplitter *m_splitter;
|
||||||
|
|
||||||
QList<DiffList> m_diffList; // list of original outputs from differ
|
QList<DiffList> m_diffList; // list of original outputs from differ
|
||||||
QList<ChunkData> m_originalChunkData; // one big chunk for every file, ignoreWhitespace taken into account
|
QList<Internal::ChunkData> m_originalChunkData; // one big chunk for every file, ignoreWhitespace taken into account
|
||||||
QList<FileData> m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account
|
QList<Internal::FileData> m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account
|
||||||
|
|
||||||
bool m_foldingBlocker;
|
bool m_foldingBlocker;
|
||||||
QString m_source;
|
QString m_source;
|
||||||
|
|||||||
Reference in New Issue
Block a user