10#include "definition.h"
11#include "definition_p.h"
16#include "highlightingdata_p.hpp"
17#include "ksyntaxhighlighting_logging.h"
18#include "ksyntaxhighlighting_version.h"
19#include "repository.h"
20#include "repository_p.h"
22#include "worddelimiters_p.h"
26#include <QCoreApplication>
28#include <QStringTokenizer>
29#include <QXmlStreamReader>
36DefinitionData::DefinitionData()
38 , wordWrapDelimiters(wordDelimiters)
42DefinitionData::~DefinitionData() =
default;
45 : d(std::make_shared<DefinitionData>())
63 return d->fileName == other.d->fileName;
68 return d->fileName != other.d->fileName;
73 return d->repo && !d->fileName.isEmpty() && !d->name.isEmpty();
88 return d->alternativeNames;
93 if (d->translatedName.isEmpty()) {
96 return d->translatedName;
106 if (d->translatedSection.isEmpty()) {
108 d->sectionUtf8.isEmpty() ? d->section.toUtf8().constData() : d->sectionUtf8.constData());
110 return d->translatedSection;
120 return d->extensions;
161 return d->wordDelimiters.contains(c);
167 return d->wordWrapDelimiters.contains(c);
172 if (d->foldingRegionsState == DefinitionData::FoldingRegionsState::Undetermined) {
176 return d->foldingRegionsState == DefinitionData::FoldingRegionsState::ContainsFoldingRegions || d->indentationBasedFolding;
182 return d->indentationBasedFolding;
188 return d->foldingIgnoreList;
193 d->load(DefinitionData::OnlyKeywords(
true));
194 return d->keywordLists.keys();
199 d->load(DefinitionData::OnlyKeywords(
true));
200 const auto list = d->keywordList(name);
206 d->load(DefinitionData::OnlyKeywords(
true));
207 KeywordList *list = d->keywordList(name);
209 list->setKeywordList(content);
221 auto formatList = d->formats.values();
223 return lhs.id() < rhs.id();
239 while (!queue.empty()) {
240 const auto *def = queue.back();
242 for (
const auto *defData : def->immediateIncludedDefinitions) {
243 auto pred = [defData](
const Definition &def) {
244 return DefinitionData::get(def) == defData;
246 if (std::find_if(definitions.
begin(), definitions.
end(), pred) == definitions.
end()) {
248 queue.push_back(defData);
254 definitions.
front() = std::move(definitions.
back());
264 return d->singleLineCommentMarker;
270 return d->singleLineCommentPosition;
276 return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker};
282 return d->characterEncodings;
285Context *DefinitionData::initialContext()
287 Q_ASSERT(!contexts.empty());
288 return &contexts.front();
291Context *DefinitionData::contextByName(
QStringView wantedName)
293 for (
auto &context : contexts) {
294 if (context.name() == wantedName) {
301KeywordList *DefinitionData::keywordList(
const QString &wantedName)
303 auto it = keywordLists.find(wantedName);
304 return (it == keywordLists.end()) ? nullptr : &it.value();
307Format DefinitionData::formatByName(QStringView wantedName)
const
309 const auto it = formats.constFind(wantedName);
310 if (it != formats.constEnd()) {
317bool DefinitionData::isLoaded()
const
319 return !contexts.empty();
324std::atomic<uint64_t> definitionId{1};
327bool DefinitionData::load(OnlyKeywords onlyKeywords)
333 if (fileName.isEmpty()) {
337 if (
bool(onlyKeywords) && keywordIsLoaded) {
341 QFile file(fileName);
346 QXmlStreamReader reader(&file);
347 while (!reader.atEnd()) {
348 const auto token = reader.readNext();
353 if (reader.name() == QLatin1String(
"highlighting")) {
354 loadHighlighting(reader, onlyKeywords);
355 if (
bool(onlyKeywords)) {
360 else if (reader.name() == QLatin1String(
"general")) {
365 for (
auto &kw : keywordLists) {
366 kw.setCaseSensitivity(caseSensitive);
371 id = definitionId.fetch_add(1, std::memory_order_relaxed);
376void DefinitionData::clear()
381 keywordLists.clear();
384 contextDatas.clear();
385 immediateIncludedDefinitions.clear();
386 wordDelimiters = WordDelimiters();
387 wordWrapDelimiters = wordDelimiters;
388 keywordIsLoaded =
false;
389 foldingRegionsState = FoldingRegionsState::Undetermined;
390 indentationBasedFolding =
false;
391 foldingIgnoreList.clear();
392 singleLineCommentMarker.clear();
394 multiLineCommentStartMarker.clear();
395 multiLineCommentEndMarker.clear();
396 characterEncodings.clear();
400 translatedName.clear();
403 translatedSection.clear();
419bool DefinitionData::loadMetaData(
const QString &definitionFileName)
421 fileName = definitionFileName;
423 QFile file(definitionFileName);
428 QXmlStreamReader reader(&file);
429 while (!reader.atEnd()) {
430 const auto token = reader.readNext();
434 if (reader.name() == QLatin1String(
"language")) {
435 return loadLanguage(reader);
442bool DefinitionData::loadMetaData(
const QString &file,
const QCborMap &obj)
457 hidden = obj.
value(QLatin1String(
"hidden")).
toBool();
460 const auto names = obj.
value(QLatin1String(
"alternativeNames")).
toString();
463 const auto exts = obj.
value(QLatin1String(
"extensions")).
toString();
466 const auto mts = obj.
value(QLatin1String(
"mimetype")).
toString();
472bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
474 Q_ASSERT(reader.
name() == QLatin1String(
"language"));
477 if (!checkKateVersion(reader.
attributes().
value(QLatin1String(
"kateversion")))) {
485 const auto names = reader.
attributes().
value(QLatin1String(
"alternativeNames"));
487 alternativeNames.push_back(n.toString());
493 hidden = Xml::attrToBool(reader.
attributes().
value(QLatin1String(
"hidden")));
498 const auto exts = reader.
attributes().
value(QLatin1String(
"extensions"));
500 extensions.push_back(ext.toString());
504 mimetypes.push_back(mt.toString());
512void DefinitionData::loadHighlighting(QXmlStreamReader &reader, OnlyKeywords onlyKeywords)
514 Q_ASSERT(reader.
name() == QLatin1String(
"highlighting"));
520 while (!reader.
atEnd()) {
523 if (reader.
name() == QLatin1String(
"list")) {
524 if (!keywordIsLoaded) {
525 KeywordList keywords;
526 keywords.load(reader);
527 keywordLists.insert(keywords.name(), keywords);
532 }
else if (
bool(onlyKeywords)) {
533 resolveIncludeKeywords();
535 }
else if (reader.
name() == QLatin1String(
"contexts")) {
536 resolveIncludeKeywords();
537 loadContexts(reader);
539 }
else if (reader.
name() == QLatin1String(
"itemDatas")) {
540 loadItemData(reader);
554void DefinitionData::resolveIncludeKeywords()
556 if (keywordIsLoaded) {
560 keywordIsLoaded =
true;
562 for (
auto &kw : keywordLists) {
563 kw.resolveIncludeKeywords(*
this);
567void DefinitionData::loadContexts(QXmlStreamReader &reader)
569 Q_ASSERT(reader.
name() == QLatin1String(
"contexts"));
572 contextDatas.reserve(32);
574 while (!reader.
atEnd()) {
577 if (reader.
name() == QLatin1String(
"context")) {
578 contextDatas.emplace_back().load(name, reader);
591void DefinitionData::resolveContexts()
593 contexts.reserve(contextDatas.size());
599 for (
const auto &contextData : std::as_const(contextDatas)) {
600 contexts.emplace_back(*
this, contextData);
606 auto ctxIt = contexts.begin();
607 for (
const auto &contextData : std::as_const(contextDatas)) {
608 ctxIt->resolveContexts(*
this, contextData);
615 contextDatas.clear();
616 contextDatas.shrink_to_fit();
621 for (
auto &context : contexts) {
622 context.resolveIncludes(*
this);
626 if (foldingRegionsState == FoldingRegionsState::Undetermined) {
627 foldingRegionsState = FoldingRegionsState::NoFoldingRegions;
631void DefinitionData::loadItemData(QXmlStreamReader &reader)
633 Q_ASSERT(reader.
name() == QLatin1String(
"itemDatas"));
636 while (!reader.
atEnd()) {
639 if (reader.
name() == QLatin1String(
"itemData")) {
641 auto formatData = FormatPrivate::detachAndGet(f);
642 formatData->definitionName =
name;
643 formatData->load(reader);
644 formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
659void DefinitionData::loadGeneral(QXmlStreamReader &reader)
661 Q_ASSERT(reader.
name() == QLatin1String(
"general"));
666 int elementRefCounter = 1;
668 while (!reader.
atEnd()) {
673 if (reader.
name() == QLatin1String(
"keywords")) {
679 wordDelimiters.append(reader.
attributes().
value(QLatin1String(
"additionalDeliminator")));
680 wordDelimiters.remove(reader.
attributes().
value(QLatin1String(
"weakDeliminator")));
683 auto wordWrapDeliminatorAttr = reader.
attributes().
value(QLatin1String(
"wordWrapDeliminator"));
684 if (wordWrapDeliminatorAttr.isEmpty()) {
685 wordWrapDelimiters = wordDelimiters;
687 wordWrapDelimiters.append(wordWrapDeliminatorAttr);
689 }
else if (reader.
name() == QLatin1String(
"folding")) {
691 indentationBasedFolding = Xml::attrToBool(reader.
attributes().
value(QLatin1String(
"indentationsensitive")));
693 }
else if (reader.
name() == QLatin1String(
"emptyLines")) {
694 loadFoldingIgnoreList(reader);
695 }
else if (reader.
name() == QLatin1String(
"comments")) {
696 loadComments(reader);
697 }
else if (reader.
name() == QLatin1String(
"spellchecking")) {
698 loadSpellchecking(reader);
706 if (elementRefCounter == 0) {
718void DefinitionData::loadComments(QXmlStreamReader &reader)
720 Q_ASSERT(reader.
name() == QLatin1String(
"comments"));
725 int elementRefCounter = 1;
727 while (!reader.
atEnd()) {
731 if (reader.
name() == QLatin1String(
"comment")) {
732 const bool isSingleLine = reader.
attributes().
value(QLatin1String(
"name")) == QLatin1String(
"singleLine");
735 const bool afterWhiteSpace = reader.
attributes().
value(QLatin1String(
"position")) == QLatin1String(
"afterwhitespace");
746 if (elementRefCounter == 0) {
758void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader)
760 Q_ASSERT(reader.
name() == QLatin1String(
"emptyLines"));
765 int elementRefCounter = 1;
767 while (!reader.
atEnd()) {
771 if (reader.
name() == QLatin1String(
"emptyLine")) {
778 if (elementRefCounter == 0) {
790void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
792 Q_ASSERT(reader.
name() == QLatin1String(
"spellchecking"));
797 int elementRefCounter = 1;
799 while (!reader.
atEnd()) {
803 if (reader.
name() == QLatin1String(
"encoding")) {
805 if (!charRef.isEmpty()) {
807 characterEncodings.push_back({charRef[0], str.toString()});
814 if (elementRefCounter == 0) {
826bool DefinitionData::checkKateVersion(QStringView verStr)
828 const auto idx = verStr.
indexOf(QLatin1Char(
'.'));
830 qCWarning(Log) <<
"Skipping" << fileName <<
"due to having no valid kateversion attribute:" << verStr;
836 if (major > KSYNTAXHIGHLIGHTING_VERSION_MAJOR || (major == KSYNTAXHIGHLIGHTING_VERSION_MAJOR && minor > KSYNTAXHIGHLIGHTING_VERSION_MINOR)) {
837 qCWarning(Log) <<
"Skipping" << fileName <<
"due to being too new, version:" << verStr;
844quint16 DefinitionData::foldingRegionId(
const QString &foldName)
846 foldingRegionsState = FoldingRegionsState::ContainsFoldingRegions;
847 return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
850DefinitionData::ResolvedContext DefinitionData::resolveIncludedContext(QStringView defName, QStringView contextName)
853 return {
this, contextByName(contextName)};
856 auto d = repo->definitionForName(defName.
toString());
858 auto *resolvedDef =
get(d);
859 if (resolvedDef !=
this) {
860 if (std::find(immediateIncludedDefinitions.begin(), immediateIncludedDefinitions.end(), resolvedDef) == immediateIncludedDefinitions.end()) {
861 immediateIncludedDefinitions.push_back(resolvedDef);
863 if (resolvedDef->foldingRegionsState == FoldingRegionsState::ContainsFoldingRegions) {
864 foldingRegionsState = FoldingRegionsState::ContainsFoldingRegions;
869 return {resolvedDef, resolvedDef->initialContext()};
871 return {resolvedDef, resolvedDef->contextByName(contextName)};
875 return {
nullptr,
nullptr};
878#include "moc_definition.cpp"
Represents a syntax definition.
QString style() const
Generalized language style, used for indentation.
QStringList keywordList(const QString &name) const
Returns the list of keywords for the keyword list name.
QString singleLineCommentMarker() const
Returns the marker that starts a single line comment.
int priority() const
Returns the definition priority.
bool isValid() const
Checks whether this object refers to a valid syntax definition.
QStringList foldingIgnoreList() const
If indentationBasedFoldingEnabled() returns true, this function returns a list of regular expressions...
QString filePath() const
Returns the full path to the definition XML file containing the syntax definition.
Definition & operator=(Definition &&other) noexcept
Move assignment operator.
CommentPosition singleLineCommentPosition() const
Returns the insert position of the comment marker for sinle line comments.
bool isHidden() const
Returns true if this is an internal definition that should not be displayed to the user.
bool indentationBasedFoldingEnabled() const
Returns whether indentation-based folding is enabled.
QStringList alternativeNames() const
Alternate names the syntax can be referred to by.
Definition()
Default constructor, creating an empty (invalid) Definition instance.
QList< QString > mimeTypes() const
Mime types associated with this syntax definition.
bool operator!=(const Definition &other) const
Checks two definitions for inequality.
bool foldingEnabled() const
Returns whether the highlighting supports code folding.
bool setKeywordList(const QString &name, const QStringList &content)
Set the contents of the keyword list name to content.
bool operator==(const Definition &other) const
Checks two definitions for equality.
QPair< QString, QString > multiLineCommentMarker() const
Returns the markers that start and end multiline comments.
QList< QPair< QChar, QString > > characterEncodings() const
Returns a list of character/string mapping that can be used for spell checking.
bool isWordWrapDelimiter(QChar c) const
Returns whether it is safe to break a line at before the character .
bool isWordDelimiter(QChar c) const
Returns whether the character c is a word delimiter.
QList< QString > extensions() const
File extensions associated with this syntax definition.
int version() const
Returns the definition version.
QList< Format > formats() const
Returns a list of all Format items used by this definition.
QStringList keywordLists() const
Returns the section names of keywords.
QString indenter() const
Indentation style to be used for this syntax.
QList< Definition > includedDefinitions() const
Returns a list of Definitions that are referenced with the IncludeRules rule.
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
QString name(StandardAction id)
Syntax highlighting engine for Kate syntax definitions.
CommentPosition
Defines the insert position when commenting code.
@ AfterWhitespace
The comment marker is inserted after leading whitespaces right befire the first non-whitespace charac...
@ StartOfLine
The comment marker is inserted at the beginning of a line at column 0.
NETWORKMANAGERQT_EXPORT QString version()
QCborValue value(QLatin1StringView key) const const
bool toBool(bool defaultValue) const const
QByteArray toByteArray(const QByteArray &defaultValue) const const
qint64 toInteger(qint64 defaultValue) const const
QString toString(const QString &defaultValue) const const
QCoreApplication * instance()
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
void push_back(parameter_type value)
QString & insert(qsizetype position, QChar ch)
bool isEmpty() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QStringView sliced(qsizetype pos) const const
float toFloat(bool *ok) const const
int toInt(bool *ok, int base) const const
QString toString() const const
bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const const
QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const const
QXmlStreamAttributes attributes() const const
QStringView name() const const
void skipCurrentElement()
TokenType tokenType() const const