Convert semantic highlighter to use additional formats

instead of extra selections. This requires a recent
version of Qt 4.7, the beta 2 will not do.

Done-with: Roberto Raggi
This commit is contained in:
mae
2010-07-13 14:37:31 +02:00
parent b421d9c007
commit 72bb7c5c11
7 changed files with 185 additions and 65 deletions

View File

@@ -56,6 +56,22 @@ public:
typedef QFuture<Use> Future; typedef QFuture<Use> Future;
static Future go(Document::Ptr doc, const LookupContext &context); 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: protected:
using ASTVisitor::visit; using ASTVisitor::visit;
using ASTVisitor::endVisit; using ASTVisitor::endVisit;

View File

@@ -129,47 +129,6 @@ static QList<QTextEdit::ExtraSelection> createSelections(QTextDocument *document
return selections; 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 { namespace {
class OverviewTreeView : public QTreeView class OverviewTreeView : public QTreeView
@@ -643,8 +602,10 @@ CPPEditor::CPPEditor(QWidget *parent)
this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr))); this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
} }
m_highlighteRevision = 0; m_highlightRevision = 0;
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(highlightTypeUsages())); m_nextHighlightBlockNumber = 0;
connect(&m_highlightWatcher, SIGNAL(resultsReadyAt(int,int)), SLOT(highlightTypeUsages(int,int)));
connect(&m_highlightWatcher, SIGNAL(finished()), SLOT(finishTypeUsages()));
} }
CPPEditor::~CPPEditor() CPPEditor::~CPPEditor()
@@ -1139,8 +1100,9 @@ void CPPEditor::updateOutlineToolTip()
void CPPEditor::updateUses() void CPPEditor::updateUses()
{ {
if (editorRevision() != m_highlightRevision)
m_highlighter.cancel();
m_updateUsesTimer->start(); m_updateUsesTimer->start();
m_highlighter.cancel();
} }
void CPPEditor::updateUsesNow() void CPPEditor::updateUsesNow()
@@ -1151,18 +1113,76 @@ void CPPEditor::updateUsesNow()
semanticRehighlight(); semanticRehighlight();
} }
void CPPEditor::highlightTypeUsages() void CPPEditor::highlightTypeUsages(int from, int to)
{ {
if (editorRevision() != m_highlighteRevision) if (editorRevision() != m_highlightRevision)
return; // outdated return; // outdated
else if (m_highlighter.isCanceled()) else if (m_highlighter.isCanceled())
return; // aborted return; // aborted
const QList<SemanticInfo::Use> typeUsages = m_highlighter.results(); CppHighlighter *highlighter = qobject_cast<CppHighlighter*>(baseTextDocument()->syntaxHighlighter());
setExtraSelections(TypeSelection, createSelections(document(), typeUsages, m_typeFormat)); 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_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;
QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);
while (b.isValid()) {
highlighter->setExtraAdditionalFormats(b, QList<QTextLayout::FormatRange>());
b = b.next();
++m_nextHighlightBlockNumber;
}
}
void CPPEditor::switchDeclarationDefinition() void CPPEditor::switchDeclarationDefinition()
{ {
if (! m_modelManager) if (! m_modelManager)
@@ -1959,7 +1979,8 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
LookupContext context(semanticInfo.doc, semanticInfo.snapshot); LookupContext context(semanticInfo.doc, semanticInfo.snapshot);
CheckUndefinedSymbols::Future f = CheckUndefinedSymbols::go(semanticInfo.doc, context); CheckUndefinedSymbols::Future f = CheckUndefinedSymbols::go(semanticInfo.doc, context);
m_highlighter = f; m_highlighter = f;
m_highlighteRevision = semanticInfo.revision; m_highlightRevision = semanticInfo.revision;
m_nextHighlightBlockNumber = 0;
m_highlightWatcher.setFuture(m_highlighter); m_highlightWatcher.setFuture(m_highlighter);
} }
@@ -1970,6 +1991,7 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
#endif #endif
} }
setExtraSelections(UnusedSymbolSelection, unusedSelections); setExtraSelections(UnusedSymbolSelection, unusedSelections);
if (! m_renameSelections.isEmpty()) if (! m_renameSelections.isEmpty())

View File

@@ -233,7 +233,8 @@ private Q_SLOTS:
void semanticRehighlight(); void semanticRehighlight();
void updateSemanticInfo(const CppEditor::Internal::SemanticInfo &semanticInfo); void updateSemanticInfo(const CppEditor::Internal::SemanticInfo &semanticInfo);
void highlightTypeUsages(); void highlightTypeUsages(int from, int to);
void finishTypeUsages();
void performQuickFix(int index); void performQuickFix(int index);
@@ -300,7 +301,8 @@ private:
QFuture<SemanticInfo::Use> m_highlighter; QFuture<SemanticInfo::Use> m_highlighter;
QFutureWatcher<SemanticInfo::Use> m_highlightWatcher; 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;
}; };

View File

