diff --git a/src/plugins/texteditor/generichighlighter/highlighter.cpp b/src/plugins/texteditor/generichighlighter/highlighter.cpp index fc2fa35bd6ca6ea35b89e29d2598a61273c6402a..aba84b8c4f80c91b3ee0f7c17fd658a9e6ee769e 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.cpp +++ b/src/plugins/texteditor/generichighlighter/highlighter.cpp @@ -53,7 +53,8 @@ const Highlighter::KateFormatMap Highlighter::m_kateFormats; Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent), - m_persistentStatesCounter(PersistentsStart), + m_regionDepth(0), + m_persistentObservableStatesCounter(PersistentsStart), m_dynamicContextsCounter(0), m_isBroken(false) {} @@ -61,7 +62,7 @@ Highlighter::Highlighter(QTextDocument *parent) : Highlighter::~Highlighter() {} -Highlighter::BlockData::BlockData() +Highlighter::BlockData::BlockData() : m_foldingIndentDelta(0) {} Highlighter::BlockData::~BlockData() @@ -93,13 +94,15 @@ void Highlighter::configureFormat(TextFormatId id, const QTextCharFormat &format void Highlighter::setDefaultContext(const QSharedPointer<Context> &defaultContext) { m_defaultContext = defaultContext; - m_persistentStates.insert(m_defaultContext->name(), Default); + m_persistentObservableStates.insert(m_defaultContext->name(), Default); } void Highlighter::highlightBlock(const QString &text) { if (!m_defaultContext.isNull() && !m_isBroken) { try { + if (!currentBlockUserData()) + initializeBlockData(); setupDataForBlock(text); handleContextChange(m_currentContext->lineBeginContext(), @@ -107,20 +110,19 @@ void Highlighter::highlightBlock(const QString &text) ProgressData progress; const int length = text.length(); - while (progress.offset() < length) { - if (progress.offset() > 0 && - progress.onlySpacesSoFar() && - !text.at(progress.offset()).isSpace()) { - progress.setOnlySpacesSoFar(false); - } - + while (progress.offset() < length) iterateThroughRules(text, length, &progress, false, m_currentContext->rules()); - } handleContextChange(m_currentContext->lineEndContext(), m_currentContext->definition(), false); 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 &) { m_isBroken = true; } @@ -131,60 +133,70 @@ void Highlighter::highlightBlock(const QString &text) void Highlighter::setupDataForBlock(const QString &text) { - if (currentBlockState() == WillContinue) + if (extractObservableState(currentBlockState()) == WillContinue) analyseConsistencyOfWillContinueBlock(text); - if (previousBlockState() == Default || previousBlockState() == -1) + if (previousBlockState() == -1) { + m_regionDepth = 0; setupDefault(); - else if (previousBlockState() == WillContinue) - setupFromWillContinue(); - else if (previousBlockState() == Continued) - setupFromContinued(); - else - setupFromPersistent(); - - setCurrentContext(); + } else { + m_regionDepth = extractRegionDepth(previousBlockState()); + const int observablePreviousState = extractObservableState(previousBlockState()); + if (observablePreviousState == Default) + setupDefault(); + else if (observablePreviousState == WillContinue) + setupFromWillContinue(); + else if (observablePreviousState == Continued) + setupFromContinued(); + else + setupFromPersistent(); + + blockData(currentBlockUserData())->m_foldingRegions = + blockData(currentBlock().previous().userData())->m_foldingRegions; + } + + assignCurrentContext(); } void Highlighter::setupDefault() { m_contexts.push_back(m_defaultContext); - setCurrentBlockState(Default); + setCurrentBlockState(computeState(Default)); } void Highlighter::setupFromWillContinue() { - BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); + BlockData *previousData = blockData(currentBlock().previous().userData()); m_contexts.push_back(previousData->m_contextToContinue); - if (!currentBlockUserData()) { - BlockData *data = initializeBlockData(); - data->m_originalState = previousData->m_originalState; - } + BlockData *data = blockData(currentBlock().userData()); + data->m_originalObservableState = previousData->m_originalObservableState; - if (currentBlockState() == Default || currentBlockState() == -1) - setCurrentBlockState(Continued); + if (currentBlockState() == -1 || extractObservableState(currentBlockState()) == Default) + setCurrentBlockState(computeState(Continued)); } void Highlighter::setupFromContinued() { - BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); + BlockData *previousData = blockData(currentBlock().previous().userData()); - Q_ASSERT(previousData->m_originalState != WillContinue && - previousData->m_originalState != Continued); + Q_ASSERT(previousData->m_originalObservableState != WillContinue && + 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); - else - pushContextSequence(previousData->m_originalState); + } else { + pushContextSequence(previousData->m_originalObservableState); + } - setCurrentBlockState(previousData->m_originalState); + setCurrentBlockState(computeState(previousData->m_originalObservableState)); } void Highlighter::setupFromPersistent() { - pushContextSequence(previousBlockState()); + pushContextSequence(extractObservableState(previousBlockState())); setCurrentBlockState(previousBlockState()); } @@ -204,12 +216,30 @@ void Highlighter::iterateThroughRules(const QString &text, RuleIterator endIt = rules.end(); while (it != endIt && progress->offset() < length) { int startOffset = progress->offset(); - const QSharedPointer<Rule> &rule = *it; if (rule->matchSucceed(text, length, progress)) { atLeastOneMatch = true; - if (progress->willContinueLine()) { + // 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()) { createWillContinueBlock(); progress->setWillContinueLine(false); } else { @@ -254,6 +284,8 @@ void Highlighter::iterateThroughRules(const QString &text, } else { applyFormat(progress->offset(), 1, m_currentContext->itemData(), m_currentContext->definition()); + if (progress->isOnlySpacesSoFar() && !text.at(progress->offset()).isSpace()) + progress->setOnlySpacesSoFar(false); progress->incrementOffset(); } } @@ -268,20 +300,22 @@ bool Highlighter::contextChangeRequired(const QString &contextName) const void Highlighter::changeContext(const QString &contextName, const QSharedPointer<HighlightDefinition> &definition, - const bool setCurrent) + const bool assignCurrent) { if (contextName.startsWith(kPop)) { QStringList list = contextName.split(kHash, QString::SkipEmptyParts); for (int i = 0; i < list.size(); ++i) m_contexts.pop_back(); - if (currentBlockState() >= PersistentsStart) { + if (extractObservableState(currentBlockState()) >= PersistentsStart) { // One or more contexts were popped during during a persistent state. const QString ¤tSequence = currentContextSequence(); - if (m_persistentStates.contains(currentSequence)) - setCurrentBlockState(m_persistentStates.value(currentSequence)); + if (m_persistentObservableStates.contains(currentSequence)) + setCurrentBlockState( + computeState(m_persistentObservableStates.value(currentSequence))); else - setCurrentBlockState(m_leadingStates.value(currentSequence)); + setCurrentBlockState( + computeState(m_leadingObservableStates.value(currentSequence))); } } else { const QSharedPointer<Context> &context = definition->context(contextName); @@ -292,19 +326,20 @@ void Highlighter::changeContext(const QString &contextName, m_contexts.push_back(context); if (m_contexts.back()->lineEndContext() == kStay || - currentBlockState() >= PersistentsStart) { + extractObservableState(currentBlockState()) >= PersistentsStart) { const QString ¤tSequence = currentContextSequence(); mapLeadingSequence(currentSequence); if (m_contexts.back()->lineEndContext() == kStay) { // A persistent context was pushed. mapPersistentSequence(currentSequence); - setCurrentBlockState(m_persistentStates.value(currentSequence)); + setCurrentBlockState( + computeState(m_persistentObservableStates.value(currentSequence))); } } } - if (setCurrent) - setCurrentContext(); + if (assignCurrent) + assignCurrentContext(); } void Highlighter::handleContextChange(const QString &contextName, @@ -378,50 +413,49 @@ void Highlighter::applyVisualWhitespaceFormat(const QString &text) void Highlighter::createWillContinueBlock() { - if (!currentBlockUserData()) - initializeBlockData(); - - BlockData *data = static_cast<BlockData *>(currentBlockUserData()); - if (currentBlockState() == Continued) { - BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData()); - data->m_originalState = previousData->m_originalState; - } else if (currentBlockState() != WillContinue) { - data->m_originalState = currentBlockState(); + BlockData *data = blockData(currentBlockUserData()); + const int currentObservableState = extractObservableState(currentBlockState()); + if (currentObservableState == Continued) { + BlockData *previousData = blockData(currentBlock().previous().userData()); + data->m_originalObservableState = previousData->m_originalObservableState; + } else if (currentObservableState != WillContinue) { + data->m_originalObservableState = currentObservableState; } data->m_contextToContinue = m_currentContext; - setCurrentBlockState(WillContinue); + setCurrentBlockState(computeState(WillContinue)); } void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text) { if (currentBlock().next().isValid() && ( text.length() == 0 || text.at(text.length() - 1) != kBackSlash) && - currentBlock().next().userState() != Continued) { - currentBlock().next().setUserState(Continued); + extractObservableState(currentBlock().next().userState()) != Continued) { + currentBlock().next().setUserState(computeState(Continued)); } if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) { - BlockData *data = static_cast<BlockData *>(currentBlockUserData()); + BlockData *data = blockData(currentBlockUserData()); data->m_contextToContinue.clear(); - setCurrentBlockState(data->m_originalState); + setCurrentBlockState(computeState(data->m_originalObservableState)); } } void Highlighter::mapPersistentSequence(const QString &contextSequence) { - if (!m_persistentStates.contains(contextSequence)) { - int newState = m_persistentStatesCounter; - m_persistentStates.insert(contextSequence, newState); + if (!m_persistentObservableStates.contains(contextSequence)) { + int newState = m_persistentObservableStatesCounter; + m_persistentObservableStates.insert(contextSequence, newState); m_persistentContexts.insert(newState, m_contexts); - ++m_persistentStatesCounter; + ++m_persistentObservableStatesCounter; } } void Highlighter::mapLeadingSequence(const QString &contextSequence) { - if (!m_leadingStates.contains(contextSequence)) - m_leadingStates.insert(contextSequence, currentBlockState()); + if (!m_leadingObservableStates.contains(contextSequence)) + m_leadingObservableStates.insert(contextSequence, + extractObservableState(currentBlockState())); } void Highlighter::pushContextSequence(int state) @@ -447,6 +481,11 @@ Highlighter::BlockData *Highlighter::initializeBlockData() return data; } +Highlighter::BlockData *Highlighter::blockData(QTextBlockUserData *userData) +{ + return static_cast<BlockData *>(userData); +} + void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext) { // A dynamic context is created from another context which serves as its basis. Then, @@ -459,7 +498,7 @@ void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext) ++m_dynamicContextsCounter; } -void Highlighter::setCurrentContext() +void Highlighter::assignCurrentContext() { if (m_contexts.isEmpty()) { // This is not supposed to happen. However, there are broken files (for example, php.xml) @@ -469,3 +508,38 @@ void Highlighter::setCurrentContext() } 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); +} diff --git a/src/plugins/texteditor/generichighlighter/highlighter.h b/src/plugins/texteditor/generichighlighter/highlighter.h index 2aaabbd88c779fb539e47c7817c88ab09b348588..7ca7e9d649d1716ff85a705e17fe2430146fde0d 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.h +++ b/src/plugins/texteditor/generichighlighter/highlighter.h @@ -34,6 +34,7 @@ #include <QtCore/QString> #include <QtCore/QVector> +#include <QtCore/QStack> #include <QtCore/QSharedPointer> #include <QtCore/QStringList> @@ -92,14 +93,14 @@ private: const bool childRule, const QList<QSharedPointer<Rule> > &rules); - void setCurrentContext(); + void assignCurrentContext(); bool contextChangeRequired(const QString &contextName) const; void handleContextChange(const QString &contextName, const QSharedPointer<HighlightDefinition> &definition, const bool setCurrent = true); void changeContext(const QString &contextName, const QSharedPointer<HighlightDefinition> &definition, - const bool setCurrent = true); + const bool assignCurrent = true); QString currentContextSequence() const; void mapPersistentSequence(const QString &contextSequence); @@ -117,6 +118,8 @@ private: const QSharedPointer<HighlightDefinition> &definition); void applyVisualWhitespaceFormat(const QString &text); + void applyFolding() const; + // Mapping from Kate format strings to format ids. struct KateFormatMap { @@ -131,27 +134,40 @@ private: BlockData(); virtual ~BlockData(); - int m_originalState; + int m_foldingIndentDelta; + int m_originalObservableState; + QStack<QString> m_foldingRegions; QSharedPointer<Context> m_contextToContinue; }; 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. // - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last // 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. // - 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 // associated with a number (incremented by a unit each time). - enum BlockState { + // Region depths occupy the remaining bits. + enum ObservableBlockState { Default = 0, WillContinue, Continued, 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; bool m_isBroken; @@ -160,11 +176,11 @@ private: QSharedPointer<Context> m_currentContext; QVector<QSharedPointer<Context> > m_contexts; - // Mapping from context sequences to the persistent state they represent. - QHash<QString, int> m_persistentStates; - // Mapping from context sequences to the non-persistent state that led to them. - QHash<QString, int> m_leadingStates; - // Mapping from persistent states to context sequences (the actual "stack"). + // Mapping from context sequences to the observable persistent state they represent. + QHash<QString, int> m_persistentObservableStates; + // Mapping from context sequences to the non-persistent observable state that led to them. + QHash<QString, int> m_leadingObservableStates; + // Mapping from observable persistent states to context sequences (the actual "stack"). QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts; // Captures used in dynamic rules. diff --git a/src/plugins/texteditor/generichighlighter/progressdata.cpp b/src/plugins/texteditor/generichighlighter/progressdata.cpp index 12c76079d84e6be2a564edcb8215988c44f50684..9a7b619eca02756b9be93d26b5c2d442c9c0bd51 100644 --- a/src/plugins/texteditor/generichighlighter/progressdata.cpp +++ b/src/plugins/texteditor/generichighlighter/progressdata.cpp @@ -38,7 +38,9 @@ ProgressData::ProgressData() : m_offset(0), m_savedOffset(-1), m_onlySpacesSoFar(true), - m_willContinueLine(false) + m_willContinueLine(false), + m_openingBraceMatchAtFirstNonSpace(false), + m_closingBraceMatchAtNonEnd(false) {} void ProgressData::setOffset(const int offset) @@ -66,13 +68,33 @@ void ProgressData::restoreOffset() void ProgressData::setOnlySpacesSoFar(const bool onlySpaces) { m_onlySpacesSoFar = onlySpaces; } -bool ProgressData::onlySpacesSoFar() const +bool ProgressData::isOnlySpacesSoFar() const { 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) { m_willContinueLine = willContinue; } -bool ProgressData::willContinueLine() const +bool ProgressData::isWillContinueLine() const { return m_willContinueLine; } void ProgressData::setCaptures(const QStringList &captures) diff --git a/src/plugins/texteditor/generichighlighter/progressdata.h b/src/plugins/texteditor/generichighlighter/progressdata.h index a621c15dc75e2449169ac23e0adc200e78dda09c..d82b4914d53f7ae8f90eea14ed0ee195da2b643d 100644 --- a/src/plugins/texteditor/generichighlighter/progressdata.h +++ b/src/plugins/texteditor/generichighlighter/progressdata.h @@ -50,10 +50,18 @@ public: void restoreOffset(); void setOnlySpacesSoFar(const bool onlySpaces); - bool onlySpacesSoFar() 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); - bool willContinueLine() const; + bool isWillContinueLine() const; void setCaptures(const QStringList &captures); const QStringList &captures() const; @@ -62,6 +70,8 @@ private: int m_offset; int m_savedOffset; bool m_onlySpacesSoFar; + bool m_openingBraceMatchAtFirstNonSpace; + bool m_closingBraceMatchAtNonEnd; bool m_willContinueLine; QStringList m_captures; }; diff --git a/src/plugins/texteditor/generichighlighter/rule.cpp b/src/plugins/texteditor/generichighlighter/rule.cpp index 3ad611938e47411ef48b5d550bf9cc8e4f2c09ca..f30e6e8e3c99321636fb9e49de717c00b57a1c14 100644 --- a/src/plugins/texteditor/generichighlighter/rule.cpp +++ b/src/plugins/texteditor/generichighlighter/rule.cpp @@ -58,6 +58,8 @@ const QLatin1Char Rule::kN('n'); const QLatin1Char Rule::kR('r'); const QLatin1Char Rule::kT('t'); const QLatin1Char Rule::kV('v'); +const QLatin1Char Rule::kOpeningBrace('{'); +const QLatin1Char Rule::kClosingBrace('}'); Rule::Rule(bool consumesNonSpace) : m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace) @@ -162,7 +164,7 @@ bool Rule::charPredicateMatchSucceed(const QString &text, bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress) const { - if (m_firstNonSpace && !progress->onlySpacesSoFar()) + if (m_firstNonSpace && !progress->isOnlySpacesSoFar()) return false; if (m_column != -1 && m_column != progress->offset()) @@ -170,7 +172,7 @@ bool Rule::matchSucceed(const QString &text, const int length, ProgressData *pro int original = progress->offset(); if (doMatchSucceed(text, length, progress)) { - if (progress->onlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace) + if (progress->isOnlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace) progress->setOnlySpacesSoFar(false); if (m_lookAhead) diff --git a/src/plugins/texteditor/generichighlighter/rule.h b/src/plugins/texteditor/generichighlighter/rule.h index a53b2f8e5c408ee6d632746fc90d13b0a0d9f1a9..77c8397bf198db3484abe6a8865e135d94c52a25 100644 --- a/src/plugins/texteditor/generichighlighter/rule.h +++ b/src/plugins/texteditor/generichighlighter/rule.h @@ -123,7 +123,9 @@ protected: static const QLatin1Char kN; static const QLatin1Char kR; static const QLatin1Char kT; - static const QLatin1Char kV; + static const QLatin1Char kV; + static const QLatin1Char kOpeningBrace; + static const QLatin1Char kClosingBrace; private: virtual bool doMatchSucceed(const QString &text, diff --git a/src/plugins/texteditor/generichighlighter/specificrules.cpp b/src/plugins/texteditor/generichighlighter/specificrules.cpp index 86e6f4e7ec339e1cb7a5c7033ad952d514f5fe29..8a43f65b703fbb26b66aac1791490fec77544ec9 100644 --- a/src/plugins/texteditor/generichighlighter/specificrules.cpp +++ b/src/plugins/texteditor/generichighlighter/specificrules.cpp @@ -86,7 +86,18 @@ bool DetectCharRule::doMatchSucceed(const QString &text, const int length, 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 diff --git a/src/plugins/texteditor/plaintexteditor.cpp b/src/plugins/texteditor/plaintexteditor.cpp index e62e2df035e24d571b21d42f0816206039b78fee..d945b166711d098535419ff6ef9065d981092aec 100644 --- a/src/plugins/texteditor/plaintexteditor.cpp +++ b/src/plugins/texteditor/plaintexteditor.cpp @@ -162,7 +162,10 @@ void PlainTextEditor::configure(const Core::MimeType &mimeType) { Highlighter *highlighter = new Highlighter(); baseTextDocument()->setSyntaxHighlighter(highlighter); + m_isMissingSyntaxDefinition = true; + setCodeFoldingSupported(false); + setCodeFoldingVisible(false); QString definitionId; if (!mimeType.isNull()) { @@ -185,6 +188,9 @@ void PlainTextEditor::configure(const Core::MimeType &mimeType) m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart()); m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd()); + setCodeFoldingSupported(true); + setCodeFoldingVisible(true); + m_isMissingSyntaxDefinition = false; } } else if (file()) { diff --git a/src/plugins/texteditor/plaintexteditorfactory.cpp b/src/plugins/texteditor/plaintexteditorfactory.cpp index 87f6c70830152cb8947c52ec448510c8ef79fe52..c06b0f79f95e0b4c35cc2796836c9c17a5b2f550 100644 --- a/src/plugins/texteditor/plaintexteditorfactory.cpp +++ b/src/plugins/texteditor/plaintexteditorfactory.cpp @@ -50,7 +50,8 @@ PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent) m_actionHandler = new TextEditorActionHandler( QLatin1String(TextEditor::Constants::C_TEXTEDITOR), TextEditorActionHandler::Format | - TextEditorActionHandler::UnCommentSelection); + TextEditorActionHandler::UnCommentSelection | + TextEditorActionHandler::UnCollapseAll); m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT); connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), diff --git a/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h b/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h index 37320e4361dc9e8e546fa34aad0fe1dbcb763e30..f3433db6327991401234361462b22ed7845de85e 100644 --- a/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h +++ b/tests/auto/generichighlighter/highlighterengine/basetextdocumentlayout.h @@ -32,13 +32,19 @@ /* 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 - QTextBlockUserData instead of TextEditor::TextBlockUserData to avoid "external" - dependencies or intrusive defines. + file replaces the "real" basetextdocumentlayout.h file. The objective is to provide a simple + TextBlockUserData and avoid "external" dependencies or intrusive defines. */ #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 diff --git a/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp b/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp index d558a9eb418201f28eeaf7305991af45987c53d1..7ed758a5a349c2472eda91473ad8052e6e867f87 100644 --- a/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp +++ b/tests/auto/generichighlighter/highlighterengine/highlightermock.cpp @@ -109,7 +109,8 @@ void HighlighterMock::highlightBlock(const QString &text) if (m_states.size() <= m_statesCounter) 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) QFAIL("Expected highlight sequence for current block not set."); diff --git a/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp b/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp index 8e402f8b8b09b9ed2ac2ac513beca4d003572fe7..6c76fe2c16385e9339293442175ad3e7591920e4 100644 --- a/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp +++ b/tests/auto/generichighlighter/highlighterengine/tst_highlighterengine.cpp @@ -80,6 +80,9 @@ private slots: void testDynamicContexts(); void testDynamicContexts_data(); + void testFirstNonSpace(); + void testFirstNonSpace_data(); + private: void createKeywords(); void createContexts(); @@ -436,6 +439,13 @@ void tst_HighlighterEngine::createContexts() r26->setActive("true"); r26->setDefinition(m_definition); dynamic->addRule(QSharedPointer<Rule>(r26)); + + DetectCharRule *r27 = new DetectCharRule; + r27->setChar("|"); + r27->setItemData("Error"); + r27->setFirstNonSpace("true"); + r27->setDefinition(m_definition); + normal->addRule(QSharedPointer<Rule>(r27)); } void tst_HighlighterEngine::createItemDatas() @@ -1031,6 +1041,47 @@ void tst_HighlighterEngine::testDynamicContexts_data() QTest::newRow("case 1") << states << sequences << text; } +void tst_HighlighterEngine::testFirstNonSpace() +{ + test(); +} + +void tst_HighlighterEngine::testFirstNonSpace_data() +{ + createColumns(); + + QList<int> states; + QList<HighlightSequence> sequences; + QString text; + + HighlightSequence seqa(0, 1, Formats::instance().errorFormat()); + HighlightSequence seqb(0, 3); + seqb.add(3, 4, Formats::instance().errorFormat()); + HighlightSequence seqc(0, 1); + seqc.add(1, 2, Formats::instance().errorFormat()); + HighlightSequence seqd(0, 2); + + states << 0; + sequences << seqa; + text = "|"; + QTest::newRow("case 0") << states << sequences << text; + + sequences.clear(); + sequences << seqb; + text = " |"; + QTest::newRow("case 1") << states << sequences << text; + + sequences.clear(); + sequences << seqc; + text = "\t|"; + QTest::newRow("case 2") << states << sequences << text; + + sequences.clear(); + sequences << seqd; + text = "a|"; + QTest::newRow("case 3") << states << sequences << text; +} + QTEST_MAIN(tst_HighlighterEngine) #include "tst_highlighterengine.moc" diff --git a/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp b/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp index 6e482f38b996aeecfe9558e2d472ee1a16200e36..c06b61fbaf5bcabfb7755bd83a455612a83ce6a7 100644 --- a/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp +++ b/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp @@ -149,8 +149,8 @@ void tst_SpecificRules::testMatch(const Rule &rule, ProgressData *progress) cons QTEST(rule.matchSucceed(s, s.length(), progress), "match"); QTEST(progress->offset(), "offset"); - QTEST(progress->onlySpacesSoFar(), "only spaces"); - QTEST(progress->willContinueLine(), "will continue"); + QTEST(progress->isOnlySpacesSoFar(), "only spaces"); + QTEST(progress->isWillContinueLine(), "will continue"); } void tst_SpecificRules::testDetectChar()