diff --git a/src/plugins/cppeditor/cppcheckundefinedsymbols.h b/src/plugins/cppeditor/cppcheckundefinedsymbols.h index 4dbc0b52f3c7b6ede4e89879234c84af563c423a..49579c6c6db9ca4cc7ca363b7ec7db365f3c3f94 100644 --- a/src/plugins/cppeditor/cppcheckundefinedsymbols.h +++ b/src/plugins/cppeditor/cppcheckundefinedsymbols.h @@ -56,6 +56,22 @@ public: typedef QFuture<Use> Future; static Future go(Document::Ptr doc, const LookupContext &context); + static QMap<int, QVector<Use> > chunks(const QFuture<Use> &future, int from, int to) + { + QMap<int, QVector<Use> > chunks; + + for (int i = from; i < to; ++i) { + const Use use = future.resultAt(i); + if (! use.line) + continue; // skip it, it's an invalid use. + + const int blockNumber = use.line - 1; + chunks[blockNumber].append(use); + } + + return chunks; + } + protected: using ASTVisitor::visit; using ASTVisitor::endVisit; diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index c2d42cfc6fb1f2da4a9d61125482017e0ad60319..6be22af53991847e9a4d3d95ac634b6eddf5cfe8 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -129,47 +129,6 @@ static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document return selections; } -static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document, - const QList<SemanticInfo::Use> &msgs, - const QTextCharFormat &format) -{ - QList<QTextEdit::ExtraSelection> selections; - - QTextBlock currentBlock = document->firstBlock(); - unsigned currentLine = 1; - - foreach (const SemanticInfo::Use &use, msgs) { - QTextCursor cursor(document); - - if (currentLine != use.line) { - int delta = use.line - currentLine; - - if (delta >= 0) { - while (delta--) - currentBlock = currentBlock.next(); - } else { - currentBlock = document->findBlockByNumber(use.line - 1); - } - - currentLine = use.line; - } - - const int pos = currentBlock.position() + use.column - 1; - if (pos < 0) - continue; - - cursor.setPosition(pos); - cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length); - - QTextEdit::ExtraSelection sel; - sel.cursor = cursor; - sel.format = format; - selections.append(sel); - } - - return selections; -} - namespace { class OverviewTreeView : public QTreeView @@ -643,8 +602,10 @@ CPPEditor::CPPEditor(QWidget *parent) this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr))); } - m_highlighteRevision = 0; - connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(highlightTypeUsages())); + m_highlightRevision = 0; + m_nextHighlightBlockNumber = 0; + connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightTypeUsages(int,int))); + connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishTypeUsages())); } CPPEditor::~CPPEditor() @@ -1139,8 +1100,9 @@ void CPPEditor::updateOutlineToolTip() void CPPEditor::updateUses() { + if (editorRevision() != m_highlightRevision) + m_highlighter.cancel(); m_updateUsesTimer->start(); - m_highlighter.cancel(); } void CPPEditor::updateUsesNow() @@ -1151,18 +1113,76 @@ void CPPEditor::updateUsesNow() semanticRehighlight(); } -void CPPEditor::highlightTypeUsages() +void CPPEditor::highlightTypeUsages(int from, int to) +{ + if (editorRevision() != m_highlightRevision) + return; // outdated + + else if (m_highlighter.isCanceled()) + return; // aborted + + CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter()); + Q_ASSERT(highlighter); + QTextDocument *doc = document(); + + if (m_nextHighlightBlockNumber >= doc->blockCount()) + return; + + QMap<int, QVector<SemanticInfo::Use> > chunks = CheckUndefinedSymbols::chunks(m_highlighter, from, to); + Q_ASSERT(!chunks.isEmpty()); + QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber); + + QMapIterator<int, QVector<SemanticInfo::Use> > it(chunks); + while (b.isValid() && it.hasNext()) { + it.next(); + const int blockNumber = it.key(); + Q_ASSERT(blockNumber < doc->blockCount()); + + while (m_nextHighlightBlockNumber < blockNumber) { + highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>()); + b = b.next(); + ++m_nextHighlightBlockNumber; + } + + QList<QTextLayout::FormatRange> formats; + foreach (const SemanticInfo::Use &use, it.value()) { + QTextLayout::FormatRange formatRange; + formatRange.format = m_typeFormat; + formatRange.start = use.column - 1; + formatRange.length = use.length; + formats.append(formatRange); + } + highlighter->setExtraAdditionalFormats(b, formats); + b = b.next(); + ++m_nextHighlightBlockNumber; + } +} + +void CPPEditor::finishTypeUsages() { - if (editorRevision() != m_highlighteRevision) + if (editorRevision() != m_highlightRevision) return; // outdated else if (m_highlighter.isCanceled()) return; // aborted - const QList<SemanticInfo::Use> typeUsages = m_highlighter.results(); - setExtraSelections(TypeSelection, createSelections(document(), typeUsages, m_typeFormat)); + CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter()); + Q_ASSERT(highlighter); + QTextDocument *doc = document(); + + if (m_nextHighlightBlockNumber >= doc->blockCount()) + return; + + QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber); + + while (b.isValid()) { + highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>()); + b = b.next(); + ++m_nextHighlightBlockNumber; + } } + void CPPEditor::switchDeclarationDefinition() { if (! m_modelManager) @@ -1959,7 +1979,8 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo) LookupContext context(semanticInfo.doc, semanticInfo.snapshot); CheckUndefinedSymbols::Future f = CheckUndefinedSymbols::go(semanticInfo.doc, context); m_highlighter = f; - m_highlighteRevision = semanticInfo.revision; + m_highlightRevision = semanticInfo.revision; + m_nextHighlightBlockNumber = 0; m_highlightWatcher.setFuture(m_highlighter); } @@ -1970,6 +1991,7 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo) #endif } + setExtraSelections(UnusedSymbolSelection, unusedSelections); if (! m_renameSelections.isEmpty()) diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index fe7cff471cc1957dc12603ad114a0336a0a8a206..738a97758666f1d332d2d484e9c8f1c95a38c692 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -233,7 +233,8 @@ private Q_SLOTS: void semanticRehighlight(); void updateSemanticInfo(const CppEditor::Internal::SemanticInfo &semanticInfo); - void highlightTypeUsages(); + void highlightTypeUsages(int from, int to); + void finishTypeUsages(); void performQuickFix(int index); @@ -300,7 +301,8 @@ private: QFuture<SemanticInfo::Use> m_highlighter; QFutureWatcher<SemanticInfo::Use> m_highlightWatcher; - unsigned m_highlighteRevision; // the editor revision that requested the highlight + unsigned m_highlightRevision; // the editor revision that requested the highlight + int m_nextHighlightBlockNumber; }; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 3283b7b77d77a6dfd33a17a90347134046e598bd..37f3ebcea02c9ed92c032407c5f9c214083a634f 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -4063,10 +4063,8 @@ int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) while (block.isValid() && ts.onlySpace(block.text())) block = block.next(); if (block.isValid() - && ts.indentationColumn(block.text()) > indentation) { - qDebug() << "indentation check failed" << indentation << ts.indentationColumn(block.next().text()); + && ts.indentationColumn(block.text()) > indentation) return 0; - } } int pos = cursor.position(); @@ -4664,7 +4662,6 @@ void BaseTextEditor::maybeClearSomeExtraSelections(const QTextCursor &cursor) if (cursor.selectionEnd() - cursor.selectionStart() < smallSelectionSize) return; - d->m_extraSelections[TypeSelection].clear(); d->m_extraSelections[UndefinedSymbolSelection].clear(); d->m_extraSelections[ObjCSelection].clear(); d->m_extraSelections[CodeWarningsSelection].clear(); diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 8a0cb0499caec17ac7345e2dc09fb85a05970c04..450c3350730c34bfa66aae6fa69cb4682c4cc822 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -349,7 +349,6 @@ public: FakeVimSelection, OtherSelection, SnippetPlaceholderSelection, - TypeSelection, ObjCSelection, NExtraSelectionKinds }; diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 59113d99f44994f756eb32b2563e6a4e61dc7008..a2245f792317d884c9849eef88df3eee51e07937 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -65,7 +65,7 @@ public: void _q_reformatBlocks(int from, int charsRemoved, int charsAdded); void reformatBlocks(int from, int charsRemoved, int charsAdded); - void reformatBlock(const QTextBlock &block); + void reformatBlock(const QTextBlock &block, int from, int charsRemoved, int charsAdded); inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) { inReformatBlocks = true; @@ -84,14 +84,26 @@ public: q_func()->rehighlight(); } - void applyFormatChanges(); + void applyFormatChanges(int from, int charsRemoved, int charsAdded); QVector<QTextCharFormat> formatChanges; QTextBlock currentBlock; bool rehighlightPending; bool inReformatBlocks; }; -void SyntaxHighlighterPrivate::applyFormatChanges() +static bool adjustRange(QTextLayout::FormatRange &range, int from, int charsRemoved, int charsAdded) { + + if (range.start >= from) { + range.start += charsAdded - charsRemoved; + return true; + } else if (range.start + range.length > from) { + range.length += charsAdded - charsRemoved; + return true; + } + return false; +} + +void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, int charsAdded) { bool formatsChanged = false; @@ -101,11 +113,17 @@ void SyntaxHighlighterPrivate::applyFormatChanges() const int preeditAreaStart = layout->preeditAreaPosition(); const int preeditAreaLength = layout->preeditAreaText().length(); + bool doAdjustRange = currentBlock.contains(from); if (preeditAreaLength != 0) { QList<QTextLayout::FormatRange>::Iterator it = ranges.begin(); while (it != ranges.end()) { - if (it->start >= preeditAreaStart + if (it->format.property(QTextFormat::UserProperty).toBool()) { + if (doAdjustRange) + formatsChanged = adjustRange(*it, from - currentBlock.position(), charsRemoved, charsAdded) + || formatsChanged; + ++it; + } else if (it->start >= preeditAreaStart && it->start + it->length <= preeditAreaStart + preeditAreaLength) { ++it; } else { @@ -114,8 +132,18 @@ void SyntaxHighlighterPrivate::applyFormatChanges() } } } else if (!ranges.isEmpty()) { - ranges.clear(); - formatsChanged = true; + QList<QTextLayout::FormatRange>::Iterator it = ranges.begin(); + while (it != ranges.end()) { + if (it->format.property(QTextFormat::UserProperty).toBool()) { + if (doAdjustRange) + formatsChanged = adjustRange(*it, from - currentBlock.position(), charsRemoved, charsAdded) + || formatsChanged; + ++it; + } else { + it = ranges.erase(it); + formatsChanged = true; + } + } } QTextCharFormat emptyFormat; @@ -201,7 +229,7 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) { const int stateBeforeHighlight = block.userState(); - reformatBlock(block); + reformatBlock(block, from, charsRemoved, charsAdded); forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight); @@ -211,7 +239,7 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch formatChanges.clear(); } -void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block) +void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block, int from, int charsRemoved, int charsAdded) { Q_Q(SyntaxHighlighter); @@ -221,7 +249,7 @@ void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block) formatChanges.fill(QTextCharFormat(), block.length() - 1); q->highlightBlock(block.text()); - applyFormatChanges(); + applyFormatChanges(from, charsRemoved, charsAdded); currentBlock = QTextBlock(); } @@ -659,4 +687,57 @@ QTextBlock SyntaxHighlighter::currentBlock() const return d->currentBlock; } +void SyntaxHighlighter::setExtraAdditionalFormats(const QTextBlock& block, + const QList<QTextLayout::FormatRange> &formats) +{ + +// qDebug() << "setAdditionalFormats() on block" << block.blockNumber(); +// for (int i = 0; i < overrides.count(); ++i) +// qDebug() << " from " << overrides.at(i).start << "length" +// << overrides.at(i).length +// << "color:" << overrides.at(i).format.foreground().color(); + Q_D(SyntaxHighlighter); + + if (block.layout() == 0) + return; + + QList<QTextLayout::FormatRange> all = block.layout()->additionalFormats(); + + bool modified = false; + + int skip = 0; + + QList<QTextLayout::FormatRange>::Iterator it = all.begin(); + while (it != all.end()) { + if (it->format.property(QTextFormat::UserProperty).toBool()) { + if (skip < formats.size() + && it->start == formats.at(skip).start + && it->length == formats.at(skip).length) { + ++skip; + ++it; + } else { + it = all.erase(it); + modified = true; + } + } else { + ++it; + } + } + + if (!modified && skip == formats.length()) + return; // skip'em all + + for (int i = skip; i < formats.length(); ++i) { + QTextLayout::FormatRange range = formats.at(i); + range.format.setProperty(QTextFormat::UserProperty, true); + all.append(range); + } + + bool wasInReformatBlocks = d->inReformatBlocks; + d->inReformatBlocks = true; + block.layout()->setAdditionalFormats(all); + document()->markContentsDirty(block.position(), block.length()-1); + d->inReformatBlocks = wasInReformatBlocks; +} + #include "moc_syntaxhighlighter.cpp" diff --git a/src/plugins/texteditor/syntaxhighlighter.h b/src/plugins/texteditor/syntaxhighlighter.h index aadbfb46d2831a913aa5a8973d809e78da2e4505..5b6722b5a34dcb60d72d31e3f1a5803ea669b2a4 100644 --- a/src/plugins/texteditor/syntaxhighlighter.h +++ b/src/plugins/texteditor/syntaxhighlighter.h @@ -46,6 +46,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qobject.h> #include <QtGui/qtextobject.h> +#include <QtGui/QTextLayout> QT_BEGIN_NAMESPACE class QTextDocument; @@ -74,6 +75,8 @@ public: void setDocument(QTextDocument *doc); QTextDocument *document() const; + void setExtraAdditionalFormats(const QTextBlock& block, const QList<QTextLayout::FormatRange> &formats); + public Q_SLOTS: void rehighlight(); void rehighlightBlock(const QTextBlock &block);