@@ -4063,10 +4063,8 @@ int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor)
while (block.isValid() && ts.onlySpace(block.text())) while (block.isValid() && ts.onlySpace(block.text()))
block = block.next(); block = block.next();
if (block.isValid() if (block.isValid()
&& ts.indentationColumn(block.text()) > indentation) { && ts.indentationColumn(block.text()) > indentation)
qDebug() << "indentation check failed" << indentation << ts.indentationColumn(block.next().text());
return 0; return 0;
}
} }
int pos = cursor.position(); int pos = cursor.position();
@@ -4664,7 +4662,6 @@ void BaseTextEditor::maybeClearSomeExtraSelections(const QTextCursor &cursor)
if (cursor.selectionEnd() - cursor.selectionStart() < smallSelectionSize) if (cursor.selectionEnd() - cursor.selectionStart() < smallSelectionSize)
return; return;
d->m_extraSelections[TypeSelection].clear();
d->m_extraSelections[UndefinedSymbolSelection].clear(); d->m_extraSelections[UndefinedSymbolSelection].clear();
d->m_extraSelections[ObjCSelection].clear(); d->m_extraSelections[ObjCSelection].clear();
d->m_extraSelections[CodeWarningsSelection].clear(); d->m_extraSelections[CodeWarningsSelection].clear();

View File

@@ -349,7 +349,6 @@ public:
FakeVimSelection, FakeVimSelection,
OtherSelection, OtherSelection,
SnippetPlaceholderSelection, SnippetPlaceholderSelection,
TypeSelection,
ObjCSelection, ObjCSelection,
NExtraSelectionKinds NExtraSelectionKinds
}; };

View File

@@ -65,7 +65,7 @@ public:
void _q_reformatBlocks(int from, int charsRemoved, int charsAdded); void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
void 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) { inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) {
inReformatBlocks = true; inReformatBlocks = true;
@@ -84,14 +84,26 @@ public:
q_func()->rehighlight(); q_func()->rehighlight();
} }
void applyFormatChanges(); void applyFormatChanges(int from, int charsRemoved, int charsAdded);
QVector<QTextCharFormat> formatChanges; QVector<QTextCharFormat> formatChanges;
QTextBlock currentBlock; QTextBlock currentBlock;
bool rehighlightPending; bool rehighlightPending;
bool inReformatBlocks; 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; bool formatsChanged = false;
@@ -101,11 +113,17 @@ void SyntaxHighlighterPrivate::applyFormatChanges()
const int preeditAreaStart = layout->preeditAreaPosition(); const int preeditAreaStart = layout->preeditAreaPosition();
const int preeditAreaLength = layout->preeditAreaText().length(); const int preeditAreaLength = layout->preeditAreaText().length();
bool doAdjustRange = currentBlock.contains(from);
if (preeditAreaLength != 0) { if (preeditAreaLength != 0) {
QList<QTextLayout::FormatRange>::Iterator it = ranges.begin(); QList<QTextLayout::FormatRange>::Iterator it = ranges.begin();
while (it != ranges.end()) { 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->start + it->length <= preeditAreaStart + preeditAreaLength) {
++it; ++it;
} else { } else {
@@ -114,8 +132,18 @@ void SyntaxHighlighterPrivate::applyFormatChanges()
} }
} }
} else if (!ranges.isEmpty()) { } else if (!ranges.isEmpty()) {
ranges.clear(); QList<QTextLayout::FormatRange>::Iterator it = ranges.begin();
formatsChanged = true; 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; QTextCharFormat emptyFormat;
@@ -201,7 +229,7 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch
while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) { while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
const int stateBeforeHighlight = block.userState(); const int stateBeforeHighlight = block.userState();
reformatBlock(block); reformatBlock(block, from, charsRemoved, charsAdded);
forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight); forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);
@@ -211,7 +239,7 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch
formatChanges.clear(); formatChanges.clear();
} }
void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block) void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block, int from, int charsRemoved, int charsAdded)
{ {
Q_Q(SyntaxHighlighter); Q_Q(SyntaxHighlighter);
@@ -221,7 +249,7 @@ void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block)
formatChanges.fill(QTextCharFormat(), block.length() - 1); formatChanges.fill(QTextCharFormat(), block.length() - 1);
q->highlightBlock(block.text()); q->highlightBlock(block.text());
applyFormatChanges(); applyFormatChanges(from, charsRemoved, charsAdded);
currentBlock = QTextBlock(); currentBlock = QTextBlock();
} }
@@ -659,4 +687,57 @@ QTextBlock SyntaxHighlighter::currentBlock() const
return d->currentBlock; 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" #include "moc_syntaxhighlighter.cpp"

View File

@@ -46,6 +46,7 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtCore/qobject.h> #include <QtCore/qobject.h>
#include <QtGui/qtextobject.h> #include <QtGui/qtextobject.h>
#include <QtGui/QTextLayout>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QTextDocument; class QTextDocument;
@@ -74,6 +75,8 @@ public:
void setDocument(QTextDocument *doc); void setDocument(QTextDocument *doc);
QTextDocument *document() const; QTextDocument *document() const;
void setExtraAdditionalFormats(const QTextBlock& block, const QList<QTextLayout::FormatRange> &formats);
public Q_SLOTS: public Q_SLOTS:
void rehighlight(); void rehighlight();
void rehighlightBlock(const QTextBlock &block); void rehighlightBlock(const QTextBlock &block);