forked from qt-creator/qt-creator
qmljseditor: Improve speed of QML/JS Editor for large files
avoid using extra selections for warnings folding them into the normal semantic update. Extra selections impose a relatively large overhead (and need expensive text cursor operations). Unlike C++ Qml warnings are continuosly recomputed in the current file of the editor, but not listed in the issue panel, unless one explicitly triggers the qml checks. Using the normal sematic update for warnings avoids QTextCursor operations, and uses batched applies. Unfortunately getting the tooltips from the additional formats instead of using the extra selections requires private API, so Ranges are also stored separately. Change-log: [Qml/JS Support] Improved speed of QML/JS Editor for large files with lots of warnings. Change-Id: I1f996231ef35d7cd77a79af58dbae2098fbbc83e Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Kai Koehne <kai.koehne@digia.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
@@ -546,6 +546,15 @@ int QmlJSTextEditorWidget::editorRevision() const
|
|||||||
return document()->revision();
|
return document()->revision();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<QTextLayout::FormatRange> QmlJSTextEditorWidget::diagnosticRanges() const
|
||||||
|
{
|
||||||
|
// this exist mainly because getting the tooltip from the additional formats
|
||||||
|
// requires the use of private api (you have to extract it from
|
||||||
|
// cursor.block().layout()->specialInfo.addFormatIndex (for the .format through .formats.at()),
|
||||||
|
// and use .addFormat to get the range). So a separate bookkeeping is used.
|
||||||
|
return m_diagnosticRanges;
|
||||||
|
}
|
||||||
|
|
||||||
bool QmlJSTextEditorWidget::isSemanticInfoOutdated() const
|
bool QmlJSTextEditorWidget::isSemanticInfoOutdated() const
|
||||||
{
|
{
|
||||||
if (m_semanticInfo.revision() != editorRevision())
|
if (m_semanticInfo.revision() != editorRevision())
|
||||||
@@ -637,44 +646,6 @@ static void appendExtraSelectionsForMessages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendExtraSelectionsForMessages(
|
|
||||||
QList<QTextEdit::ExtraSelection> *selections,
|
|
||||||
const QList<StaticAnalysis::Message> &messages,
|
|
||||||
const QTextDocument *document)
|
|
||||||
{
|
|
||||||
foreach (const StaticAnalysis::Message &d, messages) {
|
|
||||||
const int line = d.location.startLine;
|
|
||||||
const int column = qMax(1U, d.location.startColumn);
|
|
||||||
|
|
||||||
QTextEdit::ExtraSelection sel;
|
|
||||||
QTextCursor c(document->findBlockByNumber(line - 1));
|
|
||||||
sel.cursor = c;
|
|
||||||
|
|
||||||
sel.cursor.setPosition(c.position() + column - 1);
|
|
||||||
|
|
||||||
if (d.location.length == 0) {
|
|
||||||
if (sel.cursor.atBlockEnd())
|
|
||||||
sel.cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
|
|
||||||
else
|
|
||||||
sel.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
|
||||||
} else {
|
|
||||||
sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, d.location.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d.severity == StaticAnalysis::Warning || d.severity == StaticAnalysis::MaybeWarning)
|
|
||||||
sel.format.setUnderlineColor(Qt::darkYellow);
|
|
||||||
else if (d.severity == StaticAnalysis::Error || d.severity == StaticAnalysis::MaybeError)
|
|
||||||
sel.format.setUnderlineColor(Qt::red);
|
|
||||||
else if (d.severity == StaticAnalysis::Hint)
|
|
||||||
sel.format.setUnderlineColor(Qt::darkGreen);
|
|
||||||
|
|
||||||
sel.format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
|
||||||
sel.format.setToolTip(d.message);
|
|
||||||
|
|
||||||
selections->append(sel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlJSTextEditorWidget::onDocumentUpdated(QmlJS::Document::Ptr doc)
|
void QmlJSTextEditorWidget::onDocumentUpdated(QmlJS::Document::Ptr doc)
|
||||||
{
|
{
|
||||||
if (editorDocument()->fileName() != doc->fileName())
|
if (editorDocument()->fileName() != doc->fileName())
|
||||||
@@ -695,6 +666,7 @@ void QmlJSTextEditorWidget::onDocumentUpdated(QmlJS::Document::Ptr doc)
|
|||||||
// got a correctly parsed (or recovered) file.
|
// got a correctly parsed (or recovered) file.
|
||||||
m_futureSemanticInfoRevision = doc->editorRevision();
|
m_futureSemanticInfoRevision = doc->editorRevision();
|
||||||
m_semanticInfoUpdater->update(doc, m_modelManager->snapshot());
|
m_semanticInfoUpdater->update(doc, m_modelManager->snapshot());
|
||||||
|
setExtraSelections(CodeWarningsSelection, QList<QTextEdit::ExtraSelection>());
|
||||||
} else {
|
} else {
|
||||||
// show parsing errors
|
// show parsing errors
|
||||||
QList<QTextEdit::ExtraSelection> selections;
|
QList<QTextEdit::ExtraSelection> selections;
|
||||||
@@ -1368,15 +1340,8 @@ void QmlJSTextEditorWidget::acceptNewSemanticInfo(const SemanticInfo &semanticIn
|
|||||||
// update outline
|
// update outline
|
||||||
m_updateOutlineTimer->start();
|
m_updateOutlineTimer->start();
|
||||||
|
|
||||||
// update warning/error extra selections
|
|
||||||
QList<QTextEdit::ExtraSelection> selections;
|
|
||||||
appendExtraSelectionsForMessages(&selections, doc->diagnosticMessages(), document());
|
|
||||||
appendExtraSelectionsForMessages(&selections, m_semanticInfo.semanticMessages, document());
|
|
||||||
appendExtraSelectionsForMessages(&selections, m_semanticInfo.staticAnalysisMessages, document());
|
|
||||||
setExtraSelections(CodeWarningsSelection, selections);
|
|
||||||
|
|
||||||
if (Core::EditorManager::currentEditor() == editor())
|
if (Core::EditorManager::currentEditor() == editor())
|
||||||
m_semanticHighlighter->rerun(m_semanticInfo.scopeChain());
|
m_semanticHighlighter->rerun(m_semanticInfo);
|
||||||
|
|
||||||
emit semanticInfoUpdated();
|
emit semanticInfoUpdated();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
|
#include <QTextLayout>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
@@ -105,6 +107,7 @@ public:
|
|||||||
QmlJSTools::SemanticInfo semanticInfo() const;
|
QmlJSTools::SemanticInfo semanticInfo() const;
|
||||||
bool isSemanticInfoOutdated() const;
|
bool isSemanticInfoOutdated() const;
|
||||||
int editorRevision() const;
|
int editorRevision() const;
|
||||||
|
QVector<QTextLayout::FormatRange> diagnosticRanges() const;
|
||||||
|
|
||||||
Internal::QmlOutlineModel *outlineModel() const;
|
Internal::QmlOutlineModel *outlineModel() const;
|
||||||
QModelIndex outlineModelIndex();
|
QModelIndex outlineModelIndex();
|
||||||
@@ -113,7 +116,6 @@ public:
|
|||||||
|
|
||||||
TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
|
TextEditor::IAssistInterface *createAssistInterface(TextEditor::AssistKind assistKind,
|
||||||
TextEditor::AssistReason reason) const;
|
TextEditor::AssistReason reason) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void setTabSettings(const TextEditor::TabSettings &ts);
|
virtual void setTabSettings(const TextEditor::TabSettings &ts);
|
||||||
void reparseDocument();
|
void reparseDocument();
|
||||||
@@ -192,6 +194,7 @@ private:
|
|||||||
int m_futureSemanticInfoRevision;
|
int m_futureSemanticInfoRevision;
|
||||||
|
|
||||||
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
|
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
|
||||||
|
QVector<QTextLayout::FormatRange> m_diagnosticRanges;
|
||||||
|
|
||||||
QmlJS::IContextPane *m_contextPane;
|
QmlJS::IContextPane *m_contextPane;
|
||||||
int m_oldCursorPosition;
|
int m_oldCursorPosition;
|
||||||
|
|||||||
@@ -258,6 +258,12 @@ bool HoverHandler::matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditorWidget *qm
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (const QTextLayout::FormatRange &range, qmlEditor->diagnosticRanges()) {
|
||||||
|
if (pos >= range.start && pos < range.start+range.length) {
|
||||||
|
setToolTip(range.format.toolTip());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include <qmljs/qmljsutils.h>
|
#include <qmljs/qmljsutils.h>
|
||||||
#include <qmljs/parser/qmljsast_p.h>
|
#include <qmljs/parser/qmljsast_p.h>
|
||||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||||
|
#include <qmljs/qmljsstaticanalysismessage.h>
|
||||||
#include <texteditor/syntaxhighlighter.h>
|
#include <texteditor/syntaxhighlighter.h>
|
||||||
#include <texteditor/basetextdocument.h>
|
#include <texteditor/basetextdocument.h>
|
||||||
#include <texteditor/texteditorconstants.h>
|
#include <texteditor/texteditorconstants.h>
|
||||||
@@ -189,10 +190,15 @@ class CollectionTask :
|
|||||||
protected Visitor
|
protected Visitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CollectionTask(const ScopeChain &scopeChain)
|
CollectionTask(const QmlJSTools::SemanticInfo &semanticInfo,
|
||||||
: m_scopeChain(scopeChain)
|
SemanticHighlighter &semanticHighlighter)
|
||||||
|
: m_semanticInfo(semanticInfo)
|
||||||
|
, m_semanticHighlighter(semanticHighlighter)
|
||||||
|
, m_scopeChain(semanticInfo.scopeChain())
|
||||||
, m_scopeBuilder(&m_scopeChain)
|
, m_scopeBuilder(&m_scopeChain)
|
||||||
, m_lineOfLastUse(0)
|
, m_lineOfLastUse(0)
|
||||||
|
, m_nextExtraFormat(SemanticHighlighter::Max)
|
||||||
|
, m_currentDelayedUse(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -347,12 +353,102 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addMessages(QList<QmlJS::DiagnosticMessage> messages,
|
||||||
|
const Document::Ptr &doc)
|
||||||
|
{
|
||||||
|
foreach (const DiagnosticMessage &d, messages) {
|
||||||
|
int line = d.loc.startLine;
|
||||||
|
int column = qMax(1U, d.loc.startColumn);
|
||||||
|
int length = d.loc.length;
|
||||||
|
int begin = d.loc.begin();
|
||||||
|
|
||||||
|
if (d.loc.length == 0) {
|
||||||
|
QString source(doc->source());
|
||||||
|
int end = begin;
|
||||||
|
if (begin == source.size() || source.at(begin) == QLatin1Char('\n')
|
||||||
|
|| source.at(begin) == QLatin1Char('\r')) {
|
||||||
|
while (begin > end - column && !source.at(--begin).isSpace()) { }
|
||||||
|
} else {
|
||||||
|
while (end < source.size() && source.at(++end).isLetterOrNumber()) { }
|
||||||
|
}
|
||||||
|
column += begin - d.loc.begin();
|
||||||
|
length = end-begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCharFormat format;
|
||||||
|
if (d.isWarning())
|
||||||
|
format.setUnderlineColor(Qt::darkYellow);
|
||||||
|
else
|
||||||
|
format.setUnderlineColor(Qt::red);
|
||||||
|
|
||||||
|
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||||
|
format.setToolTip(d.message);
|
||||||
|
|
||||||
|
collectRanges(begin, length, format);
|
||||||
|
addDelayedUse(SemanticHighlighter::Use(line, column, length, addFormat(format)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMessages(const QList<QmlJS::StaticAnalysis::Message> &messages,
|
||||||
|
const Document::Ptr &doc)
|
||||||
|
{
|
||||||
|
foreach (const QmlJS::StaticAnalysis::Message &d, messages) {
|
||||||
|
int line = d.location.startLine;
|
||||||
|
int column = qMax(1U, d.location.startColumn);
|
||||||
|
int length = d.location.length;
|
||||||
|
int begin = d.location.begin();
|
||||||
|
|
||||||
|
if (d.location.length == 0) {
|
||||||
|
QString source(doc->source());
|
||||||
|
int end = begin;
|
||||||
|
if (begin == source.size() || source.at(begin) == QLatin1Char('\n')
|
||||||
|
|| source.at(begin) == QLatin1Char('\r')) {
|
||||||
|
while (begin > end - column && !source.at(--begin).isSpace()) { }
|
||||||
|
} else {
|
||||||
|
while (end < source.size() && source.at(++end).isLetterOrNumber()) { }
|
||||||
|
}
|
||||||
|
column += begin - d.location.begin();
|
||||||
|
length = end-begin;
|
||||||
|
}
|
||||||
|
QTextCharFormat format;
|
||||||
|
if (d.severity == StaticAnalysis::Warning || d.severity == StaticAnalysis::MaybeWarning)
|
||||||
|
format.setUnderlineColor(Qt::darkYellow);
|
||||||
|
else if (d.severity == StaticAnalysis::Error || d.severity == StaticAnalysis::MaybeError)
|
||||||
|
format.setUnderlineColor(Qt::red);
|
||||||
|
else if (d.severity == StaticAnalysis::Hint)
|
||||||
|
format.setUnderlineColor(Qt::darkGreen);
|
||||||
|
|
||||||
|
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||||
|
format.setToolTip(d.message);
|
||||||
|
|
||||||
|
collectRanges(begin, length, format);
|
||||||
|
addDelayedUse(SemanticHighlighter::Use(line, column, length, addFormat(format)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
int nMessages = m_scopeChain.document()->diagnosticMessages().size()
|
||||||
|
+ m_semanticInfo.semanticMessages.size()
|
||||||
|
+ m_semanticInfo.staticAnalysisMessages.size();
|
||||||
|
m_delayedUses.reserve(nMessages);
|
||||||
|
m_diagnosticRanges.reserve(nMessages);
|
||||||
|
m_extraFormats.reserve(nMessages);
|
||||||
|
addMessages(m_scopeChain.document()->diagnosticMessages(), m_scopeChain.document());
|
||||||
|
addMessages(m_semanticInfo.semanticMessages, m_semanticInfo.document);
|
||||||
|
addMessages(m_semanticInfo.staticAnalysisMessages, m_semanticInfo.document);
|
||||||
|
|
||||||
|
qSort(m_delayedUses.begin(), m_delayedUses.end(), sortByLinePredicate);
|
||||||
|
m_currentDelayedUse = 0;
|
||||||
|
|
||||||
|
m_semanticHighlighter.reportMessagesInfo(m_diagnosticRanges, m_extraFormats);
|
||||||
|
|
||||||
Node *root = m_scopeChain.document()->ast();
|
Node *root = m_scopeChain.document()->ast();
|
||||||
m_stateNames = CollectStateNames(m_scopeChain)(root);
|
m_stateNames = CollectStateNames(m_scopeChain)(root);
|
||||||
accept(root);
|
accept(root);
|
||||||
|
while (m_currentDelayedUse < m_delayedUses.size())
|
||||||
|
m_uses.append(m_delayedUses.value(m_currentDelayedUse++));
|
||||||
flush();
|
flush();
|
||||||
reportFinished();
|
reportFinished();
|
||||||
}
|
}
|
||||||
@@ -366,6 +462,10 @@ private:
|
|||||||
|
|
||||||
void addUse(const SemanticHighlighter::Use &use)
|
void addUse(const SemanticHighlighter::Use &use)
|
||||||
{
|
{
|
||||||
|
while (m_currentDelayedUse < m_delayedUses.size()
|
||||||
|
&& m_delayedUses.value(m_currentDelayedUse).line < use.line)
|
||||||
|
m_uses.append(m_delayedUses.value(m_currentDelayedUse++));
|
||||||
|
|
||||||
if (m_uses.size() >= chunkSize) {
|
if (m_uses.size() >= chunkSize) {
|
||||||
if (use.line > m_lineOfLastUse)
|
if (use.line > m_lineOfLastUse)
|
||||||
flush();
|
flush();
|
||||||
@@ -375,6 +475,26 @@ private:
|
|||||||
m_uses.append(use);
|
m_uses.append(use);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addDelayedUse(const SemanticHighlighter::Use &use)
|
||||||
|
{
|
||||||
|
m_delayedUses.append(use);
|
||||||
|
}
|
||||||
|
|
||||||
|
int addFormat(const QTextCharFormat &format)
|
||||||
|
{
|
||||||
|
int res = m_nextExtraFormat++;
|
||||||
|
m_extraFormats.insert(res, format);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collectRanges(int start, int length, const QTextCharFormat &format) {
|
||||||
|
QTextLayout::FormatRange range;
|
||||||
|
range.start = start;
|
||||||
|
range.length = length;
|
||||||
|
range.format = format;
|
||||||
|
m_diagnosticRanges.append(range);
|
||||||
|
}
|
||||||
|
|
||||||
static bool sortByLinePredicate(const SemanticHighlighter::Use &lhs, const SemanticHighlighter::Use &rhs)
|
static bool sortByLinePredicate(const SemanticHighlighter::Use &lhs, const SemanticHighlighter::Use &rhs)
|
||||||
{
|
{
|
||||||
return lhs.line < rhs.line;
|
return lhs.line < rhs.line;
|
||||||
@@ -393,11 +513,18 @@ private:
|
|||||||
m_uses.reserve(chunkSize);
|
m_uses.reserve(chunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QmlJSTools::SemanticInfo &m_semanticInfo;
|
||||||
|
SemanticHighlighter &m_semanticHighlighter;
|
||||||
ScopeChain m_scopeChain;
|
ScopeChain m_scopeChain;
|
||||||
ScopeBuilder m_scopeBuilder;
|
ScopeBuilder m_scopeBuilder;
|
||||||
QStringList m_stateNames;
|
QStringList m_stateNames;
|
||||||
QVector<SemanticHighlighter::Use> m_uses;
|
QVector<SemanticHighlighter::Use> m_uses;
|
||||||
unsigned m_lineOfLastUse;
|
unsigned m_lineOfLastUse;
|
||||||
|
QVector<SemanticHighlighter::Use> m_delayedUses;
|
||||||
|
int m_nextExtraFormat;
|
||||||
|
int m_currentDelayedUse;
|
||||||
|
QHash<int, QTextCharFormat> m_extraFormats;
|
||||||
|
QVector<QTextLayout::FormatRange> m_diagnosticRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@@ -413,13 +540,13 @@ SemanticHighlighter::SemanticHighlighter(QmlJSTextEditorWidget *editor)
|
|||||||
this, SLOT(finished()));
|
this, SLOT(finished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SemanticHighlighter::rerun(const ScopeChain &scopeChain)
|
void SemanticHighlighter::rerun(const QmlJSTools::SemanticInfo &semanticInfo)
|
||||||
{
|
{
|
||||||
m_watcher.cancel();
|
m_watcher.cancel();
|
||||||
|
|
||||||
// this does not simply use QtConcurrentRun because we want a low-priority future
|
// this does not simply use QtConcurrentRun because we want a low-priority future
|
||||||
// the thread pool deletes the task when it is done
|
// the thread pool deletes the task when it is done
|
||||||
CollectionTask::Future f = (new CollectionTask(scopeChain))->start(QThread::LowestPriority);
|
CollectionTask::Future f = (new CollectionTask(semanticInfo, *this))->start(QThread::LowestPriority);
|
||||||
m_startRevision = m_editor->editorRevision();
|
m_startRevision = m_editor->editorRevision();
|
||||||
m_watcher.setFuture(f);
|
m_watcher.setFuture(f);
|
||||||
}
|
}
|
||||||
@@ -442,7 +569,7 @@ void SemanticHighlighter::applyResults(int from, int to)
|
|||||||
QTC_ASSERT(highlighter, return);
|
QTC_ASSERT(highlighter, return);
|
||||||
|
|
||||||
TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
|
TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
|
||||||
highlighter, m_watcher.future(), from, to, m_formats);
|
highlighter, m_watcher.future(), from, to, m_extraFormats);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SemanticHighlighter::finished()
|
void SemanticHighlighter::finished()
|
||||||
@@ -456,6 +583,7 @@ void SemanticHighlighter::finished()
|
|||||||
QTC_ASSERT(baseTextDocument, return);
|
QTC_ASSERT(baseTextDocument, return);
|
||||||
TextEditor::SyntaxHighlighter *highlighter = qobject_cast<TextEditor::SyntaxHighlighter *>(baseTextDocument->syntaxHighlighter());
|
TextEditor::SyntaxHighlighter *highlighter = qobject_cast<TextEditor::SyntaxHighlighter *>(baseTextDocument->syntaxHighlighter());
|
||||||
QTC_ASSERT(highlighter, return);
|
QTC_ASSERT(highlighter, return);
|
||||||
|
m_editor->m_diagnosticRanges = m_diagnosticRanges;
|
||||||
|
|
||||||
TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
|
TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
|
||||||
highlighter, m_watcher.future());
|
highlighter, m_watcher.future());
|
||||||
@@ -477,6 +605,18 @@ void SemanticHighlighter::updateFontSettings(const TextEditor::FontSettings &fon
|
|||||||
m_formats[FieldType] = fontSettings.toTextCharFormat(TextEditor::C_FIELD);
|
m_formats[FieldType] = fontSettings.toTextCharFormat(TextEditor::C_FIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SemanticHighlighter::reportMessagesInfo(const QVector<QTextLayout::FormatRange> &diagnosticRanges,
|
||||||
|
const QHash<int,QTextCharFormat> &formats)
|
||||||
|
|
||||||
|
{
|
||||||
|
// tricky usage of m_extraFormats and diagnosticMessages we call this in another thread...
|
||||||
|
// but will use them only after a signal sent by that same thread, maybe we should transfer
|
||||||
|
// them more explicitly
|
||||||
|
m_extraFormats = formats;
|
||||||
|
m_extraFormats.unite(m_formats);
|
||||||
|
m_diagnosticRanges = diagnosticRanges;
|
||||||
|
}
|
||||||
|
|
||||||
int SemanticHighlighter::startRevision() const
|
int SemanticHighlighter::startRevision() const
|
||||||
{
|
{
|
||||||
return m_startRevision;
|
return m_startRevision;
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include <texteditor/semantichighlighter.h>
|
#include <texteditor/semantichighlighter.h>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
#include <QTextLayout>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
namespace QmlJS {
|
namespace QmlJS {
|
||||||
class ScopeChain;
|
class ScopeChain;
|
||||||
@@ -44,6 +46,10 @@ namespace TextEditor {
|
|||||||
class FontSettings;
|
class FontSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace QmlJSTools {
|
||||||
|
class SemanticInfo;
|
||||||
|
}
|
||||||
|
|
||||||
namespace QmlJSEditor {
|
namespace QmlJSEditor {
|
||||||
|
|
||||||
class QmlJSTextEditorWidget;
|
class QmlJSTextEditorWidget;
|
||||||
@@ -68,19 +74,22 @@ public:
|
|||||||
JsGlobalType, // in global scope
|
JsGlobalType, // in global scope
|
||||||
LocalStateNameType, // name of a state in the current file
|
LocalStateNameType, // name of a state in the current file
|
||||||
BindingNameType, // name on the left hand side of a binding
|
BindingNameType, // name on the left hand side of a binding
|
||||||
FieldType // member of an object
|
FieldType, // member of an object
|
||||||
|
Max // number of the last used value (to generate the warning formats)
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TextEditor::SemanticHighlighter::Result Use;
|
typedef TextEditor::SemanticHighlighter::Result Use;
|
||||||
|
|
||||||
SemanticHighlighter(QmlJSTextEditorWidget *editor);
|
SemanticHighlighter(QmlJSTextEditorWidget *editor);
|
||||||
|
|
||||||
void rerun(const QmlJS::ScopeChain &scopeChain);
|
void rerun(const QmlJSTools::SemanticInfo &scopeChain);
|
||||||
void cancel();
|
void cancel();
|
||||||
|
|
||||||
int startRevision() const;
|
int startRevision() const;
|
||||||
|
|
||||||
void updateFontSettings(const TextEditor::FontSettings &fontSettings);
|
void updateFontSettings(const TextEditor::FontSettings &fontSettings);
|
||||||
|
void reportMessagesInfo(const QVector<QTextLayout::FormatRange> &diagnosticMessages,
|
||||||
|
const QHash<int,QTextCharFormat> &formats);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void applyResults(int from, int to);
|
void applyResults(int from, int to);
|
||||||
@@ -91,6 +100,8 @@ private:
|
|||||||
QmlJSTextEditorWidget *m_editor;
|
QmlJSTextEditorWidget *m_editor;
|
||||||
int m_startRevision;
|
int m_startRevision;
|
||||||
QHash<int, QTextCharFormat> m_formats;
|
QHash<int, QTextCharFormat> m_formats;
|
||||||
|
QHash<int, QTextCharFormat> m_extraFormats;
|
||||||
|
QVector<QTextLayout::FormatRange> m_diagnosticRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
Reference in New Issue
Block a user