VCS: Handle code folding in diff view

Allow to do codefolding on files and hunks in the diff editor
This commit is contained in:
Tobias Hunger
2010-11-21 10:15:12 +01:00
parent f84c228568
commit 8808f0fa2d
4 changed files with 90 additions and 11 deletions

View File

@@ -114,7 +114,7 @@ QString GitEditor::changeUnderCursor(const QTextCursor &c) const
VCSBase::DiffHighlighter *GitEditor::createDiffHighlighter() const VCSBase::DiffHighlighter *GitEditor::createDiffHighlighter() const
{ {
const QRegExp filePattern(QLatin1String("^[-+][-+][-+] [ab].*")); const QRegExp filePattern(QLatin1String("^(diff --git a/|index |[+-][+-][+-] [ab]).*$"));
return new VCSBase::DiffHighlighter(filePattern); return new VCSBase::DiffHighlighter(filePattern);
} }

View File

@@ -29,6 +29,8 @@
#include "diffhighlighter.h" #include "diffhighlighter.h"
#include <texteditor/basetextdocumentlayout.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
@@ -36,7 +38,12 @@
#include <QtCore/QRegExp> #include <QtCore/QRegExp>
#include <QtGui/QBrush> #include <QtGui/QBrush>
static const int BASE_LEVEL = 0;
static const int FILE_LEVEL = 1;
static const int LOCATION_LEVEL = 2;
namespace VCSBase { namespace VCSBase {
namespace Internal {
// Formats used by DiffHighlighter // Formats used by DiffHighlighter
enum DiffFormats { enum DiffFormats {
@@ -48,8 +55,16 @@ enum DiffFormats {
NumDiffFormats NumDiffFormats
}; };
enum FoldingState {
StartOfFile,
Header,
File,
Location
};
// --- DiffHighlighterPrivate // --- DiffHighlighterPrivate
struct DiffHighlighterPrivate { class DiffHighlighterPrivate {
public:
DiffHighlighterPrivate(const QRegExp &filePattern); DiffHighlighterPrivate(const QRegExp &filePattern);
inline DiffFormats analyzeLine(const QString &block) const; inline DiffFormats analyzeLine(const QString &block) const;
@@ -59,13 +74,16 @@ struct DiffHighlighterPrivate {
const QChar m_diffOutIndicator; const QChar m_diffOutIndicator;
QTextCharFormat m_formats[NumDiffFormats]; QTextCharFormat m_formats[NumDiffFormats];
QTextCharFormat m_addedTrailingWhiteSpaceFormat; QTextCharFormat m_addedTrailingWhiteSpaceFormat;
FoldingState m_foldingState;
}; };
DiffHighlighterPrivate::DiffHighlighterPrivate(const QRegExp &filePattern) : DiffHighlighterPrivate::DiffHighlighterPrivate(const QRegExp &filePattern) :
m_filePattern(filePattern), m_filePattern(filePattern),
m_locationIndicator(QLatin1String("@@")), m_locationIndicator(QLatin1String("@@")),
m_diffInIndicator(QLatin1Char('+')), m_diffInIndicator(QLatin1Char('+')),
m_diffOutIndicator(QLatin1Char('-')) m_diffOutIndicator(QLatin1Char('-')),
m_foldingState(StartOfFile)
{ {
QTC_ASSERT(filePattern.isValid(), /**/); QTC_ASSERT(filePattern.isValid(), /**/);
} }
@@ -85,11 +103,13 @@ DiffFormats DiffHighlighterPrivate::analyzeLine(const QString &text) const
return DiffTextFormat; return DiffTextFormat;
} }
} // namespace Internal
// --- DiffHighlighter // --- DiffHighlighter
DiffHighlighter::DiffHighlighter(const QRegExp &filePattern, DiffHighlighter::DiffHighlighter(const QRegExp &filePattern,
QTextDocument *document) : QTextDocument *document) :
TextEditor::SyntaxHighlighter(document), TextEditor::SyntaxHighlighter(document),
m_d(new DiffHighlighterPrivate(filePattern)) m_d(new Internal::DiffHighlighterPrivate(filePattern))
{ {
} }
@@ -113,11 +133,11 @@ void DiffHighlighter::highlightBlock(const QString &text)
return; return;
const int length = text.length(); const int length = text.length();
const DiffFormats format = m_d->analyzeLine(text); const Internal::DiffFormats format = m_d->analyzeLine(text);
switch (format) { switch (format) {
case DiffTextFormat: case Internal::DiffTextFormat:
break; break;
case DiffInFormat: { case Internal::DiffInFormat: {
// Mark trailing whitespace. // Mark trailing whitespace.
const int trimmedLen = trimmedLength(text); const int trimmedLen = trimmedLength(text);
setFormat(0, trimmedLen, m_d->m_formats[format]); setFormat(0, trimmedLen, m_d->m_formats[format]);
@@ -129,6 +149,61 @@ void DiffHighlighter::highlightBlock(const QString &text)
setFormat(0, length, m_d->m_formats[format]); setFormat(0, length, m_d->m_formats[format]);
break; break;
} }
// codefolding:
TextEditor::TextBlockUserData *data =
TextEditor::BaseTextDocumentLayout::userData(currentBlock());
Q_ASSERT(data);
if (!TextEditor::BaseTextDocumentLayout::testUserData(currentBlock().previous()))
m_d->m_foldingState = Internal::StartOfFile;
switch (m_d->m_foldingState) {
case Internal::StartOfFile:
case Internal::Header:
switch (format) {
case Internal::DiffFileFormat:
m_d->m_foldingState = Internal::File;
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), BASE_LEVEL);
break;
case Internal::DiffLocationFormat:
m_d->m_foldingState = Internal::Location;
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), FILE_LEVEL);
break;
default:
m_d->m_foldingState = Internal::Header;
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), BASE_LEVEL);
break;
}
break;
case Internal::File:
switch (format) {
case Internal::DiffFileFormat:
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), FILE_LEVEL);
break;
case Internal::DiffLocationFormat:
m_d->m_foldingState = Internal::Location;
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), FILE_LEVEL);
break;
default:
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), FILE_LEVEL);
break;
}
break;
case Internal::Location:
switch (format) {
case Internal::DiffFileFormat:
m_d->m_foldingState = Internal::File;
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), BASE_LEVEL);
break;
case Internal::DiffLocationFormat:
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), FILE_LEVEL);
break;
default:
TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), LOCATION_LEVEL);
break;
}
break;
}
} }
static inline QTextCharFormat invertedColorFormat(const QTextCharFormat &in) static inline QTextCharFormat invertedColorFormat(const QTextCharFormat &in)
@@ -141,10 +216,11 @@ static inline QTextCharFormat invertedColorFormat(const QTextCharFormat &in)
void DiffHighlighter::setFormats(const QVector<QTextCharFormat> &s) void DiffHighlighter::setFormats(const QVector<QTextCharFormat> &s)
{ {
if (s.size() == NumDiffFormats) { if (s.size() == Internal::NumDiffFormats) {
qCopy(s.constBegin(), s.constEnd(), m_d->m_formats); qCopy(s.constBegin(), s.constEnd(), m_d->m_formats);
// Display trailing blanks with colors swapped // Display trailing blanks with colors swapped
m_d->m_addedTrailingWhiteSpaceFormat = invertedColorFormat(m_d->m_formats[DiffInFormat]); m_d->m_addedTrailingWhiteSpaceFormat =
invertedColorFormat(m_d->m_formats[Internal::DiffInFormat]);
} else { } else {
qWarning("%s: insufficient setting size: %d", Q_FUNC_INFO, s.size()); qWarning("%s: insufficient setting size: %d", Q_FUNC_INFO, s.size());
} }

View File

@@ -48,7 +48,9 @@ namespace TextEditor {
namespace VCSBase { namespace VCSBase {
struct DiffHighlighterPrivate; namespace Internal {
class DiffHighlighterPrivate;
} // namespace Internal
/* A highlighter for diffs. Parametrizable by the file indicator, /* A highlighter for diffs. Parametrizable by the file indicator,
* which is for example '^====' in case of p4: * which is for example '^====' in case of p4:
@@ -81,7 +83,7 @@ public:
QRegExp filePattern() const; QRegExp filePattern() const;
private: private:
DiffHighlighterPrivate *m_d; Internal::DiffHighlighterPrivate *m_d;
}; };
} // namespace VCSBase } // namespace VCSBase

View File

@@ -201,6 +201,7 @@ void VCSBaseEditor::init()
break; break;
case DiffOutput: { case DiffOutput: {
DiffHighlighter *dh = createDiffHighlighter(); DiffHighlighter *dh = createDiffHighlighter();
setCodeFoldingSupported(true);
baseTextDocument()->setSyntaxHighlighter(dh); baseTextDocument()->setSyntaxHighlighter(dh);
d->m_diffFilePattern = dh->filePattern(); d->m_diffFilePattern = dh->filePattern();
connect(this, SIGNAL(textChanged()), this, SLOT(slotPopulateDiffBrowser())); connect(this, SIGNAL(textChanged()), this, SLOT(slotPopulateDiffBrowser()));