1/*
2 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
3 SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
4
5 SPDX-License-Identifier: MIT
6*/
7
8#include "definition_p.h"
9#include "keywordlist_p.h"
10#include "ksyntaxhighlighting_logging.h"
11#include "repository.h"
12
13#include <QXmlStreamReader>
14
15#include <algorithm>
16
17using namespace KSyntaxHighlighting;
18
19namespace
20{
21struct KeywordComparator {
22 Qt::CaseSensitivity caseSensitive;
23
24 bool operator()(QStringView a, QStringView b) const
25 {
26 if (a.size() < b.size()) {
27 return true;
28 }
29
30 if (a.size() > b.size()) {
31 return false;
32 }
33
34 return a.compare(other: b, cs: caseSensitive) < 0;
35 }
36};
37
38}
39
40bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) const
41{
42 /**
43 * get right vector to search in
44 */
45 const auto &vectorToSearch = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
46
47 /**
48 * search with right predicate
49 */
50 return std::binary_search(first: vectorToSearch.begin(), last: vectorToSearch.end(), val: str, comp: KeywordComparator{.caseSensitive: caseSensitive});
51}
52
53void KeywordList::load(QXmlStreamReader &reader)
54{
55 Q_ASSERT(reader.name() == QLatin1String("list"));
56 Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
57
58 m_name = reader.attributes().value(qualifiedName: QLatin1String("name")).toString();
59
60 while (!reader.atEnd()) {
61 switch (reader.tokenType()) {
62 case QXmlStreamReader::StartElement:
63 if (reader.name() == QLatin1String("item")) {
64 m_keywords.append(t: reader.readElementText().trimmed());
65 reader.readNextStartElement();
66 break;
67 } else if (reader.name() == QLatin1String("include")) {
68 m_includes.append(t: reader.readElementText().trimmed());
69 reader.readNextStartElement();
70 break;
71 }
72 reader.readNext();
73 break;
74 case QXmlStreamReader::EndElement:
75 reader.readNext();
76 return;
77 default:
78 reader.readNext();
79 break;
80 }
81 }
82}
83
84void KeywordList::setCaseSensitivity(Qt::CaseSensitivity caseSensitive)
85{
86 /**
87 * remember default case-sensitivity and init lookup for it
88 */
89 m_caseSensitive = caseSensitive;
90 initLookupForCaseSensitivity(caseSensitive: m_caseSensitive);
91}
92
93void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive)
94{
95 /**
96 * get right vector to sort, if non-empty, we are done
97 */
98 auto &vectorToSort = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
99 if (!vectorToSort.empty()) {
100 return;
101 }
102
103 /**
104 * fill vector with refs to keywords
105 */
106 vectorToSort.assign(first: m_keywords.constBegin(), last: m_keywords.constEnd());
107
108 /**
109 * sort with right predicate
110 */
111 std::sort(first: vectorToSort.begin(), last: vectorToSort.end(), comp: KeywordComparator{.caseSensitive: caseSensitive});
112}
113
114void KeywordList::resolveIncludeKeywords(DefinitionData &def)
115{
116 while (!m_includes.isEmpty()) {
117 const auto kw_include = std::move(m_includes.back());
118 m_includes.pop_back();
119
120 const auto idx = kw_include.indexOf(s: QLatin1String("##"));
121 KeywordList *keywords = nullptr;
122
123 if (idx >= 0) {
124 auto defName = kw_include.mid(position: idx + 2);
125 auto includeDef = def.repo->definitionForName(defName);
126 if (includeDef.isValid()) {
127 auto listName = kw_include.left(n: idx);
128 auto defData = DefinitionData::get(def: includeDef);
129 defData->load(onlyKeywords: DefinitionData::OnlyKeywords(true));
130 keywords = defData->keywordList(name: listName);
131 } else {
132 qCWarning(Log) << "Unable to resolve external include keyword for definition" << defName << "in" << def.name;
133 }
134 } else {
135 keywords = def.keywordList(name: kw_include);
136 }
137
138 if (keywords) {
139 if (this != keywords) {
140 keywords->resolveIncludeKeywords(def);
141 }
142 m_keywords += keywords->m_keywords;
143 } else {
144 qCWarning(Log) << "Unresolved include keyword" << kw_include << "in" << def.name;
145 }
146 }
147}
148

source code of syntax-highlighting/src/lib/keywordlist.cpp