Generic highlighter: Code folding support.

This commit is contained in:
Leandro Melo
2010-06-18 16:30:56 +02:00
parent 81955e045e
commit 20eeca15ce
11 changed files with 235 additions and 79 deletions

View File

@@ -53,7 +53,8 @@ const Highlighter::KateFormatMap Highlighter::m_kateFormats;
Highlighter::Highlighter(QTextDocument *parent) : Highlighter::Highlighter(QTextDocument *parent) :
QSyntaxHighlighter(parent), QSyntaxHighlighter(parent),
m_persistentStatesCounter(PersistentsStart), m_regionDepth(0),
m_persistentObservableStatesCounter(PersistentsStart),
m_dynamicContextsCounter(0), m_dynamicContextsCounter(0),
m_isBroken(false) m_isBroken(false)
{} {}
@@ -61,7 +62,7 @@ Highlighter::Highlighter(QTextDocument *parent) :
Highlighter::~Highlighter() Highlighter::~Highlighter()
{} {}
Highlighter::BlockData::BlockData() Highlighter::BlockData::BlockData() : m_foldingIndentDelta(0)
{} {}
Highlighter::BlockData::~BlockData() Highlighter::BlockData::~BlockData()
@@ -93,13 +94,15 @@ void Highlighter::configureFormat(TextFormatId id, const QTextCharFormat &format
void Highlighter::setDefaultContext(const QSharedPointer<Context> &defaultContext) void Highlighter::setDefaultContext(const QSharedPointer<Context> &defaultContext)
{ {
m_defaultContext = defaultContext; m_defaultContext = defaultContext;
m_persistentStates.insert(m_defaultContext->name(), Default); m_persistentObservableStates.insert(m_defaultContext->name(), Default);
} }
void Highlighter::highlightBlock(const QString &text) void Highlighter::highlightBlock(const QString &text)
{ {
if (!m_defaultContext.isNull() && !m_isBroken) { if (!m_defaultContext.isNull() && !m_isBroken) {
try { try {
if (!currentBlockUserData())
initializeBlockData();
setupDataForBlock(text); setupDataForBlock(text);
handleContextChange(m_currentContext->lineBeginContext(), handleContextChange(m_currentContext->lineBeginContext(),
@@ -114,6 +117,12 @@ void Highlighter::highlightBlock(const QString &text)
m_currentContext->definition(), m_currentContext->definition(),
false); false);
m_contexts.clear(); m_contexts.clear();
applyFolding();
// Takes into the account any change that might have affected the region depth since
// the last time the state was set.
setCurrentBlockState(computeState(extractObservableState(currentBlockState())));
} catch (const HighlighterException &) { } catch (const HighlighterException &) {
m_isBroken = true; m_isBroken = true;
} }
@@ -124,60 +133,70 @@ void Highlighter::highlightBlock(const QString &text)
void Highlighter::setupDataForBlock(const QString &text) void Highlighter::setupDataForBlock(const QString &text)
{ {
if (currentBlockState() == WillContinue) if (extractObservableState(currentBlockState()) == WillContinue)
analyseConsistencyOfWillContinueBlock(text); analyseConsistencyOfWillContinueBlock(text);
if (previousBlockState() == Default || previousBlockState() == -1) if (previousBlockState() == -1) {
m_regionDepth = 0;
setupDefault(); setupDefault();
else if (previousBlockState() == WillContinue) } else {
setupFromWillContinue(); m_regionDepth = extractRegionDepth(previousBlockState());
else if (previousBlockState() == Continued) const int observablePreviousState = extractObservableState(previousBlockState());
setupFromContinued(); if (observablePreviousState == Default)
else setupDefault();
setupFromPersistent(); else if (observablePreviousState == WillContinue)
setupFromWillContinue();
else if (observablePreviousState == Continued)
setupFromContinued();
else
setupFromPersistent();
setCurrentContext(); blockData(currentBlockUserData())->m_foldingRegions =
blockData(currentBlock().previous().userData())->m_foldingRegions;
}
assignCurrentContext();
} }
void Highlighter::setupDefault() void Highlighter::setupDefault()
{ {
m_contexts.push_back(m_defaultContext); m_contexts.push_back(m_defaultContext);
setCurrentBlockState(Default); setCurrentBlockState(computeState(Default));
} }
void Highlighter::setupFromWillContinue() void Highlighter::setupFromWillContinue()
{ {
BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); BlockData *previousData = blockData(currentBlock().previous().userData());
m_contexts.push_back(previousData->m_contextToContinue); m_contexts.push_back(previousData->m_contextToContinue);
if (!currentBlockUserData()) { BlockData *data = blockData(currentBlock().userData());
BlockData *data = initializeBlockData(); data->m_originalObservableState = previousData->m_originalObservableState;
data->m_originalState = previousData->m_originalState;
}
if (currentBlockState() == Default || currentBlockState() == -1) if (currentBlockState() == -1 || extractObservableState(currentBlockState()) == Default)
setCurrentBlockState(Continued); setCurrentBlockState(computeState(Continued));
} }
void Highlighter::setupFromContinued() void Highlighter::setupFromContinued()
{ {
BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); BlockData *previousData = blockData(currentBlock().previous().userData());
Q_ASSERT(previousData->m_originalState != WillContinue && Q_ASSERT(previousData->m_originalObservableState != WillContinue &&
previousData->m_originalState != Continued); previousData->m_originalObservableState != Continued);
if (previousData->m_originalState == Default || previousData->m_originalState == -1) if (previousData->m_originalObservableState == Default ||
previousData->m_originalObservableState == -1) {
m_contexts.push_back(m_defaultContext); m_contexts.push_back(m_defaultContext);
else } else {
pushContextSequence(previousData->m_originalState); pushContextSequence(previousData->m_originalObservableState);
}
setCurrentBlockState(previousData->m_originalState); setCurrentBlockState(computeState(previousData->m_originalObservableState));
} }
void Highlighter::setupFromPersistent() void Highlighter::setupFromPersistent()
{ {
pushContextSequence(previousBlockState()); pushContextSequence(extractObservableState(previousBlockState()));
setCurrentBlockState(previousBlockState()); setCurrentBlockState(previousBlockState());
} }
@@ -197,11 +216,29 @@ void Highlighter::iterateThroughRules(const QString &text,
RuleIterator endIt = rules.end(); RuleIterator endIt = rules.end();
while (it != endIt && progress->offset() < length) { while (it != endIt && progress->offset() < length) {
int startOffset = progress->offset(); int startOffset = progress->offset();
const QSharedPointer<Rule> &rule = *it; const QSharedPointer<Rule> &rule = *it;
if (rule->matchSucceed(text, length, progress)) { if (rule->matchSucceed(text, length, progress)) {
atLeastOneMatch = true; atLeastOneMatch = true;
// Code folding.
if (!rule->beginRegion().isEmpty()) {
blockData(currentBlockUserData())->m_foldingRegions.push(rule->beginRegion());
++m_regionDepth;
if (progress->isOpeningBraceMatchAtFirstNonSpace())
++blockData(currentBlockUserData())->m_foldingIndentDelta;
}
if (!rule->endRegion().isEmpty()) {
QStack<QString> *currentRegions =
&blockData(currentBlockUserData())->m_foldingRegions;
if (!currentRegions->isEmpty() && rule->endRegion() == currentRegions->top()) {
currentRegions->pop();
--m_regionDepth;
if (progress->isClosingBraceMatchAtNonEnd())
--blockData(currentBlockUserData())->m_foldingIndentDelta;
}
}
progress->clearBracesMatches();
if (progress->isWillContinueLine()) { if (progress->isWillContinueLine()) {
createWillContinueBlock(); createWillContinueBlock();
progress->setWillContinueLine(false); progress->setWillContinueLine(false);
@@ -263,20 +300,22 @@ bool Highlighter::contextChangeRequired(const QString &contextName) const
void Highlighter::changeContext(const QString &contextName, void Highlighter::changeContext(const QString &contextName,
const QSharedPointer<HighlightDefinition> &definition, const QSharedPointer<HighlightDefinition> &definition,
const bool setCurrent) const bool assignCurrent)
{ {
if (contextName.startsWith(kPop)) { if (contextName.startsWith(kPop)) {
QStringList list = contextName.split(kHash, QString::SkipEmptyParts); QStringList list = contextName.split(kHash, QString::SkipEmptyParts);
for (int i = 0; i < list.size(); ++i) for (int i = 0; i < list.size(); ++i)
m_contexts.pop_back(); m_contexts.pop_back();
if (currentBlockState() >= PersistentsStart) { if (extractObservableState(currentBlockState()) >= PersistentsStart) {
// One or more contexts were popped during during a persistent state. // One or more contexts were popped during during a persistent state.
const QString &currentSequence = currentContextSequence(); const QString &currentSequence = currentContextSequence();
if (m_persistentStates.contains(currentSequence)) if (m_persistentObservableStates.contains(currentSequence))
setCurrentBlockState(m_persistentStates.value(currentSequence)); setCurrentBlockState(
computeState(m_persistentObservableStates.value(currentSequence)));
else else
setCurrentBlockState(m_leadingStates.value(currentSequence)); setCurrentBlockState(
computeState(m_leadingObservableStates.value(currentSequence)));
} }
} else { } else {
const QSharedPointer<Context> &context = definition->context(contextName); const QSharedPointer<Context> &context = definition->context(contextName);
@@ -287,19 +326,20 @@ void Highlighter::changeContext(const QString &contextName,
m_contexts.push_back(context); m_contexts.push_back(context);
if (m_contexts.back()->lineEndContext() == kStay || if (m_contexts.back()->lineEndContext() == kStay ||
currentBlockState() >= PersistentsStart) { extractObservableState(currentBlockState()) >= PersistentsStart) {
const QString &currentSequence = currentContextSequence(); const QString &currentSequence = currentContextSequence();
mapLeadingSequence(currentSequence); mapLeadingSequence(currentSequence);
if (m_contexts.back()->lineEndContext() == kStay) { if (m_contexts.back()->lineEndContext() == kStay) {
// A persistent context was pushed. // A persistent context was pushed.
mapPersistentSequence(currentSequence); mapPersistentSequence(currentSequence);
setCurrentBlockState(m_persistentStates.value(currentSequence)); setCurrentBlockState(
computeState(m_persistentObservableStates.value(currentSequence)));
} }
} }
} }
if (setCurrent) if (assignCurrent)
setCurrentContext(); assignCurrentContext();
} }
void Highlighter::handleContextChange(const QString &contextName, void Highlighter::handleContextChange(const QString &contextName,
@@ -373,50 +413,49 @@ void Highlighter::applyVisualWhitespaceFormat(const QString &text)
void Highlighter::createWillContinueBlock() void Highlighter::createWillContinueBlock()
{ {
if (!currentBlockUserData()) BlockData *data = blockData(currentBlockUserData());
initializeBlockData(); const int currentObservableState = extractObservableState(currentBlockState());
if (currentObservableState == Continued) {
BlockData *data = static_cast<BlockData *>(currentBlockUserData()); BlockData *previousData = blockData(currentBlock().previous().userData());
if (currentBlockState() == Continued) { data->m_originalObservableState = previousData->m_originalObservableState;
BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); } else if (currentObservableState != WillContinue) {
data->m_originalState = previousData->m_originalState; data->m_originalObservableState = currentObservableState;
} else if (currentBlockState() != WillContinue) {
data->m_originalState = currentBlockState();
} }
data->m_contextToContinue = m_currentContext; data->m_contextToContinue = m_currentContext;
setCurrentBlockState(WillContinue); setCurrentBlockState(computeState(WillContinue));
} }
void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text) void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text)
{ {
if (currentBlock().next().isValid() && ( if (currentBlock().next().isValid() && (
text.length() == 0 || text.at(text.length() - 1) != kBackSlash) && text.length() == 0 || text.at(text.length() - 1) != kBackSlash) &&
currentBlock().next().userState() != Continued) { extractObservableState(currentBlock().next().userState()) != Continued) {
currentBlock().next().setUserState(Continued); currentBlock().next().setUserState(computeState(Continued));
} }
if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) { if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) {
BlockData *data = static_cast<BlockData *>(currentBlockUserData()); BlockData *data = blockData(currentBlockUserData());
data->m_contextToContinue.clear(); data->m_contextToContinue.clear();
setCurrentBlockState(data->m_originalState); setCurrentBlockState(computeState(data->m_originalObservableState));
} }
} }
void Highlighter::mapPersistentSequence(const QString &contextSequence) void Highlighter::mapPersistentSequence(const QString &contextSequence)
{ {
if (!m_persistentStates.contains(contextSequence)) { if (!m_persistentObservableStates.contains(contextSequence)) {
int newState = m_persistentStatesCounter; int newState = m_persistentObservableStatesCounter;
m_persistentStates.insert(contextSequence, newState); m_persistentObservableStates.insert(contextSequence, newState);
m_persistentContexts.insert(newState, m_contexts); m_persistentContexts.insert(newState, m_contexts);
++m_persistentStatesCounter; ++m_persistentObservableStatesCounter;
} }
} }
void Highlighter::mapLeadingSequence(const QString &contextSequence) void Highlighter::mapLeadingSequence(const QString &contextSequence)
{ {
if (!m_leadingStates.contains(contextSequence)) if (!m_leadingObservableStates.contains(contextSequence))
m_leadingStates.insert(contextSequence, currentBlockState()); m_leadingObservableStates.insert(contextSequence,
extractObservableState(currentBlockState()));
} }
void Highlighter::pushContextSequence(int state) void Highlighter::pushContextSequence(int state)
@@ -442,6 +481,11 @@ Highlighter::BlockData *Highlighter::initializeBlockData()
return data; return data;
} }
Highlighter::BlockData *Highlighter::blockData(QTextBlockUserData *userData)
{
return static_cast<BlockData *>(userData);
}
void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext) void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext)
{ {
// A dynamic context is created from another context which serves as its basis. Then, // A dynamic context is created from another context which serves as its basis. Then,
@@ -454,7 +498,7 @@ void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext)
++m_dynamicContextsCounter; ++m_dynamicContextsCounter;
} }
void Highlighter::setCurrentContext() void Highlighter::assignCurrentContext()
{ {
if (m_contexts.isEmpty()) { if (m_contexts.isEmpty()) {
// This is not supposed to happen. However, there are broken files (for example, php.xml) // This is not supposed to happen. However, there are broken files (for example, php.xml)
@@ -464,3 +508,38 @@ void Highlighter::setCurrentContext()
} }
m_currentContext = m_contexts.back(); m_currentContext = m_contexts.back();
} }
int Highlighter::extractRegionDepth(const int state)
{
return state >> 12;
}
int Highlighter::extractObservableState(const int state)
{
return state & 0xFFF;
}
int Highlighter::computeState(const int observableState) const
{
return m_regionDepth << 12 | observableState;
}
void Highlighter::applyFolding() const
{
int folding = 0;
BlockData *data = blockData(currentBlockUserData());
BlockData *previousData = blockData(currentBlock().previous().userData());
if (previousData) {
folding = extractRegionDepth(previousBlockState());
if (data->m_foldingIndentDelta != 0) {
folding += data->m_foldingIndentDelta;
if (data->m_foldingIndentDelta > 0)
data->setFoldingStartIncluded(true);
else
previousData->setFoldingEndIncluded(false);
data->m_foldingIndentDelta = 0;
}
}
data->setFoldingEndIncluded(true);
data->setFoldingIndent(folding);
}

View File

@@ -34,6 +34,7 @@
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QVector> #include <QtCore/QVector>
#include <QtCore/QStack>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QStringList> #include <QtCore/QStringList>
@@ -92,14 +93,14 @@ private:
const bool childRule, const bool childRule,
const QList<QSharedPointer<Rule> > &rules); const QList<QSharedPointer<Rule> > &rules);
void setCurrentContext(); void assignCurrentContext();
bool contextChangeRequired(const QString &contextName) const; bool contextChangeRequired(const QString &contextName) const;
void handleContextChange(const QString &contextName, void handleContextChange(const QString &contextName,
const QSharedPointer<HighlightDefinition> &definition, const QSharedPointer<HighlightDefinition> &definition,
const bool setCurrent = true); const bool setCurrent = true);
void changeContext(const QString &contextName, void changeContext(const QString &contextName,
const QSharedPointer<HighlightDefinition> &definition, const QSharedPointer<HighlightDefinition> &definition,
const bool setCurrent = true); const bool assignCurrent = true);
QString currentContextSequence() const; QString currentContextSequence() const;
void mapPersistentSequence(const QString &contextSequence); void mapPersistentSequence(const QString &contextSequence);
@@ -117,6 +118,8 @@ private:
const QSharedPointer<HighlightDefinition> &definition); const QSharedPointer<HighlightDefinition> &definition);
void applyVisualWhitespaceFormat(const QString &text); void applyVisualWhitespaceFormat(const QString &text);
void applyFolding() const;
// Mapping from Kate format strings to format ids. // Mapping from Kate format strings to format ids.
struct KateFormatMap struct KateFormatMap
{ {
@@ -131,27 +134,40 @@ private:
BlockData(); BlockData();
virtual ~BlockData(); virtual ~BlockData();
int m_originalState; int m_foldingIndentDelta;
int m_originalObservableState;
QStack<QString> m_foldingRegions;
QSharedPointer<Context> m_contextToContinue; QSharedPointer<Context> m_contextToContinue;
}; };
BlockData *initializeBlockData(); BlockData *initializeBlockData();
static BlockData *blockData(QTextBlockUserData *userData);
// Block states // Block states are composed by the region depth (used for code folding) and what I call
// observable states. Observable states occupy the 12 least significant bits. They might have
// the following values:
// - Default [0]: Nothing special. // - Default [0]: Nothing special.
// - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last // - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last
// character). // character).
// - Continued [2]: Blocks that happen after a WillContinue block and continued from their // - Continued [2]: Blocks that happen after a WillContinue block and continue from their
// context until the next line end. // context until the next line end.
// - Persistent(s) [Anything >= 3]: Correspond to persistent contexts which last until a pop // - Persistent(s) [Anything >= 3]: Correspond to persistent contexts which last until a pop
// occurs due to a matching rule. Every sequence of persistent contexts seen so far is // occurs due to a matching rule. Every sequence of persistent contexts seen so far is
// associated with a number (incremented by a unit each time). // associated with a number (incremented by a unit each time).
enum BlockState { // Region depths occupy the remaining bits.
enum ObservableBlockState {
Default = 0, Default = 0,
WillContinue, WillContinue,
Continued, Continued,
PersistentsStart PersistentsStart
}; };
int m_persistentStatesCounter; int computeState(const int observableState) const;
static int extractRegionDepth(const int state);
static int extractObservableState(const int state);
int m_regionDepth;
int m_persistentObservableStatesCounter;
int m_dynamicContextsCounter; int m_dynamicContextsCounter;
bool m_isBroken; bool m_isBroken;
@@ -160,11 +176,11 @@ private:
QSharedPointer<Context> m_currentContext; QSharedPointer<Context> m_currentContext;
QVector<QSharedPointer<Context> > m_contexts; QVector<QSharedPointer<Context> > m_contexts;
// Mapping from context sequences to the persistent state they represent. // Mapping from context sequences to the observable persistent state they represent.
QHash<QString, int> m_persistentStates; QHash<QString, int> m_persistentObservableStates;
// Mapping from context sequences to the non-persistent state that led to them. // Mapping from context sequences to the non-persistent observable state that led to them.
QHash<QString, int> m_leadingStates; QHash<QString, int> m_leadingObservableStates;
// Mapping from persistent states to context sequences (the actual "stack"). // Mapping from observable persistent states to context sequences (the actual "stack").
QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts; QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts;
// Captures used in dynamic rules. // Captures used in dynamic rules.

