KSyntaxHighlighting

definition.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
3 SPDX-FileCopyrightText: 2018 Dominik Haumann <dhaumann@kde.org>
4 SPDX-FileCopyrightText: 2018 Christoph Cullmann <cullmann@kde.org>
5 SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
6
7 SPDX-License-Identifier: MIT
8*/
9
10#include "definition.h"
11#include "definition_p.h"
12
13#include "context_p.h"
14#include "format.h"
15#include "format_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"
21#include "rule_p.h"
22#include "worddelimiters_p.h"
23#include "xml_p.h"
24
25#include <QCborMap>
26#include <QCoreApplication>
27#include <QFile>
28#include <QStringTokenizer>
29#include <QXmlStreamReader>
30
31#include <algorithm>
32#include <atomic>
33
34using namespace KSyntaxHighlighting;
35
36DefinitionData::DefinitionData()
37 : wordDelimiters()
38 , wordWrapDelimiters(wordDelimiters)
39{
40}
41
42DefinitionData::~DefinitionData() = default;
43
45 : d(std::make_shared<DefinitionData>())
46{
47 d->q = d;
48}
49
50Definition::Definition(Definition &&other) noexcept = default;
51Definition::Definition(const Definition &) = default;
52Definition::~Definition() = default;
53Definition &Definition::operator=(Definition &&other) noexcept = default;
55
56Definition::Definition(const DefinitionData &defData)
57 : d(defData.q.lock())
58{
59}
60
61bool Definition::operator==(const Definition &other) const
62{
63 return d->fileName == other.d->fileName;
64}
65
66bool Definition::operator!=(const Definition &other) const
67{
68 return d->fileName != other.d->fileName;
69}
70
72{
73 return d->repo && !d->fileName.isEmpty() && !d->name.isEmpty();
74}
75
77{
78 return d->fileName;
79}
80
81QString Definition::name() const
82{
83 return d->name;
84}
85
87{
88 return d->alternativeNames;
89}
90
91QString Definition::translatedName() const
92{
93 if (d->translatedName.isEmpty()) {
94 d->translatedName = QCoreApplication::instance()->translate("Language", d->nameUtf8.isEmpty() ? d->name.toUtf8().constData() : d->nameUtf8.constData());
95 }
96 return d->translatedName;
97}
98
99QString Definition::section() const
100{
101 return d->section;
102}
103
104QString Definition::translatedSection() const
105{
106 if (d->translatedSection.isEmpty()) {
107 d->translatedSection = QCoreApplication::instance()->translate("Language Section",
108 d->sectionUtf8.isEmpty() ? d->section.toUtf8().constData() : d->sectionUtf8.constData());
109 }
110 return d->translatedSection;
111}
112
114{
115 return d->mimetypes;
116}
117
119{
120 return d->extensions;
121}
122
124{
125 return d->version;
126}
127
129{
130 return d->priority;
131}
132
134{
135 return d->hidden;
136}
137
139{
140 return d->style;
141}
142
144{
145 return d->indenter;
146}
147
148QString Definition::author() const
149{
150 return d->author;
151}
152
153QString Definition::license() const
154{
155 return d->license;
156}
157
159{
160 d->load();
161 return d->wordDelimiters.contains(c);
162}
163
165{
166 d->load();
167 return d->wordWrapDelimiters.contains(c);
168}
169
171{
172 if (d->foldingRegionsState == DefinitionData::FoldingRegionsState::Undetermined) {
173 d->load();
174 }
175
176 return d->foldingRegionsState == DefinitionData::FoldingRegionsState::ContainsFoldingRegions || d->indentationBasedFolding;
177}
178
180{
181 d->load();
182 return d->indentationBasedFolding;
183}
184
186{
187 d->load();
188 return d->foldingIgnoreList;
189}
190
192{
193 d->load(DefinitionData::OnlyKeywords(true));
194 return d->keywordLists.keys();
195}
196
198{
199 d->load(DefinitionData::OnlyKeywords(true));
200 const auto list = d->keywordList(name);
201 return list ? list->keywords() : QStringList();
202}
203
204bool Definition::setKeywordList(const QString &name, const QStringList &content)
205{
206 d->load(DefinitionData::OnlyKeywords(true));
207 KeywordList *list = d->keywordList(name);
208 if (list) {
209 list->setKeywordList(content);
210 return true;
211 } else {
212 return false;
213 }
214}
215
217{
218 d->load();
219
220 // sort formats so that the order matches the order of the itemDatas in the xml files.
221 auto formatList = d->formats.values();
222 std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format &lhs, const KSyntaxHighlighting::Format &rhs) {
223 return lhs.id() < rhs.id();
224 });
225
226 return formatList;
227}
228
230{
231 QList<Definition> definitions;
232
233 if (isValid()) {
234 d->load();
235
236 // init worklist and result used as guard with this definition
238 definitions.push_back(*this);
239 while (!queue.empty()) {
240 const auto *def = queue.back();
241 queue.pop_back();
242 for (const auto *defData : def->immediateIncludedDefinitions) {
243 auto pred = [defData](const Definition &def) {
244 return DefinitionData::get(def) == defData;
245 };
246 if (std::find_if(definitions.begin(), definitions.end(), pred) == definitions.end()) {
247 definitions.push_back(Definition(*defData));
248 queue.push_back(defData);
249 }
250 }
251 }
252
253 // remove the 1st entry, since it is this Definition
254 definitions.front() = std::move(definitions.back());
255 definitions.pop_back();
256 }
257
258 return definitions;
259}
260
262{
263 d->load();
264 return d->singleLineCommentMarker;
265}
266
268{
269 d->load();
270 return d->singleLineCommentPosition;
271}
272
273QPair<QString, QString> Definition::multiLineCommentMarker() const
274{
275 d->load();
276 return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker};
277}
278
280{
281 d->load();
282 return d->characterEncodings;
283}
284
285Context *DefinitionData::initialContext()
286{
287 Q_ASSERT(!contexts.empty());
288 return &contexts.front();
289}
290
291Context *DefinitionData::contextByName(QStringView wantedName)
292{
293 for (auto &context : contexts) {
294 if (context.name() == wantedName) {
295 return &context;
296 }
297 }
298 return nullptr;
299}
300
301KeywordList *DefinitionData::keywordList(const QString &wantedName)
302{
303 auto it = keywordLists.find(wantedName);
304 return (it == keywordLists.end()) ? nullptr : &it.value();
305}
306
307Format DefinitionData::formatByName(QStringView wantedName) const
308{
309 const auto it = formats.constFind(wantedName);
310 if (it != formats.constEnd()) {
311 return it.value();
312 }
313
314 return Format();
315}
316
317bool DefinitionData::isLoaded() const
318{
319 return !contexts.empty();
320}
321
322namespace
323{
324std::atomic<uint64_t> definitionId{1};
325}
326
327bool DefinitionData::load(OnlyKeywords onlyKeywords)
328{
329 if (isLoaded()) {
330 return true;
331 }
332
333 if (fileName.isEmpty()) {
334 return false;
335 }
336
337 if (bool(onlyKeywords) && keywordIsLoaded) {
338 return true;
339 }
340
341 QFile file(fileName);
342 if (!file.open(QFile::ReadOnly)) {
343 return false;
344 }
345
346 QXmlStreamReader reader(&file);
347 while (!reader.atEnd()) {
348 const auto token = reader.readNext();
349 if (token != QXmlStreamReader::StartElement) {
350 continue;
351 }
352
353 if (reader.name() == QLatin1String("highlighting")) {
354 loadHighlighting(reader, onlyKeywords);
355 if (bool(onlyKeywords)) {
356 return true;
357 }
358 }
359
360 else if (reader.name() == QLatin1String("general")) {
361 loadGeneral(reader);
362 }
363 }
364
365 for (auto &kw : keywordLists) {
366 kw.setCaseSensitivity(caseSensitive);
367 }
368
369 resolveContexts();
370
371 id = definitionId.fetch_add(1, std::memory_order_relaxed);
372
373 return true;
374}
375
376void DefinitionData::clear()
377{
378 // keep only name and repo, so we can re-lookup to make references persist over repo reloads
379 // see AbstractHighlighterPrivate::ensureDefinitionLoaded()
380 id = 0;
381 keywordLists.clear();
382 contexts.clear();
383 formats.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();
393 singleLineCommentPosition = CommentPosition::StartOfLine;
394 multiLineCommentStartMarker.clear();
395 multiLineCommentEndMarker.clear();
396 characterEncodings.clear();
397
398 fileName.clear();
399 nameUtf8.clear();
400 translatedName.clear();
401 section.clear();
402 sectionUtf8.clear();
403 translatedSection.clear();
404 style.clear();
405 indenter.clear();
406 author.clear();
407 license.clear();
408 mimetypes.clear();
409 extensions.clear();
410 caseSensitive = Qt::CaseSensitive;
411 version = 0.0f;
412 priority = 0;
413 hidden = false;
414
415 // purge our cache that is used to unify states
416 unify.clear();
417}
418
419bool DefinitionData::loadMetaData(const QString &definitionFileName)
420{
421 fileName = definitionFileName;
422
423 QFile file(definitionFileName);
424 if (!file.open(QFile::ReadOnly)) {
425 return false;
426 }
427
428 QXmlStreamReader reader(&file);
429 while (!reader.atEnd()) {
430 const auto token = reader.readNext();
431 if (token != QXmlStreamReader::StartElement) {
432 continue;
433 }
434 if (reader.name() == QLatin1String("language")) {
435 return loadLanguage(reader);
436 }
437 }
438
439 return false;
440}
441
442bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj)
443{
444 name = obj.value(QLatin1String("name")).toString();
445 if (name.isEmpty()) {
446 return false;
447 }
448 nameUtf8 = obj.value(QLatin1String("name")).toByteArray();
449 section = obj.value(QLatin1String("section")).toString();
450 sectionUtf8 = obj.value(QLatin1String("section")).toByteArray();
451 version = obj.value(QLatin1String("version")).toInteger();
452 priority = obj.value(QLatin1String("priority")).toInteger();
453 style = obj.value(QLatin1String("style")).toString();
454 author = obj.value(QLatin1String("author")).toString();
455 license = obj.value(QLatin1String("license")).toString();
456 indenter = obj.value(QLatin1String("indenter")).toString();
457 hidden = obj.value(QLatin1String("hidden")).toBool();
458 fileName = file;
459
460 const auto names = obj.value(QLatin1String("alternativeNames")).toString();
461 alternativeNames = names.split(QLatin1Char(';'), Qt::SkipEmptyParts);
462
463 const auto exts = obj.value(QLatin1String("extensions")).toString();
464 extensions = exts.split(QLatin1Char(';'), Qt::SkipEmptyParts);
465
466 const auto mts = obj.value(QLatin1String("mimetype")).toString();
467 mimetypes = mts.split(QLatin1Char(';'), Qt::SkipEmptyParts);
468
469 return true;
470}
471
472bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
473{
474 Q_ASSERT(reader.name() == QLatin1String("language"));
475 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
476
477 if (!checkKateVersion(reader.attributes().value(QLatin1String("kateversion")))) {
478 return false;
479 }
480
481 name = reader.attributes().value(QLatin1String("name")).toString();
482 if (name.isEmpty()) {
483 return false;
484 }
485 const auto names = reader.attributes().value(QLatin1String("alternativeNames"));
486 for (const auto &n : QStringTokenizer(names, u';', Qt::SkipEmptyParts)) {
487 alternativeNames.push_back(n.toString());
488 }
489 section = reader.attributes().value(QLatin1String("section")).toString();
490 // toFloat instead of toInt for backward compatibility with old Kate files
491 version = reader.attributes().value(QLatin1String("version")).toFloat();
492 priority = reader.attributes().value(QLatin1String("priority")).toInt();
493 hidden = Xml::attrToBool(reader.attributes().value(QLatin1String("hidden")));
494 style = reader.attributes().value(QLatin1String("style")).toString();
495 indenter = reader.attributes().value(QLatin1String("indenter")).toString();
496 author = reader.attributes().value(QLatin1String("author")).toString();
497 license = reader.attributes().value(QLatin1String("license")).toString();
498 const auto exts = reader.attributes().value(QLatin1String("extensions"));
499 for (const auto &ext : QStringTokenizer(exts, u';', Qt::SkipEmptyParts)) {
500 extensions.push_back(ext.toString());
501 }
502 const auto mts = reader.attributes().value(QLatin1String("mimetype"));
503 for (const auto &mt : QStringTokenizer(mts, u';', Qt::SkipEmptyParts)) {
504 mimetypes.push_back(mt.toString());
505 }
506 if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) {
507 caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
508 }
509 return true;
510}
511
512void DefinitionData::loadHighlighting(QXmlStreamReader &reader, OnlyKeywords onlyKeywords)
513{
514 Q_ASSERT(reader.name() == QLatin1String("highlighting"));
515 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
516
517 // skip highlighting
518 reader.readNext();
519
520 while (!reader.atEnd()) {
521 switch (reader.tokenType()) {
523 if (reader.name() == QLatin1String("list")) {
524 if (!keywordIsLoaded) {
525 KeywordList keywords;
526 keywords.load(reader);
527 keywordLists.insert(keywords.name(), keywords);
528 } else {
529 reader.skipCurrentElement();
530 reader.readNext(); // Skip </list>
531 }
532 } else if (bool(onlyKeywords)) {
533 resolveIncludeKeywords();
534 return;
535 } else if (reader.name() == QLatin1String("contexts")) {
536 resolveIncludeKeywords();
537 loadContexts(reader);
538 reader.readNext();
539 } else if (reader.name() == QLatin1String("itemDatas")) {
540 loadItemData(reader);
541 } else {
542 reader.readNext();
543 }
544 break;
546 return;
547 default:
548 reader.readNext();
549 break;
550 }
551 }
552}
553
554void DefinitionData::resolveIncludeKeywords()
555{
556 if (keywordIsLoaded) {
557 return;
558 }
559
560 keywordIsLoaded = true;
561
562 for (auto &kw : keywordLists) {
563 kw.resolveIncludeKeywords(*this);
564 }
565}
566
567void DefinitionData::loadContexts(QXmlStreamReader &reader)
568{
569 Q_ASSERT(reader.name() == QLatin1String("contexts"));
570 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
571
572 contextDatas.reserve(32);
573
574 while (!reader.atEnd()) {
575 switch (reader.tokenType()) {
577 if (reader.name() == QLatin1String("context")) {
578 contextDatas.emplace_back().load(name, reader);
579 }
580 reader.readNext();
581 break;
583 return;
584 default:
585 reader.readNext();
586 break;
587 }
588 }
589}
590
591void DefinitionData::resolveContexts()
592{
593 contexts.reserve(contextDatas.size());
594
595 /**
596 * Transform all HighlightingContextData to Context.
597 * This is necessary so that Context::resolveContexts() can find the referenced contexts.
598 */
599 for (const auto &contextData : std::as_const(contextDatas)) {
600 contexts.emplace_back(*this, contextData);
601 }
602
603 /**
604 * Resolves contexts and rules.
605 */
606 auto ctxIt = contexts.begin();
607 for (const auto &contextData : std::as_const(contextDatas)) {
608 ctxIt->resolveContexts(*this, contextData);
609 ++ctxIt;
610 }
611
612 /**
613 * To free the memory, constDatas is emptied because it is no longer used.
614 */
615 contextDatas.clear();
616 contextDatas.shrink_to_fit();
617
618 /**
619 * Resolved includeRules.
620 */
621 for (auto &context : contexts) {
622 context.resolveIncludes(*this);
623 }
624
625 // when a context includes a folding region this value is Yes, otherwise it remains undetermined
626 if (foldingRegionsState == FoldingRegionsState::Undetermined) {
627 foldingRegionsState = FoldingRegionsState::NoFoldingRegions;
628 }
629}
630
631void DefinitionData::loadItemData(QXmlStreamReader &reader)
632{
633 Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
634 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
635
636 while (!reader.atEnd()) {
637 switch (reader.tokenType()) {
639 if (reader.name() == QLatin1String("itemData")) {
640 Format f;
641 auto formatData = FormatPrivate::detachAndGet(f);
642 formatData->definitionName = name;
643 formatData->load(reader);
644 formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
645 formats.insert(f.name(), f);
646 reader.readNext();
647 }
648 reader.readNext();
649 break;
651 return;
652 default:
653 reader.readNext();
654 break;
655 }
656 }
657}
658
659void DefinitionData::loadGeneral(QXmlStreamReader &reader)
660{
661 Q_ASSERT(reader.name() == QLatin1String("general"));
662 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
663 reader.readNext();
664
665 // reference counter to count XML child elements, to not return too early
666 int elementRefCounter = 1;
667
668 while (!reader.atEnd()) {
669 switch (reader.tokenType()) {
671 ++elementRefCounter;
672
673 if (reader.name() == QLatin1String("keywords")) {
674 if (reader.attributes().hasAttribute(QLatin1String("casesensitive"))) {
675 caseSensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
676 }
677
678 // adapt wordDelimiters
679 wordDelimiters.append(reader.attributes().value(QLatin1String("additionalDeliminator")));
680 wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator")));
681
682 // adapt WordWrapDelimiters
683 auto wordWrapDeliminatorAttr = reader.attributes().value(QLatin1String("wordWrapDeliminator"));
684 if (wordWrapDeliminatorAttr.isEmpty()) {
685 wordWrapDelimiters = wordDelimiters;
686 } else {
687 wordWrapDelimiters.append(wordWrapDeliminatorAttr);
688 }
689 } else if (reader.name() == QLatin1String("folding")) {
690 if (reader.attributes().hasAttribute(QLatin1String("indentationsensitive"))) {
691 indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("indentationsensitive")));
692 }
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);
699 } else {
700 reader.skipCurrentElement();
701 }
702 reader.readNext();
703 break;
705 --elementRefCounter;
706 if (elementRefCounter == 0) {
707 return;
708 }
709 reader.readNext();
710 break;
711 default:
712 reader.readNext();
713 break;
714 }
715 }
716}
717
718void DefinitionData::loadComments(QXmlStreamReader &reader)
719{
720 Q_ASSERT(reader.name() == QLatin1String("comments"));
721 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
722 reader.readNext();
723
724 // reference counter to count XML child elements, to not return too early
725 int elementRefCounter = 1;
726
727 while (!reader.atEnd()) {
728 switch (reader.tokenType()) {
730 ++elementRefCounter;
731 if (reader.name() == QLatin1String("comment")) {
732 const bool isSingleLine = reader.attributes().value(QLatin1String("name")) == QLatin1String("singleLine");
733 if (isSingleLine) {
734 singleLineCommentMarker = reader.attributes().value(QLatin1String("start")).toString();
735 const bool afterWhiteSpace = reader.attributes().value(QLatin1String("position")) == QLatin1String("afterwhitespace");
736 singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
737 } else {
738 multiLineCommentStartMarker = reader.attributes().value(QLatin1String("start")).toString();
739 multiLineCommentEndMarker = reader.attributes().value(QLatin1String("end")).toString();
740 }
741 }
742 reader.readNext();
743 break;
745 --elementRefCounter;
746 if (elementRefCounter == 0) {
747 return;
748 }
749 reader.readNext();
750 break;
751 default:
752 reader.readNext();
753 break;
754 }
755 }
756}
757
758void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader &reader)
759{
760 Q_ASSERT(reader.name() == QLatin1String("emptyLines"));
761 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
762 reader.readNext();
763
764 // reference counter to count XML child elements, to not return too early
765 int elementRefCounter = 1;
766
767 while (!reader.atEnd()) {
768 switch (reader.tokenType()) {
770 ++elementRefCounter;
771 if (reader.name() == QLatin1String("emptyLine")) {
772 foldingIgnoreList << reader.attributes().value(QLatin1String("regexpr")).toString();
773 }
774 reader.readNext();
775 break;
777 --elementRefCounter;
778 if (elementRefCounter == 0) {
779 return;
780 }
781 reader.readNext();
782 break;
783 default:
784 reader.readNext();
785 break;
786 }
787 }
788}
789
790void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
791{
792 Q_ASSERT(reader.name() == QLatin1String("spellchecking"));
793 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
794 reader.readNext();
795
796 // reference counter to count XML child elements, to not return too early
797 int elementRefCounter = 1;
798
799 while (!reader.atEnd()) {
800 switch (reader.tokenType()) {
802 ++elementRefCounter;
803 if (reader.name() == QLatin1String("encoding")) {
804 const auto charRef = reader.attributes().value(QLatin1String("char"));
805 if (!charRef.isEmpty()) {
806 const auto str = reader.attributes().value(QLatin1String("string"));
807 characterEncodings.push_back({charRef[0], str.toString()});
808 }
809 }
810 reader.readNext();
811 break;
813 --elementRefCounter;
814 if (elementRefCounter == 0) {
815 return;
816 }
817 reader.readNext();
818 break;
819 default:
820 reader.readNext();
821 break;
822 }
823 }
824}
825
826bool DefinitionData::checkKateVersion(QStringView verStr)
827{
828 const auto idx = verStr.indexOf(QLatin1Char('.'));
829 if (idx <= 0) {
830 qCWarning(Log) << "Skipping" << fileName << "due to having no valid kateversion attribute:" << verStr;
831 return false;
832 }
833 const auto major = verStr.sliced(0, idx).toInt();
834 const auto minor = verStr.sliced(idx + 1).toInt();
835
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;
838 return false;
839 }
840
841 return true;
842}
843
844quint16 DefinitionData::foldingRegionId(const QString &foldName)
845{
846 foldingRegionsState = FoldingRegionsState::ContainsFoldingRegions;
847 return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
848}
849
850DefinitionData::ResolvedContext DefinitionData::resolveIncludedContext(QStringView defName, QStringView contextName)
851{
852 if (defName.isEmpty()) {
853 return {this, contextByName(contextName)};
854 }
855
856 auto d = repo->definitionForName(defName.toString());
857 if (d.isValid()) {
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);
862 resolvedDef->load();
863 if (resolvedDef->foldingRegionsState == FoldingRegionsState::ContainsFoldingRegions) {
864 foldingRegionsState = FoldingRegionsState::ContainsFoldingRegions;
865 }
866 }
867 }
868 if (contextName.isEmpty()) {
869 return {resolvedDef, resolvedDef->initialContext()};
870 } else {
871 return {resolvedDef, resolvedDef->contextByName(contextName)};
872 }
873 }
874
875 return {nullptr, nullptr};
876}
877
878#include "moc_definition.cpp"
Represents a syntax definition.
Definition definition.h:83
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.
Describes the format to be used for a specific text fragment.
Definition format.h:28
QString name() const
The name of this format as used in the syntax definition file.
Definition format.cpp:95
KDB_EXPORT KDbVersionInfo version()
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.
Definition definition.h:32
@ 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.
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)
reference back()
iterator begin()
iterator end()
reference front()
void pop_back()
void push_back(parameter_type value)
QString & insert(qsizetype position, QChar ch)
bool isEmpty() 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
CaseSensitive
SkipEmptyParts
bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const const
QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const const
bool atEnd() const const
QXmlStreamAttributes attributes() const const
QStringView name() const const
TokenType readNext()
void skipCurrentElement()
TokenType tokenType() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:17:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.