diff options
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp')
-rw-r--r-- | src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp | 729 |
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" |