View File

@@ -38,7 +38,9 @@ ProgressData::ProgressData() :
m_offset(0), m_offset(0),
m_savedOffset(-1), m_savedOffset(-1),
m_onlySpacesSoFar(true), m_onlySpacesSoFar(true),
m_willContinueLine(false) m_willContinueLine(false),
m_openingBraceMatchAtFirstNonSpace(false),
m_closingBraceMatchAtNonEnd(false)
{} {}
void ProgressData::setOffset(const int offset) void ProgressData::setOffset(const int offset)
@@ -69,6 +71,26 @@ void ProgressData::setOnlySpacesSoFar(const bool onlySpaces)
bool ProgressData::isOnlySpacesSoFar() const bool ProgressData::isOnlySpacesSoFar() const
{ return m_onlySpacesSoFar; } { return m_onlySpacesSoFar; }
void ProgressData::setOpeningBraceMatchAtFirstNonSpace(const bool match)
{ m_openingBraceMatchAtFirstNonSpace = match; }
bool ProgressData::isOpeningBraceMatchAtFirstNonSpace() const
{ return m_openingBraceMatchAtFirstNonSpace; }
void ProgressData::setClosingBraceMatchAtNonEnd(const bool match)
{ m_closingBraceMatchAtNonEnd = match; }
bool ProgressData::isClosingBraceMatchAtNonEnd() const
{ return m_closingBraceMatchAtNonEnd; }
void ProgressData::clearBracesMatches()
{
if (m_openingBraceMatchAtFirstNonSpace)
m_openingBraceMatchAtFirstNonSpace = false;
if (m_closingBraceMatchAtNonEnd)
m_closingBraceMatchAtNonEnd = false;
}
void ProgressData::setWillContinueLine(const bool willContinue) void ProgressData::setWillContinueLine(const bool willContinue)
{ m_willContinueLine = willContinue; } { m_willContinueLine = willContinue; }

