forked from qt-creator/qt-creator
SyntaxHighlighter: Move generic highlighter to separate thread
Adds a full copy of KSyntaxHighlighting::Repository class to the Highlighter class, enabling the relocation of the Highlighter class to a separate thread. This adjustment ensures that all Definitions come from the copy of the repository, making them immutable from external code. The "reload Definition" function stays supported, as triggering it results in the recreation of the highlighter for the document, thereby reconstructing the Repository class. Change-Id: Id7a4d865228c7e7e20e4770601a3fde55b8a6513 Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -68,15 +68,24 @@ TextStyle categoryForTextStyle(int style)
|
|||||||
return C_TEXT;
|
return C_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
Highlighter::Highlighter()
|
Highlighter::Highlighter(const QString &definitionFilesPath)
|
||||||
|
: m_repository(new KSyntaxHighlighting::Repository())
|
||||||
{
|
{
|
||||||
|
m_repository->addCustomSearchPath(definitionFilesPath);
|
||||||
|
const Utils::FilePath dir = Core::ICore::resourcePath("generic-highlighter/syntax");
|
||||||
|
if (dir.exists())
|
||||||
|
m_repository->addCustomSearchPath(dir.parentDir().path());
|
||||||
|
m_repository->reload();
|
||||||
|
|
||||||
setTextFormatCategories(QMetaEnum::fromType<KSyntaxHighlighting::Theme::TextStyle>().keyCount(),
|
setTextFormatCategories(QMetaEnum::fromType<KSyntaxHighlighting::Theme::TextStyle>().keyCount(),
|
||||||
&categoryForTextStyle);
|
&categoryForTextStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition Highlighter::getDefinition()
|
Highlighter::~Highlighter() = default;
|
||||||
|
|
||||||
|
void Highlighter::setDefinitionName(const QString &name)
|
||||||
{
|
{
|
||||||
return definition();
|
KSyntaxHighlighting::AbstractHighlighter::setDefinition(m_repository->definitionForName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isOpeningParenthesis(QChar c)
|
static bool isOpeningParenthesis(QChar c)
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <KSyntaxHighlighting/AbstractHighlighter>
|
#include <KSyntaxHighlighting/AbstractHighlighter>
|
||||||
|
|
||||||
|
namespace KSyntaxHighlighting { class Repository; }
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
class TextDocument;
|
class TextDocument;
|
||||||
|
|
||||||
@@ -17,14 +19,18 @@ class Highlighter : public SyntaxHighlighter, public KSyntaxHighlighting::Abstra
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_INTERFACES(KSyntaxHighlighting::AbstractHighlighter)
|
Q_INTERFACES(KSyntaxHighlighting::AbstractHighlighter)
|
||||||
public:
|
public:
|
||||||
Highlighter();
|
Highlighter(const QString &definitionFilesPath);
|
||||||
|
~Highlighter() override;
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition getDefinition() override;
|
void setDefinitionName(const QString &name) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void highlightBlock(const QString &text) override;
|
void highlightBlock(const QString &text) override;
|
||||||
void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override;
|
void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override;
|
||||||
void applyFolding(int offset, int length, KSyntaxHighlighting::FoldingRegion region) override;
|
void applyFolding(int offset, int length, KSyntaxHighlighting::FoldingRegion region) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<KSyntaxHighlighting::Repository> m_repository;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace TextEditor
|
} // namespace TextEditor
|
||||||
|
@@ -156,9 +156,9 @@ void GenerigHighlighterTests::testHighlight()
|
|||||||
QTextBlock block = m_editor->textDocument()->document()->findBlockByNumber(blockNumber);
|
QTextBlock block = m_editor->textDocument()->document()->findBlockByNumber(blockNumber);
|
||||||
QVERIFY(block.isValid());
|
QVERIFY(block.isValid());
|
||||||
|
|
||||||
|
QTRY_COMPARE(block.layout()->formats().size(), formatRanges.size());
|
||||||
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
||||||
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
||||||
QCOMPARE(actualFormats.size(), formatRanges.size());
|
|
||||||
for (int i = 0; i < formatRanges.size(); ++i)
|
for (int i = 0; i < formatRanges.size(); ++i)
|
||||||
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
||||||
}
|
}
|
||||||
@@ -178,9 +178,9 @@ void GenerigHighlighterTests::testChange()
|
|||||||
|
|
||||||
const FormatRanges formatRanges = {{0, 4, toFormat(C_VISUAL_WHITESPACE)},
|
const FormatRanges formatRanges = {{0, 4, toFormat(C_VISUAL_WHITESPACE)},
|
||||||
{4, 1, toFormat(C_TEXT)}};
|
{4, 1, toFormat(C_TEXT)}};
|
||||||
|
QTRY_COMPARE(block.layout()->formats().size(), formatRanges.size());
|
||||||
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
||||||
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
||||||
QCOMPARE(actualFormats.size(), formatRanges.size());
|
|
||||||
for (int i = 0; i < formatRanges.size(); ++i)
|
for (int i = 0; i < formatRanges.size(); ++i)
|
||||||
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
||||||
}
|
}
|
||||||
@@ -204,9 +204,9 @@ void GenerigHighlighterTests::testPreeditText()
|
|||||||
{14, 1, toFormat(C_VISUAL_WHITESPACE)},
|
{14, 1, toFormat(C_VISUAL_WHITESPACE)},
|
||||||
{15, 6, toFormat(C_STRING)},
|
{15, 6, toFormat(C_STRING)},
|
||||||
{21, 1, toFormat(C_FUNCTION)}};
|
{21, 1, toFormat(C_FUNCTION)}};
|
||||||
|
QTRY_COMPARE(block.layout()->formats().size(), formatRanges.size());
|
||||||
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
const QList<QTextLayout::FormatRange> actualFormats = block.layout()->formats();
|
||||||
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
// full hash calculation for QTextCharFormat fails so just check the important entries of format
|
||||||
QCOMPARE(actualFormats.size(), formatRanges.size());
|
|
||||||
for (int i = 0; i < formatRanges.size(); ++i)
|
for (int i = 0; i < formatRanges.size(); ++i)
|
||||||
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
compareFormats(actualFormats.at(i), formatRanges.at(i));
|
||||||
}
|
}
|
||||||
|
@@ -112,7 +112,7 @@ public:
|
|||||||
void setExtraFormats(const QTextBlock &block, const QList<QTextLayout::FormatRange> &formats);
|
void setExtraFormats(const QTextBlock &block, const QList<QTextLayout::FormatRange> &formats);
|
||||||
virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting
|
virtual void setLanguageFeaturesFlags(unsigned int /*flags*/) {}; // needed for CppHighlighting
|
||||||
virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter
|
virtual void setEnabled(bool /*enabled*/) {}; // needed for DiffAndLogHighlighter
|
||||||
virtual KSyntaxHighlighting::Definition getDefinition() { return {}; }
|
virtual void setDefinitionName(const QString & /*definitionName*/) {} // needed for Highlighter
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void rehighlight();
|
virtual void rehighlight();
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "syntaxhighlighterrunner.h"
|
#include "syntaxhighlighterrunner.h"
|
||||||
|
|
||||||
#include <texteditor/fontsettings.h>
|
#include "fontsettings.h"
|
||||||
#include <texteditor/textdocumentlayout.h>
|
#include "textdocumentlayout.h"
|
||||||
|
|
||||||
#include <utils/textutils.h>
|
#include <utils/textutils.h>
|
||||||
|
|
||||||
@@ -81,7 +81,10 @@ public:
|
|||||||
m_highlighter->rehighlight();
|
m_highlighter->rehighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition getDefinition() { return m_highlighter->getDefinition(); }
|
void setDefinitionName(const QString &name)
|
||||||
|
{
|
||||||
|
return m_highlighter->setDefinitionName(name);
|
||||||
|
}
|
||||||
|
|
||||||
void setLanguageFeaturesFlags(unsigned int flags)
|
void setLanguageFeaturesFlags(unsigned int flags)
|
||||||
{
|
{
|
||||||
@@ -195,9 +198,18 @@ void BaseSyntaxHighlighterRunner::rehighlight()
|
|||||||
QMetaObject::invokeMethod(d.get(), [this] { d->rehighlight(); });
|
QMetaObject::invokeMethod(d.get(), [this] { d->rehighlight(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition BaseSyntaxHighlighterRunner::getDefinition()
|
QString BaseSyntaxHighlighterRunner::definitionName()
|
||||||
{
|
{
|
||||||
return d->getDefinition();
|
return m_definitionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseSyntaxHighlighterRunner::setDefinitionName(const QString &name)
|
||||||
|
{
|
||||||
|
if (name.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_definitionName = name;
|
||||||
|
QMetaObject::invokeMethod(d.get(), [this, name] { d->setDefinitionName(name); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------- ThreadedSyntaxHighlighterRunner ------------------------------------
|
// --------------------------- ThreadedSyntaxHighlighterRunner ------------------------------------
|
||||||
@@ -240,16 +252,6 @@ ThreadedSyntaxHighlighterRunner::~ThreadedSyntaxHighlighterRunner()
|
|||||||
m_thread.wait();
|
m_thread.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition ThreadedSyntaxHighlighterRunner::getDefinition()
|
|
||||||
{
|
|
||||||
KSyntaxHighlighting::Definition definition;
|
|
||||||
QMetaObject::invokeMethod(
|
|
||||||
d.get(),
|
|
||||||
[this, &definition] { definition = d->getDefinition(); },
|
|
||||||
Qt::BlockingQueuedConnection);
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace TextEditor
|
} // namespace TextEditor
|
||||||
|
|
||||||
#include "syntaxhighlighterrunner.moc"
|
#include "syntaxhighlighterrunner.moc"
|
||||||
|
@@ -39,7 +39,8 @@ public:
|
|||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
void rehighlight();
|
void rehighlight();
|
||||||
|
|
||||||
virtual KSyntaxHighlighting::Definition getDefinition();
|
QString definitionName();
|
||||||
|
void setDefinitionName(const QString &name);
|
||||||
|
|
||||||
QTextDocument *document() const { return m_document; }
|
QTextDocument *document() const { return m_document; }
|
||||||
SyntaxHighLighterCreator creator() const { return m_creator; }
|
SyntaxHighLighterCreator creator() const { return m_creator; }
|
||||||
@@ -56,6 +57,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SyntaxHighLighterCreator m_creator;
|
SyntaxHighLighterCreator m_creator;
|
||||||
|
QString m_definitionName;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT ThreadedSyntaxHighlighterRunner : public BaseSyntaxHighlighterRunner
|
class TEXTEDITOR_EXPORT ThreadedSyntaxHighlighterRunner : public BaseSyntaxHighlighterRunner
|
||||||
@@ -65,8 +67,6 @@ public:
|
|||||||
QTextDocument *document);
|
QTextDocument *document);
|
||||||
~ThreadedSyntaxHighlighterRunner();
|
~ThreadedSyntaxHighlighterRunner();
|
||||||
|
|
||||||
KSyntaxHighlighting::Definition getDefinition() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThread m_thread;
|
QThread m_thread;
|
||||||
};
|
};
|
||||||
|
@@ -1933,7 +1933,7 @@ void TextEditorWidgetPrivate::foldLicenseHeader()
|
|||||||
QStringList docMarker;
|
QStringList docMarker;
|
||||||
HighlighterHelper::Definition def;
|
HighlighterHelper::Definition def;
|
||||||
if (BaseSyntaxHighlighterRunner *highlighter = q->textDocument()->syntaxHighlighterRunner())
|
if (BaseSyntaxHighlighterRunner *highlighter = q->textDocument()->syntaxHighlighterRunner())
|
||||||
def = highlighter->getDefinition();
|
def = HighlighterHelper::definitionForName(highlighter->definitionName());
|
||||||
|
|
||||||
if (def.isValid()) {
|
if (def.isValid()) {
|
||||||
for (const QString &marker :
|
for (const QString &marker :
|
||||||
@@ -3709,12 +3709,12 @@ void TextEditorWidgetPrivate::configureGenericHighlighter(
|
|||||||
q->setCodeFoldingSupported(false);
|
q->setCodeFoldingSupported(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_document->resetSyntaxHighlighter([definition] {
|
const QString definitionFilesPath
|
||||||
auto highlighter = new Highlighter();
|
= TextEditorSettings::highlighterSettings().definitionFilesPath().toString();
|
||||||
if (definition.isValid())
|
m_document->resetSyntaxHighlighter([definitionFilesPath] {
|
||||||
highlighter->setDefinition(definition);
|
return new Highlighter(definitionFilesPath);
|
||||||
return highlighter;
|
});
|
||||||
}, false);
|
m_document->syntaxHighlighterRunner()->setDefinitionName(definition.name());
|
||||||
|
|
||||||
m_document->setFontSettings(TextEditorSettings::fontSettings());
|
m_document->setFontSettings(TextEditorSettings::fontSettings());
|
||||||
}
|
}
|
||||||
@@ -3740,7 +3740,7 @@ void TextEditorWidgetPrivate::setupFromDefinition(const KSyntaxHighlighting::Def
|
|||||||
KSyntaxHighlighting::Definition TextEditorWidgetPrivate::currentDefinition()
|
KSyntaxHighlighting::Definition TextEditorWidgetPrivate::currentDefinition()
|
||||||
{
|
{
|
||||||
if (BaseSyntaxHighlighterRunner *highlighter = m_document->syntaxHighlighterRunner())
|
if (BaseSyntaxHighlighterRunner *highlighter = m_document->syntaxHighlighterRunner())
|
||||||
return highlighter->getDefinition();
|
return HighlighterHelper::definitionForName(highlighter->definitionName());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user