2014-02-13 16:43:28 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-02-13 16:43:28 +01:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-02-13 16:43:28 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-02-13 16:43:28 +01:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "unifieddiffeditorwidget.h"
|
2017-05-09 12:19:11 +02:00
|
|
|
|
|
|
|
|
#include "diffeditorconstants.h"
|
2015-01-30 16:59:25 +01:00
|
|
|
#include "diffeditordocument.h"
|
2016-07-13 15:55:18 +02:00
|
|
|
#include "diffutils.h"
|
2014-02-13 16:43:28 +01:00
|
|
|
|
2015-02-26 13:22:35 +01:00
|
|
|
#include <QMenu>
|
2016-07-13 15:55:18 +02:00
|
|
|
#include <QPainter>
|
2015-04-16 15:31:25 +02:00
|
|
|
#include <QScrollBar>
|
2014-02-13 16:43:28 +01:00
|
|
|
#include <QTextBlock>
|
|
|
|
|
|
2017-05-09 12:19:11 +02:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
2015-02-26 13:22:35 +01:00
|
|
|
#include <texteditor/textdocument.h>
|
2014-09-26 09:14:03 +02:00
|
|
|
#include <texteditor/textdocumentlayout.h>
|
2014-02-13 16:43:28 +01:00
|
|
|
#include <texteditor/texteditorsettings.h>
|
|
|
|
|
#include <texteditor/fontsettings.h>
|
|
|
|
|
#include <texteditor/displaysettings.h>
|
|
|
|
|
|
|
|
|
|
#include <utils/tooltip/tooltip.h>
|
|
|
|
|
|
|
|
|
|
using namespace Core;
|
|
|
|
|
using namespace TextEditor;
|
|
|
|
|
|
|
|
|
|
namespace DiffEditor {
|
2015-01-30 14:51:44 +01:00
|
|
|
namespace Internal {
|
2015-01-30 14:46:20 +01:00
|
|
|
|
2014-02-13 16:43:28 +01:00
|
|
|
UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
|
2014-09-01 10:35:06 +02:00
|
|
|
: SelectableTextEditorWidget("DiffEditor.UnifiedDiffEditor", parent)
|
2016-07-13 15:55:18 +02:00
|
|
|
, m_controller(this)
|
2014-02-13 16:43:28 +01:00
|
|
|
{
|
|
|
|
|
DisplaySettings settings = displaySettings();
|
|
|
|
|
settings.m_textWrapping = false;
|
|
|
|
|
settings.m_displayLineNumbers = true;
|
|
|
|
|
settings.m_highlightCurrentLine = false;
|
|
|
|
|
settings.m_displayFoldingMarkers = true;
|
|
|
|
|
settings.m_markTextChanges = false;
|
|
|
|
|
settings.m_highlightBlocks = false;
|
|
|
|
|
SelectableTextEditorWidget::setDisplaySettings(settings);
|
|
|
|
|
|
|
|
|
|
setReadOnly(true);
|
2014-08-28 17:00:12 +02:00
|
|
|
connect(TextEditorSettings::instance(), &TextEditorSettings::displaySettingsChanged,
|
|
|
|
|
this, &UnifiedDiffEditorWidget::setDisplaySettings);
|
2014-02-13 16:43:28 +01:00
|
|
|
setDisplaySettings(TextEditorSettings::displaySettings());
|
|
|
|
|
setCodeStyle(TextEditorSettings::codeStyle());
|
|
|
|
|
|
2015-01-30 10:56:10 +01:00
|
|
|
connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
|
|
|
|
|
this, &UnifiedDiffEditorWidget::setFontSettings);
|
2014-02-13 16:43:28 +01:00
|
|
|
setFontSettings(TextEditorSettings::fontSettings());
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
clear(tr("No document"));
|
2014-02-13 16:43:28 +01:00
|
|
|
|
2015-01-30 10:56:10 +01:00
|
|
|
connect(this, &QPlainTextEdit::cursorPositionChanged,
|
|
|
|
|
this, &UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor);
|
2017-05-09 12:19:11 +02:00
|
|
|
|
|
|
|
|
m_context = new Core::IContext(this);
|
|
|
|
|
m_context->setWidget(this);
|
|
|
|
|
m_context->setContext(Core::Context(Constants::UNIFIED_VIEW_ID));
|
|
|
|
|
Core::ICore::addContextObject(m_context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UnifiedDiffEditorWidget::~UnifiedDiffEditorWidget()
|
|
|
|
|
{
|
|
|
|
|
Core::ICore::removeContextObject(m_context);
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
void UnifiedDiffEditorWidget::setDocument(DiffEditorDocument *document)
|
2014-02-13 16:43:28 +01:00
|
|
|
{
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.setDocument(document);
|
2016-11-23 11:20:12 +01:00
|
|
|
clear();
|
|
|
|
|
QList<FileData> diffFileList;
|
|
|
|
|
QString workingDirectory;
|
|
|
|
|
if (document) {
|
|
|
|
|
diffFileList = document->diffFiles();
|
|
|
|
|
workingDirectory = document->baseDirectory();
|
|
|
|
|
}
|
|
|
|
|
setDiff(diffFileList, workingDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DiffEditorDocument *UnifiedDiffEditorWidget::diffDocument() const
|
|
|
|
|
{
|
|
|
|
|
return m_controller.document();
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
void UnifiedDiffEditorWidget::saveState()
|
2014-07-11 12:55:31 +02:00
|
|
|
{
|
|
|
|
|
if (!m_state.isNull())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
m_state = SelectableTextEditorWidget::saveState();
|
2014-07-11 12:55:31 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
void UnifiedDiffEditorWidget::restoreState()
|
2014-07-11 12:55:31 +02:00
|
|
|
{
|
|
|
|
|
if (m_state.isNull())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
|
|
|
|
|
m_controller.m_ignoreCurrentIndexChange = true;
|
2015-01-30 16:59:25 +01:00
|
|
|
SelectableTextEditorWidget::restoreState(m_state);
|
2014-07-11 12:55:31 +02:00
|
|
|
m_state.clear();
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
|
2014-07-11 12:55:31 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-13 16:43:28 +01:00
|
|
|
void UnifiedDiffEditorWidget::setDisplaySettings(const DisplaySettings &ds)
|
|
|
|
|
{
|
|
|
|
|
DisplaySettings settings = displaySettings();
|
|
|
|
|
settings.m_visualizeWhitespace = ds.m_visualizeWhitespace;
|
|
|
|
|
SelectableTextEditorWidget::setDisplaySettings(settings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setFontSettings(const FontSettings &fontSettings)
|
|
|
|
|
{
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.setFontSettings(fontSettings);
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor()
|
|
|
|
|
{
|
2016-07-13 15:55:18 +02:00
|
|
|
if (m_controller.m_ignoreCurrentIndexChange)
|
2014-02-13 16:43:28 +01:00
|
|
|
return;
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
|
|
|
|
|
m_controller.m_ignoreCurrentIndexChange = true;
|
2015-01-30 16:59:25 +01:00
|
|
|
emit currentDiffFileIndexChanged(fileIndexForBlockNumber(textCursor().blockNumber()));
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->button() == Qt::LeftButton && !(e->modifiers() & Qt::ShiftModifier)) {
|
|
|
|
|
QTextCursor cursor = cursorForPosition(e->pos());
|
|
|
|
|
jumpToOriginalFile(cursor);
|
|
|
|
|
e->accept();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SelectableTextEditorWidget::mouseDoubleClickEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::contextMenuEvent(QContextMenuEvent *e)
|
|
|
|
|
{
|
|
|
|
|
QPointer<QMenu> menu = createStandardContextMenu();
|
|
|
|
|
|
|
|
|
|
QTextCursor cursor = cursorForPosition(e->pos());
|
|
|
|
|
const int blockNumber = cursor.blockNumber();
|
|
|
|
|
|
|
|
|
|
addContextMenuActions(menu, fileIndexForBlockNumber(blockNumber),
|
|
|
|
|
chunkIndexForBlockNumber(blockNumber));
|
|
|
|
|
|
2015-02-02 07:17:50 +01:00
|
|
|
connect(this, &UnifiedDiffEditorWidget::destroyed, menu.data(), &QMenu::deleteLater);
|
2014-02-13 16:43:28 +01:00
|
|
|
menu->exec(e->globalPos());
|
|
|
|
|
delete menu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
|
|
|
|
|
int diffFileIndex,
|
|
|
|
|
int chunkIndex)
|
|
|
|
|
{
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.addCodePasterAction(menu);
|
|
|
|
|
m_controller.addApplyAction(menu, diffFileIndex, chunkIndex);
|
|
|
|
|
m_controller.addRevertAction(menu, diffFileIndex, chunkIndex);
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::clear(const QString &message)
|
|
|
|
|
{
|
|
|
|
|
m_leftLineNumberDigits = 1;
|
|
|
|
|
m_rightLineNumberDigits = 1;
|
|
|
|
|
m_leftLineNumbers.clear();
|
|
|
|
|
m_rightLineNumbers.clear();
|
|
|
|
|
m_fileInfo.clear();
|
|
|
|
|
m_chunkInfo.clear();
|
|
|
|
|
setSelections(QMap<int, QList<DiffSelection> >());
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
|
|
|
|
|
m_controller.m_ignoreCurrentIndexChange = true;
|
2014-02-13 16:43:28 +01:00
|
|
|
SelectableTextEditorWidget::clear();
|
2016-11-23 11:20:12 +01:00
|
|
|
m_controller.m_contextFileData.clear();
|
2014-02-13 16:43:28 +01:00
|
|
|
setPlainText(message);
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString UnifiedDiffEditorWidget::lineNumber(int blockNumber) const
|
|
|
|
|
{
|
|
|
|
|
QString lineNumberString;
|
|
|
|
|
|
|
|
|
|
const bool leftLineExists = m_leftLineNumbers.contains(blockNumber);
|
|
|
|
|
const bool rightLineExists = m_rightLineNumbers.contains(blockNumber);
|
|
|
|
|
|
|
|
|
|
if (leftLineExists || rightLineExists) {
|
|
|
|
|
const QString leftLine = leftLineExists
|
|
|
|
|
? QString::number(m_leftLineNumbers.value(blockNumber))
|
|
|
|
|
: QString();
|
|
|
|
|
lineNumberString += QString(m_leftLineNumberDigits - leftLine.count(),
|
|
|
|
|
QLatin1Char(' ')) + leftLine;
|
|
|
|
|
|
|
|
|
|
lineNumberString += QLatin1Char('|');
|
|
|
|
|
|
|
|
|
|
const QString rightLine = rightLineExists
|
|
|
|
|
? QString::number(m_rightLineNumbers.value(blockNumber))
|
|
|
|
|
: QString();
|
|
|
|
|
lineNumberString += QString(m_rightLineNumberDigits - rightLine.count(),
|
|
|
|
|
QLatin1Char(' ')) + rightLine;
|
|
|
|
|
}
|
|
|
|
|
return lineNumberString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int UnifiedDiffEditorWidget::lineNumberDigits() const
|
|
|
|
|
{
|
|
|
|
|
return m_leftLineNumberDigits + m_rightLineNumberDigits + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setLeftLineNumber(int blockNumber, int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
const QString lineNumberString = QString::number(lineNumber);
|
|
|
|
|
m_leftLineNumbers.insert(blockNumber, lineNumber);
|
|
|
|
|
m_leftLineNumberDigits = qMax(m_leftLineNumberDigits,
|
|
|
|
|
lineNumberString.count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setRightLineNumber(int blockNumber, int lineNumber)
|
|
|
|
|
{
|
|
|
|
|
const QString lineNumberString = QString::number(lineNumber);
|
|
|
|
|
m_rightLineNumbers.insert(blockNumber, lineNumber);
|
|
|
|
|
m_rightLineNumberDigits = qMax(m_rightLineNumberDigits,
|
|
|
|
|
lineNumberString.count());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setFileInfo(int blockNumber,
|
|
|
|
|
const DiffFileInfo &leftFileInfo,
|
|
|
|
|
const DiffFileInfo &rightFileInfo)
|
|
|
|
|
{
|
|
|
|
|
m_fileInfo[blockNumber] = qMakePair(leftFileInfo, rightFileInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setChunkIndex(int startBlockNumber,
|
|
|
|
|
int blockCount,
|
|
|
|
|
int chunkIndex)
|
|
|
|
|
{
|
|
|
|
|
m_chunkInfo.insert(startBlockNumber, qMakePair(blockCount, chunkIndex));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setDiff(const QList<FileData> &diffFileList,
|
|
|
|
|
const QString &workingDirectory)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(workingDirectory)
|
|
|
|
|
|
2016-11-23 11:20:12 +01:00
|
|
|
clear();
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_contextFileData = diffFileList;
|
2014-02-13 16:43:28 +01:00
|
|
|
showDiff();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
|
|
|
|
|
bool lastChunk,
|
|
|
|
|
int *blockNumber,
|
|
|
|
|
int *charNumber,
|
|
|
|
|
QMap<int, QList<DiffSelection> > *selections)
|
|
|
|
|
{
|
|
|
|
|
if (chunkData.contextChunk)
|
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
|
|
QString diffText;
|
|
|
|
|
int leftLineCount = 0;
|
|
|
|
|
int rightLineCount = 0;
|
|
|
|
|
int blockCount = 0;
|
|
|
|
|
int charCount = 0;
|
|
|
|
|
QList<TextLineData> leftBuffer, rightBuffer;
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
(*selections)[*blockNumber].append(DiffSelection(&m_controller.m_chunkLineFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
|
2014-07-09 12:37:47 +02:00
|
|
|
int lastEqualRow = -1;
|
|
|
|
|
if (lastChunk) {
|
|
|
|
|
for (int i = chunkData.rows.count(); i > 0; i--) {
|
|
|
|
|
if (chunkData.rows.at(i - 1).equal) {
|
|
|
|
|
if (i != chunkData.rows.count())
|
|
|
|
|
lastEqualRow = i - 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 16:43:28 +01:00
|
|
|
for (int i = 0; i <= chunkData.rows.count(); i++) {
|
|
|
|
|
const RowData &rowData = i < chunkData.rows.count()
|
|
|
|
|
? chunkData.rows.at(i)
|
|
|
|
|
: RowData(TextLineData(TextLineData::Separator)); // dummy,
|
|
|
|
|
// ensure we process buffers to the end.
|
|
|
|
|
// rowData will be equal
|
2014-07-09 12:37:47 +02:00
|
|
|
if (rowData.equal && i != lastEqualRow) {
|
2014-02-13 16:43:28 +01:00
|
|
|
if (leftBuffer.count()) {
|
|
|
|
|
for (int j = 0; j < leftBuffer.count(); j++) {
|
|
|
|
|
const TextLineData &lineData = leftBuffer.at(j);
|
|
|
|
|
const QString line = DiffUtils::makePatchLine(
|
|
|
|
|
QLatin1Char('-'),
|
|
|
|
|
lineData.text,
|
|
|
|
|
lastChunk,
|
|
|
|
|
i == chunkData.rows.count()
|
|
|
|
|
&& j == leftBuffer.count() - 1);
|
|
|
|
|
|
|
|
|
|
const int blockDelta = line.count(QLatin1Char('\n')); // no new line
|
|
|
|
|
// could have been added
|
|
|
|
|
for (int k = 0; k < blockDelta; k++)
|
2016-07-13 15:55:18 +02:00
|
|
|
(*selections)[*blockNumber + blockCount + 1 + k].append(&m_controller.m_leftLineFormat);
|
2017-06-27 11:59:11 +02:00
|
|
|
|
|
|
|
|
for (auto it = lineData.changedPositions.cbegin(),
|
|
|
|
|
end = lineData.changedPositions.cend(); it != end; ++it) {
|
|
|
|
|
const int startPos = it.key() < 0
|
|
|
|
|
? 1 : it.key() + 1;
|
|
|
|
|
const int endPos = it.value() < 0
|
|
|
|
|
? it.value() : it.value() + 1;
|
2014-02-13 16:43:28 +01:00
|
|
|
(*selections)[*blockNumber + blockCount + 1].append(
|
2016-07-13 15:55:18 +02:00
|
|
|
DiffSelection(startPos, endPos, &m_controller.m_leftCharFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!line.isEmpty()) {
|
|
|
|
|
setLeftLineNumber(*blockNumber + blockCount + 1,
|
|
|
|
|
chunkData.leftStartingLineNumber
|
|
|
|
|
+ leftLineCount + 1);
|
|
|
|
|
blockCount += blockDelta;
|
|
|
|
|
++leftLineCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffText += line;
|
|
|
|
|
|
|
|
|
|
charCount += line.count();
|
|
|
|
|
}
|
|
|
|
|
leftBuffer.clear();
|
|
|
|
|
}
|
|
|
|
|
if (rightBuffer.count()) {
|
|
|
|
|
for (int j = 0; j < rightBuffer.count(); j++) {
|
|
|
|
|
const TextLineData &lineData = rightBuffer.at(j);
|
|
|
|
|
const QString line = DiffUtils::makePatchLine(
|
|
|
|
|
QLatin1Char('+'),
|
|
|
|
|
lineData.text,
|
|
|
|
|
lastChunk,
|
|
|
|
|
i == chunkData.rows.count()
|
|
|
|
|
&& j == rightBuffer.count() - 1);
|
|
|
|
|
|
|
|
|
|
const int blockDelta = line.count(QLatin1Char('\n')); // no new line
|
|
|
|
|
// could have been added
|
|
|
|
|
|
|
|
|
|
for (int k = 0; k < blockDelta; k++)
|
2016-07-13 15:55:18 +02:00
|
|
|
(*selections)[*blockNumber + blockCount + 1 + k].append(&m_controller.m_rightLineFormat);
|
2017-06-27 11:59:11 +02:00
|
|
|
|
|
|
|
|
for (auto it = lineData.changedPositions.cbegin(),
|
|
|
|
|
end = lineData.changedPositions.cend(); it != end; ++it) {
|
|
|
|
|
const int startPos = it.key() < 0
|
|
|
|
|
? 1 : it.key() + 1;
|
|
|
|
|
const int endPos = it.value() < 0
|
|
|
|
|
? it.value() : it.value() + 1;
|
2014-02-13 16:43:28 +01:00
|
|
|
(*selections)[*blockNumber + blockCount + 1].append
|
2016-07-13 15:55:18 +02:00
|
|
|
(DiffSelection(startPos, endPos, &m_controller.m_rightCharFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!line.isEmpty()) {
|
|
|
|
|
setRightLineNumber(*blockNumber + blockCount + 1,
|
|
|
|
|
chunkData.rightStartingLineNumber
|
|
|
|
|
+ rightLineCount + 1);
|
|
|
|
|
blockCount += blockDelta;
|
|
|
|
|
++rightLineCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffText += line;
|
|
|
|
|
|
|
|
|
|
charCount += line.count();
|
|
|
|
|
}
|
|
|
|
|
rightBuffer.clear();
|
|
|
|
|
}
|
|
|
|
|
if (i < chunkData.rows.count()) {
|
|
|
|
|
const QString line = DiffUtils::makePatchLine(QLatin1Char(' '),
|
|
|
|
|
rowData.rightLine.text,
|
|
|
|
|
lastChunk,
|
|
|
|
|
i == chunkData.rows.count() - 1);
|
|
|
|
|
|
|
|
|
|
if (!line.isEmpty()) {
|
|
|
|
|
setLeftLineNumber(*blockNumber + blockCount + 1,
|
|
|
|
|
chunkData.leftStartingLineNumber
|
|
|
|
|
+ leftLineCount + 1);
|
|
|
|
|
setRightLineNumber(*blockNumber + blockCount + 1,
|
|
|
|
|
chunkData.rightStartingLineNumber
|
|
|
|
|
+ rightLineCount + 1);
|
|
|
|
|
blockCount += line.count(QLatin1Char('\n'));
|
|
|
|
|
++leftLineCount;
|
|
|
|
|
++rightLineCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffText += line;
|
|
|
|
|
|
|
|
|
|
charCount += line.count();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
|
|
|
|
leftBuffer.append(rowData.leftLine);
|
|
|
|
|
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
|
|
|
|
rightBuffer.append(rowData.rightLine);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QString chunkLine = QLatin1String("@@ -")
|
|
|
|
|
+ QString::number(chunkData.leftStartingLineNumber + 1)
|
|
|
|
|
+ QLatin1Char(',')
|
|
|
|
|
+ QString::number(leftLineCount)
|
|
|
|
|
+ QLatin1String(" +")
|
|
|
|
|
+ QString::number(chunkData.rightStartingLineNumber+ 1)
|
|
|
|
|
+ QLatin1Char(',')
|
|
|
|
|
+ QString::number(rightLineCount)
|
2014-08-14 17:20:42 +02:00
|
|
|
+ QLatin1String(" @@")
|
|
|
|
|
+ chunkData.contextInfo
|
|
|
|
|
+ QLatin1Char('\n');
|
2014-02-13 16:43:28 +01:00
|
|
|
|
|
|
|
|
diffText.prepend(chunkLine);
|
|
|
|
|
|
|
|
|
|
*blockNumber += blockCount + 1; // +1 for chunk line
|
|
|
|
|
*charNumber += charCount + chunkLine.count();
|
|
|
|
|
return diffText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::showDiff()
|
|
|
|
|
{
|
|
|
|
|
QString diffText;
|
|
|
|
|
|
|
|
|
|
int blockNumber = 0;
|
|
|
|
|
int charNumber = 0;
|
|
|
|
|
|
|
|
|
|
QMap<int, QList<DiffSelection> > selections;
|
|
|
|
|
|
2017-06-27 11:59:11 +02:00
|
|
|
for (const FileData &fileData : m_controller.m_contextFileData) {
|
2014-02-13 16:43:28 +01:00
|
|
|
const QString leftFileInfo = QLatin1String("--- ")
|
|
|
|
|
+ fileData.leftFileInfo.fileName + QLatin1Char('\n');
|
|
|
|
|
const QString rightFileInfo = QLatin1String("+++ ")
|
|
|
|
|
+ fileData.rightFileInfo.fileName + QLatin1Char('\n');
|
|
|
|
|
setFileInfo(blockNumber, fileData.leftFileInfo, fileData.rightFileInfo);
|
2016-07-13 15:55:18 +02:00
|
|
|
selections[blockNumber].append(DiffSelection(&m_controller.m_fileLineFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
blockNumber++;
|
2016-07-13 15:55:18 +02:00
|
|
|
selections[blockNumber].append(DiffSelection(&m_controller.m_fileLineFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
blockNumber++;
|
|
|
|
|
|
|
|
|
|
diffText += leftFileInfo;
|
|
|
|
|
diffText += rightFileInfo;
|
|
|
|
|
charNumber += leftFileInfo.count() + rightFileInfo.count();
|
|
|
|
|
|
|
|
|
|
if (fileData.binaryFiles) {
|
2016-07-13 15:55:18 +02:00
|
|
|
selections[blockNumber].append(DiffSelection(&m_controller.m_chunkLineFormat));
|
2014-02-13 16:43:28 +01:00
|
|
|
blockNumber++;
|
|
|
|
|
const QString binaryLine = QLatin1String("Binary files ")
|
|
|
|
|
+ fileData.leftFileInfo.fileName
|
|
|
|
|
+ QLatin1String(" and ")
|
|
|
|
|
+ fileData.rightFileInfo.fileName
|
|
|
|
|
+ QLatin1String(" differ\n");
|
|
|
|
|
diffText += binaryLine;
|
|
|
|
|
charNumber += binaryLine.count();
|
|
|
|
|
} else {
|
|
|
|
|
for (int j = 0; j < fileData.chunks.count(); j++) {
|
|
|
|
|
const int oldBlockNumber = blockNumber;
|
|
|
|
|
diffText += showChunk(fileData.chunks.at(j),
|
|
|
|
|
(j == fileData.chunks.count() - 1)
|
|
|
|
|
&& fileData.lastChunkAtTheEndOfFile,
|
|
|
|
|
&blockNumber,
|
|
|
|
|
&charNumber,
|
|
|
|
|
&selections);
|
|
|
|
|
if (!fileData.chunks.at(j).contextChunk)
|
|
|
|
|
setChunkIndex(oldBlockNumber, blockNumber - oldBlockNumber, j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 16:59:25 +01:00
|
|
|
if (diffText.isEmpty()) {
|
|
|
|
|
setPlainText(tr("No difference."));
|
2014-02-13 16:43:28 +01:00
|
|
|
return;
|
2015-01-30 16:59:25 +01:00
|
|
|
}
|
2014-02-13 16:43:28 +01:00
|
|
|
|
|
|
|
|
diffText.replace(QLatin1Char('\r'), QLatin1Char(' '));
|
2016-07-13 15:55:18 +02:00
|
|
|
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
|
|
|
|
|
m_controller.m_ignoreCurrentIndexChange = true;
|
2014-02-13 16:43:28 +01:00
|
|
|
setPlainText(diffText);
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
|
2014-02-13 16:43:28 +01:00
|
|
|
|
|
|
|
|
setSelections(selections);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int UnifiedDiffEditorWidget::blockNumberForFileIndex(int fileIndex) const
|
|
|
|
|
{
|
|
|
|
|
if (fileIndex < 0 || fileIndex >= m_fileInfo.count())
|
|
|
|
|
return -1;
|
|
|
|
|
|
2017-06-27 11:59:11 +02:00
|
|
|
return (m_fileInfo.constBegin() + fileIndex).key();
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int UnifiedDiffEditorWidget::fileIndexForBlockNumber(int blockNumber) const
|
|
|
|
|
{
|
|
|
|
|
int i = -1;
|
2017-06-27 11:59:11 +02:00
|
|
|
for (auto it = m_fileInfo.cbegin(), end = m_fileInfo.cend(); it != end; ++it, ++i) {
|
2014-02-13 16:43:28 +01:00
|
|
|
if (it.key() > blockNumber)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-27 11:59:11 +02:00
|
|
|
|
2014-02-13 16:43:28 +01:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int UnifiedDiffEditorWidget::chunkIndexForBlockNumber(int blockNumber) const
|
|
|
|
|
{
|
|
|
|
|
if (m_chunkInfo.isEmpty())
|
|
|
|
|
return -1;
|
|
|
|
|
|
2017-06-27 11:59:11 +02:00
|
|
|
auto it = m_chunkInfo.upperBound(blockNumber);
|
2014-02-13 16:43:28 +01:00
|
|
|
if (it == m_chunkInfo.constBegin())
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
--it;
|
|
|
|
|
|
|
|
|
|
if (blockNumber < it.key() + it.value().first)
|
|
|
|
|
return it.value().second;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::jumpToOriginalFile(const QTextCursor &cursor)
|
|
|
|
|
{
|
|
|
|
|
if (m_fileInfo.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const int blockNumber = cursor.blockNumber();
|
2014-07-04 10:51:38 +02:00
|
|
|
const int fileIndex = fileIndexForBlockNumber(blockNumber);
|
|
|
|
|
if (fileIndex < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
const FileData fileData = m_controller.m_contextFileData.at(fileIndex);
|
2014-07-04 10:51:38 +02:00
|
|
|
const QString leftFileName = fileData.leftFileInfo.fileName;
|
|
|
|
|
const QString rightFileName = fileData.rightFileInfo.fileName;
|
|
|
|
|
|
2014-02-13 16:43:28 +01:00
|
|
|
const int columnNumber = cursor.positionInBlock() - 1; // -1 for the first character in line
|
|
|
|
|
|
|
|
|
|
const int rightLineNumber = m_rightLineNumbers.value(blockNumber, -1);
|
|
|
|
|
if (rightLineNumber >= 0) {
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.jumpToOriginalFile(rightFileName, rightLineNumber, columnNumber);
|
2014-02-13 16:43:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int leftLineNumber = m_leftLineNumbers.value(blockNumber, -1);
|
|
|
|
|
if (leftLineNumber >= 0) {
|
2014-07-04 10:51:38 +02:00
|
|
|
if (leftFileName == rightFileName) {
|
2017-06-27 11:59:11 +02:00
|
|
|
for (const ChunkData &chunkData : fileData.chunks) {
|
2014-07-04 10:51:38 +02:00
|
|
|
|
|
|
|
|
int newLeftLineNumber = chunkData.leftStartingLineNumber;
|
|
|
|
|
int newRightLineNumber = chunkData.rightStartingLineNumber;
|
|
|
|
|
|
2017-06-27 11:59:11 +02:00
|
|
|
for (const RowData &rowData : chunkData.rows) {
|
2014-07-04 10:51:38 +02:00
|
|
|
if (rowData.leftLine.textLineType == TextLineData::TextLine)
|
|
|
|
|
newLeftLineNumber++;
|
|
|
|
|
if (rowData.rightLine.textLineType == TextLineData::TextLine)
|
|
|
|
|
newRightLineNumber++;
|
|
|
|
|
if (newLeftLineNumber == leftLineNumber) {
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.jumpToOriginalFile(leftFileName, newRightLineNumber, 0);
|
2014-07-04 10:51:38 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.jumpToOriginalFile(leftFileName, leftLineNumber, columnNumber);
|
2014-07-04 10:51:38 +02:00
|
|
|
}
|
2014-02-13 16:43:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnifiedDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
|
|
|
|
|
{
|
2016-07-13 15:55:18 +02:00
|
|
|
if (m_controller.m_ignoreCurrentIndexChange)
|
2014-02-13 16:43:28 +01:00
|
|
|
return;
|
|
|
|
|
|
2016-07-13 15:55:18 +02:00
|
|
|
const bool oldIgnore = m_controller.m_ignoreCurrentIndexChange;
|
|
|
|
|
m_controller.m_ignoreCurrentIndexChange = true;
|
2014-02-13 16:43:28 +01:00
|
|
|
const int blockNumber = blockNumberForFileIndex(diffFileIndex);
|
|
|
|
|
|
|
|
|
|
QTextBlock block = document()->findBlockByNumber(blockNumber);
|
|
|
|
|
QTextCursor cursor = textCursor();
|
|
|
|
|
cursor.setPosition(block.position());
|
|
|
|
|
setTextCursor(cursor);
|
2015-04-16 15:31:25 +02:00
|
|
|
verticalScrollBar()->setValue(blockNumber);
|
2016-07-13 15:55:18 +02:00
|
|
|
m_controller.m_ignoreCurrentIndexChange = oldIgnore;
|
2014-02-13 16:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 14:51:44 +01:00
|
|
|
} // namespace Internal
|
2014-02-13 16:43:28 +01:00
|
|
|
} // namespace DiffEditor
|