aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp')
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp729
1 files changed, 384 insertions, 345 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
index ae95a6b235..e2cca6da71 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
@@ -1,28 +1,11 @@
/*
- Copyright (C) 2016 Volker Krause <vkrause@kde.org>
- Copyright (C) 2018 Dominik Haumann <dhaumann@kde.org>
- Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
+ SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
+ SPDX-FileCopyrightText: 2018 Dominik Haumann <dhaumann@kde.org>
+ SPDX-FileCopyrightText: 2018 Christoph Cullmann <cullmann@kde.org>
+ SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
+ SPDX-License-Identifier: MIT
+*/
#include "definition.h"
#include "definition_p.h"
@@ -31,66 +14,51 @@
#include "context_p.h"
#include "format.h"
#include "format_p.h"
+#include "highlightingdata_p.hpp"
+#include "ksyntaxhighlighting_logging.h"
+#include "ksyntaxhighlighting_version.h"
#include "repository.h"
#include "repository_p.h"
#include "rule_p.h"
-#include "ksyntaxhighlighting_logging.h"
-#include "ksyntaxhighlighting_version.h"
+#include "worddelimiters_p.h"
#include "xml_p.h"
+#include <QCborMap>
#include <QCoreApplication>
-#include <QDebug>
#include <QFile>
-#include <QHash>
-#include <QJsonObject>
-#include <QStringList>
-#include <QVector>
#include <QXmlStreamReader>
#include <algorithm>
+#include <atomic>
using namespace KSyntaxHighlighting;
DefinitionData::DefinitionData()
- : wordDelimiters(QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~")) // must be sorted!
+ : wordDelimiters()
, wordWrapDelimiters(wordDelimiters)
{
}
-DefinitionData::~DefinitionData()
-{
- qDeleteAll(contexts);
-}
-
-DefinitionData* DefinitionData::get(const Definition &def)
-{
- return def.d.get();
-}
-
-Definition::Definition() :
- d(new DefinitionData)
-{
-}
+DefinitionData::~DefinitionData() = default;
-Definition::Definition(const Definition &other) :
- d(other.d)
+Definition::Definition()
+ : d(std::make_shared<DefinitionData>())
{
d->q = *this;
}
-Definition::Definition(const std::shared_ptr<DefinitionData> &dd) :
- d(dd)
-{
-}
-
-Definition::~Definition()
-{
-}
+Definition::Definition(Definition &&other) noexcept = default;
+Definition::Definition(const Definition &) = default;
+Definition::~Definition() = default;
+Definition &Definition::operator=(Definition &&other) noexcept = default;
+Definition &Definition::operator=(const Definition &) = default;
-Definition& Definition::operator=(const Definition &rhs)
+Definition::Definition(std::shared_ptr<DefinitionData> &&dd)
+ : d(std::move(dd))
{
- d = rhs.d;
- return *this;
+ if (!d) {
+ Definition().d.swap(d);
+ }
}
bool Definition::operator==(const Definition &other) const
@@ -98,7 +66,7 @@ bool Definition::operator==(const Definition &other) const
return d->fileName == other.d->fileName;
}
-bool Definition::operator!=(const Definition& other) const
+bool Definition::operator!=(const Definition &other) const
{
return d->fileName != other.d->fileName;
}
@@ -120,7 +88,10 @@ QString Definition::name() const
QString Definition::translatedName() const
{
- return QCoreApplication::instance()->translate("Language", d->name.toUtf8().constData());
+ if (d->translatedName.isEmpty()) {
+ d->translatedName = QCoreApplication::instance()->translate("Language", d->nameUtf8.isEmpty() ? d->name.toUtf8().constData() : d->nameUtf8.constData());
+ }
+ return d->translatedName;
}
QString Definition::section() const
@@ -130,15 +101,19 @@ QString Definition::section() const
QString Definition::translatedSection() const
{
- return QCoreApplication::instance()->translate("Language Section", d->section.toUtf8().constData());
+ if (d->translatedSection.isEmpty()) {
+ d->translatedSection = QCoreApplication::instance()->translate("Language Section",
+ d->sectionUtf8.isEmpty() ? d->section.toUtf8().constData() : d->sectionUtf8.constData());
+ }
+ return d->translatedSection;
}
-QVector<QString> Definition::mimeTypes() const
+QList<QString> Definition::mimeTypes() const
{
return d->mimetypes;
}
-QVector<QString> Definition::extensions() const
+QList<QString> Definition::extensions() const
{
return d->extensions;
}
@@ -181,13 +156,13 @@ QString Definition::license() const
bool Definition::isWordDelimiter(QChar c) const
{
d->load();
- return d->isWordDelimiter(c);
+ return d->wordDelimiters.contains(c);
}
bool Definition::isWordWrapDelimiter(QChar c) const
{
d->load();
- return std::binary_search(d->wordWrapDelimiters.constBegin(), d->wordWrapDelimiters.constEnd(), c);
+ return d->wordWrapDelimiters.contains(c);
}
bool Definition::foldingEnabled() const
@@ -227,69 +202,60 @@ QStringList Definition::keywordLists() const
return d->keywordLists.keys();
}
-QStringList Definition::keywordList(const QString& name) const
+QStringList Definition::keywordList(const QString &name) const
{
d->load(DefinitionData::OnlyKeywords(true));
const auto list = d->keywordList(name);
return list ? list->keywords() : QStringList();
}
-QVector<Format> Definition::formats() const
+bool Definition::setKeywordList(const QString &name, const QStringList &content)
+{
+ d->load(DefinitionData::OnlyKeywords(true));
+ KeywordList *list = d->keywordList(name);
+ if (list) {
+ list->setKeywordList(content);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QList<Format> Definition::formats() const
{
d->load();
// sort formats so that the order matches the order of the itemDatas in the xml files.
- auto formatList = QVector<Format>::fromList(d->formats.values());
- std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs){
+ auto formatList = d->formats.values();
+ std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format &lhs, const KSyntaxHighlighting::Format &rhs) {
return lhs.id() < rhs.id();
});
return formatList;
}
-QVector<Definition> Definition::includedDefinitions() const
+QList<Definition> Definition::includedDefinitions() const
{
d->load();
// init worklist and result used as guard with this definition
- QVector<Definition> queue{*this};
- QVector<Definition> definitions{*this};
- while (!queue.isEmpty()) {
- // Iterate all context rules to find associated Definitions. This will
- // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch.
- const auto definition = queue.takeLast();
- for (const auto & context : qAsConst(definition.d->contexts)) {
- // handle context switch attributes of this context itself
- for (const auto switchContext : {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) {
- if (switchContext) {
- if (!definitions.contains(switchContext->definition())) {
- queue.push_back(switchContext->definition());
- definitions.push_back(switchContext->definition());
- }
- }
- }
-
- // handle the embedded rules
- for (const auto &rule : context->rules()) {
- // handle include rules like inclusion
- if (!definitions.contains(rule->definition())) {
- queue.push_back(rule->definition());
- definitions.push_back(rule->definition());
- }
-
- // handle context switch context inclusion
- if (auto switchContext = rule->context().context()) {
- if (!definitions.contains(switchContext->definition())) {
- queue.push_back(switchContext->definition());
- definitions.push_back(switchContext->definition());
- }
- }
+ QList<const DefinitionData *> queue{d.get()};
+ QList<Definition> definitions{*this};
+ while (!queue.empty()) {
+ const auto *def = queue.back();
+ queue.pop_back();
+ for (const auto &defRef : std::as_const(def->immediateIncludedDefinitions)) {
+ const auto definition = defRef.definition();
+ if (!definitions.contains(definition)) {
+ definitions.push_back(definition);
+ queue.push_back(definition.d.get());
}
}
}
// remove the 1st entry, since it is this Definition
- definitions.pop_front();
+ definitions.front() = std::move(definitions.back());
+ definitions.pop_back();
return definitions;
}
@@ -309,75 +275,82 @@ CommentPosition Definition::singleLineCommentPosition() const
QPair<QString, QString> Definition::multiLineCommentMarker() const
{
d->load();
- return { d->multiLineCommentStartMarker, d->multiLineCommentEndMarker };
+ return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker};
}
-QVector<QPair<QChar, QString>> Definition::characterEncodings() const
+QList<QPair<QChar, QString>> Definition::characterEncodings() const
{
d->load();
return d->characterEncodings;
}
-Context* DefinitionData::initialContext() const
+Context *DefinitionData::initialContext()
{
- Q_ASSERT(!contexts.isEmpty());
- return contexts.first();
+ Q_ASSERT(!contexts.empty());
+ return &contexts.front();
}
-Context* DefinitionData::contextByName(const QString& wantedName) const
+Context *DefinitionData::contextByName(QStringView wantedName)
{
- for (const auto context : contexts) {
- if (context->name() == wantedName)
- return context;
+ for (auto &context : contexts) {
+ if (context.name() == wantedName) {
+ return &context;
+ }
}
return nullptr;
}
-KeywordList *DefinitionData::keywordList(const QString& wantedName)
+KeywordList *DefinitionData::keywordList(const QString &wantedName)
{
auto it = keywordLists.find(wantedName);
return (it == keywordLists.end()) ? nullptr : &it.value();
}
-bool DefinitionData::isWordDelimiter(QChar c) const
-{
- return std::binary_search(wordDelimiters.constBegin(), wordDelimiters.constEnd(), c);
-}
-
-Format DefinitionData::formatByName(const QString& wantedName) const
+Format DefinitionData::formatByName(const QString &wantedName) const
{
const auto it = formats.constFind(wantedName);
- if (it != formats.constEnd())
+ if (it != formats.constEnd()) {
return it.value();
+ }
return Format();
}
bool DefinitionData::isLoaded() const
{
- return !contexts.isEmpty();
+ return !contexts.empty();
+}
+
+namespace
+{
+std::atomic<uint64_t> definitionId{1};
}
bool DefinitionData::load(OnlyKeywords onlyKeywords)
{
- if (fileName.isEmpty())
+ if (fileName.isEmpty()) {
return false;
+ }
- if (isLoaded())
+ if (isLoaded()) {
return true;
+ }
- if (bool(onlyKeywords) && keywordIsLoaded)
+ if (bool(onlyKeywords) && keywordIsLoaded) {
return true;
+ }
QFile file(fileName);
- if (!file.open(QFile::ReadOnly))
+ if (!file.open(QFile::ReadOnly)) {
return false;
+ }
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
const auto token = reader.readNext();
- if (token != QXmlStreamReader::StartElement)
+ if (token != QXmlStreamReader::StartElement) {
continue;
+ }
if (reader.name() == QLatin1String("highlighting")) {
loadHighlighting(reader, onlyKeywords);
@@ -386,61 +359,79 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords)
}
}
- else if (reader.name() == QLatin1String("general"))
+ else if (reader.name() == QLatin1String("general")) {
loadGeneral(reader);
+ }
}
for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it) {
it->setCaseSensitivity(caseSensitive);
}
- for (const auto context : qAsConst(contexts)) {
- context->resolveContexts();
- context->resolveIncludes();
- context->resolveAttributeFormat();
- }
+ resolveContexts();
+
+ id = definitionId.fetch_add(1, std::memory_order_relaxed);
- Q_ASSERT(std::is_sorted(wordDelimiters.constBegin(), wordDelimiters.constEnd()));
return true;
}
void DefinitionData::clear()
{
// keep only name and repo, so we can re-lookup to make references persist over repo reloads
+ id = 0;
keywordLists.clear();
- qDeleteAll(contexts);
contexts.clear();
formats.clear();
+ contextDatas.clear();
+ immediateIncludedDefinitions.clear();
+ wordDelimiters = WordDelimiters();
+ wordWrapDelimiters = wordDelimiters;
+ keywordIsLoaded = false;
+ hasFoldingRegions = false;
+ indentationBasedFolding = false;
+ foldingIgnoreList.clear();
+ singleLineCommentMarker.clear();
+ singleLineCommentPosition = CommentPosition::StartOfLine;
+ multiLineCommentStartMarker.clear();
+ multiLineCommentEndMarker.clear();
+ characterEncodings.clear();
fileName.clear();
+ nameUtf8.clear();
+ translatedName.clear();
section.clear();
+ sectionUtf8.clear();
+ translatedSection.clear();
style.clear();
indenter.clear();
author.clear();
license.clear();
mimetypes.clear();
extensions.clear();
- wordDelimiters = QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~"); // must be sorted!
- wordWrapDelimiters = wordDelimiters;
caseSensitive = Qt::CaseSensitive;
version = 0.0f;
priority = 0;
hidden = false;
+
+ // purge our cache that is used to unify states
+ unify.clear();
}
-bool DefinitionData::loadMetaData(const QString& definitionFileName)
+bool DefinitionData::loadMetaData(const QString &definitionFileName)
{
fileName = definitionFileName;
QFile file(definitionFileName);
- if (!file.open(QFile::ReadOnly))
+ if (!file.open(QFile::ReadOnly)) {
return false;
+ }
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
const auto token = reader.readNext();
- if (token != QXmlStreamReader::StartElement)
+ if (token != QXmlStreamReader::StartElement) {
continue;
+ }
if (reader.name() == QLatin1String("language")) {
return loadLanguage(reader);
}
@@ -449,25 +440,26 @@ bool DefinitionData::loadMetaData(const QString& definitionFileName)
return false;
}
-bool DefinitionData::loadMetaData(const QString &file, const QJsonObject &obj)
+bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj)
{
- name = obj.value(QLatin1String("name")).toString();
- section = obj.value(QLatin1String("section")).toString();
- version = obj.value(QLatin1String("version")).toInt();
- priority = obj.value(QLatin1String("priority")).toInt();
- style = obj.value(QLatin1String("style")).toString();
- author = obj.value(QLatin1String("author")).toString();
- license = obj.value(QLatin1String("license")).toString();
+ name = obj.value(QLatin1String("name")).toString();
+ nameUtf8 = obj.value(QLatin1String("name")).toByteArray();
+ section = obj.value(QLatin1String("section")).toString();
+ sectionUtf8 = obj.value(QLatin1String("section")).toByteArray();
+ version = obj.value(QLatin1String("version")).toInteger();
+ priority = obj.value(QLatin1String("priority")).toInteger();
+ style = obj.value(QLatin1String("style")).toString();
+ author = obj.value(QLatin1String("author")).toString();
+ license = obj.value(QLatin1String("license")).toString();
indenter = obj.value(QLatin1String("indenter")).toString();
- hidden = obj.value(QLatin1String("hidden")).toBool();
+ hidden = obj.value(QLatin1String("hidden")).toBool();
fileName = file;
const auto exts = obj.value(QLatin1String("extensions")).toString();
- for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
- extensions.push_back(ext);
+ extensions = exts.split(QLatin1Char(';'), Qt::SkipEmptyParts);
+
const auto mts = obj.value(QLatin1String("mimetype")).toString();
- for (const auto &mt : mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
- mimetypes.push_back(mt);
+ mimetypes = mts.split(QLatin1Char(';'), Qt::SkipEmptyParts);
return true;
}
@@ -477,31 +469,35 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
Q_ASSERT(reader.name() == QLatin1String("language"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
- if (!checkKateVersion(reader.attributes().value(QStringLiteral("kateversion"))))
+ if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) {
return false;
+ }
- name = reader.attributes().value(QStringLiteral("name")).toString();
- section = reader.attributes().value(QStringLiteral("section")).toString();
+ name = reader.attributes().value(QLatin1String("name")).toString();
+ section = reader.attributes().value(QLatin1String("section")).toString();
// toFloat instead of toInt for backward compatibility with old Kate files
- version = reader.attributes().value(QStringLiteral("version")).toFloat();
- priority = reader.attributes().value(QStringLiteral("priority")).toInt();
- hidden = Xml::attrToBool(reader.attributes().value(QStringLiteral("hidden")));
- style = reader.attributes().value(QStringLiteral("style")).toString();
- indenter = reader.attributes().value(QStringLiteral("indenter")).toString();
- author = reader.attributes().value(QStringLiteral("author")).toString();
- license = reader.attributes().value(QStringLiteral("license")).toString();
- const auto exts = reader.attributes().value(QStringLiteral("extensions")).toString();
- for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
- extensions.push_back(ext);
- const auto mts = reader.attributes().value(QStringLiteral("mimetype")).toString();
- for (const auto &mt : mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
- mimetypes.push_back(mt);
- if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
- caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ version = reader.attributes().value(QLatin1String("version")).toFloat();
+ priority = reader.attributes().value(QLatin1String("priority")).toInt();
+ hidden = Xml::attrToBool(reader.attributes().value(QLatin1String("hidden")));
+ style = reader.attributes().value(QLatin1String("style")).toString();
+ indenter = reader.attributes().value(QLatin1String("indenter")).toString();
+ author = reader.attributes().value(QLatin1String("author")).toString();
+ license = reader.attributes().value(QLatin1String("license")).toString();
+ const auto exts = reader.attributes().value(QLatin1String("extensions"));
+ for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) {
+ extensions.push_back(ext.toString());
+ }
+ const auto mts = reader.attributes().value(QLatin1String("mimetype"));
+ for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) {
+ mimetypes.push_back(mt.toString());
+ }
+ if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) {
+ caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ }
return true;
}
-void DefinitionData::loadHighlighting(QXmlStreamReader& reader, OnlyKeywords onlyKeywords)
+void DefinitionData::loadHighlighting(QXmlStreamReader &reader, OnlyKeywords onlyKeywords)
{
Q_ASSERT(reader.name() == QLatin1String("highlighting"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -511,35 +507,34 @@ void DefinitionData::loadHighlighting(QXmlStreamReader& reader, OnlyKeywords onl
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("list")) {
- if (!keywordIsLoaded) {
- KeywordList keywords;
- keywords.load(reader);
- keywordLists.insert(keywords.name(), keywords);
- }
- else {
- reader.skipCurrentElement();
- reader.readNext(); // Skip </list>
- }
- } else if (bool(onlyKeywords)) {
- resolveIncludeKeywords();
- return;
- } else if (reader.name() == QLatin1String("contexts")) {
- resolveIncludeKeywords();
- loadContexts(reader);
- reader.readNext();
- } else if (reader.name() == QLatin1String("itemDatas")) {
- loadItemData(reader);
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("list")) {
+ if (!keywordIsLoaded) {
+ KeywordList keywords;
+ keywords.load(reader);
+ keywordLists.insert(keywords.name(), keywords);
} else {
- reader.readNext();
+ reader.skipCurrentElement();
+ reader.readNext(); // Skip </list>
}
- break;
- case QXmlStreamReader::EndElement:
+ } else if (bool(onlyKeywords)) {
+ resolveIncludeKeywords();
return;
- default:
+ } else if (reader.name() == QLatin1String("contexts")) {
+ resolveIncludeKeywords();
+ loadContexts(reader);
reader.readNext();
- break;
+ } else if (reader.name() == QLatin1String("itemDatas")) {
+ loadItemData(reader);
+ } else {
+ reader.readNext();
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -557,60 +552,95 @@ void DefinitionData::resolveIncludeKeywords()
}
}
-void DefinitionData::loadContexts(QXmlStreamReader& reader)
+void DefinitionData::loadContexts(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("contexts"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ contextDatas.reserve(32);
+
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("context")) {
- auto context = new Context;
- context->setDefinition(q);
- context->load(reader);
- contexts.push_back(context);
- }
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("context")) {
+ contextDatas.push_back(HighlightingContextData());
+ contextDatas.back().load(name, reader);
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadItemData(QXmlStreamReader& reader)
+void DefinitionData::resolveContexts()
+{
+ contexts.reserve(contextDatas.size());
+
+ /**
+ * Transform all HighlightingContextData to Context.
+ * This is necessary so that Context::resolveContexts() can find the referenced contexts.
+ */
+ for (const auto &contextData : std::as_const(contextDatas)) {
+ contexts.emplace_back(*this, contextData);
+ }
+
+ /**
+ * Resolves contexts and rules.
+ */
+ auto ctxIt = contexts.begin();
+ for (const auto &contextData : std::as_const(contextDatas)) {
+ ctxIt->resolveContexts(*this, contextData);
+ ++ctxIt;
+ }
+
+ /**
+ * To free the memory, constDatas is emptied because it is no longer used.
+ */
+ contextDatas.clear();
+ contextDatas.shrink_to_fit();
+
+ /**
+ * Resolved includeRules.
+ */
+ for (auto &context : contexts) {
+ context.resolveIncludes(*this);
+ }
+}
+
+void DefinitionData::loadItemData(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- if (reader.name() == QLatin1String("itemData")) {
- Format f;
- auto formatData = FormatPrivate::detachAndGet(f);
- formatData->definition = q;
- formatData->load(reader);
- formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
- formats.insert(f.name(), f);
- reader.readNext();
- }
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("itemData")) {
+ Format f;
+ auto formatData = FormatPrivate::detachAndGet(f);
+ formatData->definitionName = name;
+ formatData->load(reader);
+ formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
+ formats.insert(f.name(), f);
reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadGeneral(QXmlStreamReader& reader)
+void DefinitionData::loadGeneral(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("general"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -621,49 +651,50 @@ void DefinitionData::loadGeneral(QXmlStreamReader& reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
-
- if (reader.name() == QLatin1String("keywords")) {
- if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
- caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
-
- // adapt sorted wordDelimiters
- wordDelimiters += reader.attributes().value(QStringLiteral("additionalDeliminator"));
- std::sort(wordDelimiters.begin(), wordDelimiters.end());
- auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
- wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
- for (const auto c : reader.attributes().value(QLatin1String("weakDeliminator")))
- wordDelimiters.remove(c);
-
- // adaptWordWrapDelimiters, and sort
- wordWrapDelimiters = reader.attributes().value(QStringLiteral("wordWrapDeliminator")).toString();
- std::sort(wordWrapDelimiters.begin(), wordWrapDelimiters.end());
- if (wordWrapDelimiters.isEmpty())
- wordWrapDelimiters = wordDelimiters;
- } else if (reader.name() == QLatin1String("folding")) {
- if (reader.attributes().hasAttribute(QStringLiteral("indentationsensitive")))
- indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("indentationsensitive")));
- } else if (reader.name() == QLatin1String("emptyLines")) {
- loadFoldingIgnoreList(reader);
- } else if (reader.name() == QLatin1String("comments")) {
- loadComments(reader);
- } else if (reader.name() == QLatin1String("spellchecking")) {
- loadSpellchecking(reader);
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+
+ if (reader.name() == QLatin1String("keywords")) {
+ if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) {
+ caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ }
+
+ // adapt wordDelimiters
+ wordDelimiters.append(reader.attributes().value(QLatin1String("additionalDeliminator")));
+ wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator")));
+
+ // adapt WordWrapDelimiters
+ auto wordWrapDeliminatorAttr = reader.attributes().value(QLatin1String("wordWrapDeliminator"));
+ if (wordWrapDeliminatorAttr.isEmpty()) {
+ wordWrapDelimiters = wordDelimiters;
} else {
- reader.skipCurrentElement();
+ wordWrapDelimiters.append(wordWrapDeliminatorAttr);
}
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ } else if (reader.name() == QLatin1String("folding")) {
+ if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) {
+ indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("indentationsensitive")));
+ }
+ } else if (reader.name() == QLatin1String("emptyLines")) {
+ loadFoldingIgnoreList(reader);
+ } else if (reader.name() == QLatin1String("comments")) {
+ loadComments(reader);
+ } else if (reader.name() == QLatin1String("spellchecking")) {
+ loadSpellchecking(reader);
+ } else {
+ reader.skipCurrentElement();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0) {
+ return;
+ }
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -679,35 +710,36 @@ void DefinitionData::loadComments(QXmlStreamReader &reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("comment")) {
- const bool isSingleLine = reader.attributes().value(QStringLiteral("name")) == QStringLiteral("singleLine");
- if (isSingleLine) {
- singleLineCommentMarker = reader.attributes().value(QStringLiteral("start")).toString();
- const bool afterWhiteSpace = reader.attributes().value(QStringLiteral("position")).toString() == QStringLiteral("afterwhitespace");
- singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
- } else {
- multiLineCommentStartMarker = reader.attributes().value(QStringLiteral("start")).toString();
- multiLineCommentEndMarker = reader.attributes().value(QStringLiteral("end")).toString();
- }
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("comment")) {
+ const bool isSingleLine = reader.attributes().value(QLatin1String("name")) == QLatin1String("singleLine");
+ if (isSingleLine) {
+ singleLineCommentMarker = reader.attributes().value(QLatin1String("start")).toString();
+ const bool afterWhiteSpace = reader.attributes().value(QLatin1String("position")) == QLatin1String("afterwhitespace");
+ singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
+ } else {
+ multiLineCommentStartMarker = reader.attributes().value(QLatin1String("start")).toString();
+ multiLineCommentEndMarker = reader.attributes().value(QLatin1String("end")).toString();
}
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0) {
+ return;
+ }
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
-void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
+void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("emptyLines"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
@@ -718,22 +750,23 @@ void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("emptyLine")) {
- foldingIgnoreList << reader.attributes().value(QStringLiteral("regexpr")).toString();
- }
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("emptyLine")) {
+ foldingIgnoreList << reader.attributes().value(QLatin1String("regexpr")).toString();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0) {
+ return;
+ }
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
@@ -749,31 +782,32 @@ void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
while (!reader.atEnd()) {
switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- ++elementRefCounter;
- if (reader.name() == QLatin1String("encoding")) {
- const auto charRef = reader.attributes().value(QStringLiteral("char"));
- if (!charRef.isEmpty()) {
- const auto str = reader.attributes().value(QStringLiteral("string")).toString();
- characterEncodings.push_back({ charRef[0], str });
- }
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("encoding")) {
+ const auto charRef = reader.attributes().value(QLatin1String("char"));
+ if (!charRef.isEmpty()) {
+ const auto str = reader.attributes().value(QLatin1String("string"));
+ characterEncodings.push_back({charRef[0], str.toString()});
}
- reader.readNext();
- break;
- case QXmlStreamReader::EndElement:
- --elementRefCounter;
- if (elementRefCounter == 0)
- return;
- reader.readNext();
- break;
- default:
- reader.readNext();
- break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0) {
+ return;
+ }
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
}
}
}
-bool DefinitionData::checkKateVersion(const QStringRef& verStr)
+bool DefinitionData::checkKateVersion(QStringView verStr)
{
const auto idx = verStr.indexOf(QLatin1Char('.'));
if (idx <= 0) {
@@ -783,7 +817,7 @@ bool DefinitionData::checkKateVersion(const QStringRef& verStr)
const auto major = verStr.left(idx).toInt();
const auto minor = verStr.mid(idx + 1).toInt();
- if (major > SyntaxHighlighting_VERSION_MAJOR || (major == SyntaxHighlighting_VERSION_MAJOR && minor > SyntaxHighlighting_VERSION_MINOR)) {
+ if (major > KSYNTAXHIGHLIGHTING_VERSION_MAJOR || (major == KSYNTAXHIGHLIGHTING_VERSION_MAJOR && minor > KSYNTAXHIGHLIGHTING_VERSION_MINOR)) {
qCWarning(Log) << "Skipping" << fileName << "due to being too new, version:" << verStr;
return false;
}
@@ -797,20 +831,24 @@ quint16 DefinitionData::foldingRegionId(const QString &foldName)
return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
}
-DefinitionRef::DefinitionRef()
+void DefinitionData::addImmediateIncludedDefinition(const Definition &def)
{
+ if (get(def) != this) {
+ DefinitionRef defRef(def);
+ if (!immediateIncludedDefinitions.contains(defRef)) {
+ immediateIncludedDefinitions.push_back(std::move(defRef));
+ }
+ }
}
-DefinitionRef::DefinitionRef(const Definition &def) :
- d(def.d)
-{
-}
+DefinitionRef::DefinitionRef() = default;
-DefinitionRef::~DefinitionRef()
+DefinitionRef::DefinitionRef(const Definition &def) noexcept
+ : d(def.d)
{
}
-DefinitionRef& DefinitionRef::operator=(const Definition &def)
+DefinitionRef &DefinitionRef::operator=(const Definition &def) noexcept
{
d = def.d;
return *this;
@@ -818,16 +856,17 @@ DefinitionRef& DefinitionRef::operator=(const Definition &def)
Definition DefinitionRef::definition() const
{
- if (!d.expired())
- return Definition(d.lock());
- return Definition();
+ return Definition(d.lock());
}
bool DefinitionRef::operator==(const DefinitionRef &other) const
{
- if (d.expired() != other.d.expired()) {
- return false;
- }
+ return !d.owner_before(other.d) && !other.d.owner_before(d);
+}
- return d.expired() || d.lock().get() == other.d.lock().get();
+bool DefinitionRef::operator==(const Definition &other) const
+{
+ return !d.owner_before(other.d) && !other.d.owner_before(d);
}
+
+#include "moc_definition.cpp"