View File

@@ -52,6 +52,14 @@ public:
void setOnlySpacesSoFar(const bool onlySpaces); void setOnlySpacesSoFar(const bool onlySpaces);
bool isOnlySpacesSoFar() const; bool isOnlySpacesSoFar() const;
void setOpeningBraceMatchAtFirstNonSpace(const bool match);
bool isOpeningBraceMatchAtFirstNonSpace() const;
void setClosingBraceMatchAtNonEnd(const bool match);
bool isClosingBraceMatchAtNonEnd() const;
void clearBracesMatches();
void setWillContinueLine(const bool willContinue); void setWillContinueLine(const bool willContinue);
bool isWillContinueLine() const; bool isWillContinueLine() const;
@@ -62,6 +70,8 @@ private:
int m_offset; int m_offset;
int m_savedOffset; int m_savedOffset;
bool m_onlySpacesSoFar; bool m_onlySpacesSoFar;
bool m_openingBraceMatchAtFirstNonSpace;
bool m_closingBraceMatchAtNonEnd;
bool m_willContinueLine; bool m_willContinueLine;
QStringList m_captures; QStringList m_captures;
}; };

View File

@@ -58,6 +58,8 @@ const QLatin1Char Rule::kN('n');
const QLatin1Char Rule::kR('r'); const QLatin1Char Rule::kR('r');
const QLatin1Char Rule::kT('t'); const QLatin1Char Rule::kT('t');
const QLatin1Char Rule::kV('v'); const QLatin1Char Rule::kV('v');
const QLatin1Char Rule::kOpeningBrace('{');
const QLatin1Char Rule::kClosingBrace('}');
Rule::Rule(bool consumesNonSpace) : Rule::Rule(bool consumesNonSpace) :
m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace) m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)

View File

@@ -124,6 +124,8 @@ protected:
static const QLatin1Char kR; static const QLatin1Char kR;
static const QLatin1Char kT; static const QLatin1Char kT;
static const QLatin1Char kV; static const QLatin1Char kV;
static const QLatin1Char kOpeningBrace;
static const QLatin1Char kClosingBrace;
private: private:
virtual bool doMatchSucceed(const QString &text, virtual bool doMatchSucceed(const QString &text,

View File

@@ -86,7 +86,18 @@ bool DetectCharRule::doMatchSucceed(const QString &text,
const int length, const int length,
ProgressData *progress) const ProgressData *progress) const
{ {
return matchCharacter(text, length, progress, m_char); if (matchCharacter(text, length, progress, m_char)) {
// This is to make code folding have a control flow style look in the case of braces.
// Naturally, this assumes that language definitions use braces with this meaning.
if (m_char == kOpeningBrace && progress->isOnlySpacesSoFar() && !isLookAhead()) {
progress->setOpeningBraceMatchAtFirstNonSpace(true);
} else if (m_char == kClosingBrace &&
!text.right(length - progress->offset()).trimmed().isEmpty()) {
progress->setClosingBraceMatchAtNonEnd(true);
}
return true;
}
return false;
} }
// Detect2Chars // Detect2Chars

View File

@@ -162,7 +162,10 @@ void PlainTextEditor::configure(const Core::MimeType &mimeType)
{ {
Highlighter *highlighter = new Highlighter(); Highlighter *highlighter = new Highlighter();
baseTextDocument()->setSyntaxHighlighter(highlighter); baseTextDocument()->setSyntaxHighlighter(highlighter);
m_isMissingSyntaxDefinition = true; m_isMissingSyntaxDefinition = true;
setCodeFoldingSupported(false);
setCodeFoldingVisible(false);
QString definitionId; QString definitionId;
if (!mimeType.isNull()) { if (!mimeType.isNull()) {
@@ -185,6 +188,9 @@ void PlainTextEditor::configure(const Core::MimeType &mimeType)
m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart()); m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart());
m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd()); m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd());
setCodeFoldingSupported(true);
setCodeFoldingVisible(true);
m_isMissingSyntaxDefinition = false; m_isMissingSyntaxDefinition = false;
} }
} else if (file()) { } else if (file()) {

View File

@@ -50,7 +50,8 @@ PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent)
m_actionHandler = new TextEditorActionHandler( m_actionHandler = new TextEditorActionHandler(
QLatin1String(TextEditor::Constants::C_TEXTEDITOR), QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
TextEditorActionHandler::Format | TextEditorActionHandler::Format |
TextEditorActionHandler::UnCommentSelection); TextEditorActionHandler::UnCommentSelection |
TextEditorActionHandler::UnCollapseAll);
m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT); m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT);
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),

View File

@@ -32,13 +32,19 @@
/* /*
Since the text editor plugin directory is not included in the search list of the pro file, this Since the text editor plugin directory is not included in the search list of the pro file, this
file replaces the "real" basetextdocumentlayout.h file. The objective is to simply use file replaces the "real" basetextdocumentlayout.h file. The objective is to provide a simple
QTextBlockUserData instead of TextEditor::TextBlockUserData to avoid "external" TextBlockUserData and avoid "external" dependencies or intrusive defines.
dependencies or intrusive defines.
*/ */
#include <QtGui/QTextBlockUserData> #include <QtGui/QTextBlockUserData>
typedef QTextBlockUserData TextBlockUserData; struct TextBlockUserData : QTextBlockUserData
{
virtual ~TextBlockUserData(){}
void setFoldingStartIncluded(const bool) {}
void setFoldingEndIncluded(const bool) {}
void setFoldingIndent(const int) {}
};
#endif // BASETEXTDOCUMENTLAYOUT_H #endif // BASETEXTDOCUMENTLAYOUT_H

View File

@@ -109,7 +109,8 @@ void HighlighterMock::highlightBlock(const QString &text)
if (m_states.size() <= m_statesCounter) if (m_states.size() <= m_statesCounter)
QFAIL("Expected state for current block not set."); QFAIL("Expected state for current block not set.");
QCOMPARE(currentBlockState(), m_states.at(m_statesCounter++)); const int observableState = currentBlockState() & 0xFFF;
QCOMPARE(observableState, m_states.at(m_statesCounter++));
if (m_formatSequence.size() <= m_formatsCounter) if (m_formatSequence.size() <= m_formatsCounter)
QFAIL("Expected highlight sequence for current block not set."); QFAIL("Expected highlight sequence for current block not set.");