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(b, 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(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), KeywordComparator{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(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(reader.readElementText().trimmed());
65 reader.readNextStartElement();
66 break;
67 } else if (reader.name() == QLatin1String("include")) {
68 m_includes.append(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(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.reserve(m_keywords.size());
107 for (const auto &keyword : std::as_const(m_keywords)) {
108 vectorToSort.push_back(keyword);
109 }
110
111 /**
112 * sort with right predicate
113 */
114 std::sort(vectorToSort.begin(), vectorToSort.end(), KeywordComparator{caseSensitive});
115}
116
117void KeywordList::resolveIncludeKeywords(DefinitionData &def)
118{
119 while (!m_includes.isEmpty()) {
120 const auto kw_include = std::move(m_includes.back());
121 m_includes.pop_back();
122
123 const auto idx = kw_include.indexOf(QLatin1String("##"));
124 KeywordList *keywords = nullptr;
125
126 if (idx >= 0) {
127 auto defName = kw_include.mid(idx + 2);
128 auto includeDef = def.repo->definitionForName(defName);
129 if (includeDef.isValid()) {
130 auto listName = kw_include.left(idx);
131 auto defData = DefinitionData::get(def: includeDef);
132 defData->load(DefinitionData::OnlyKeywords(true));
133 keywords = defData->keywordList(listName);
134 } else {
135 qCWarning(Log) << "Unable to resolve external include keyword for definition" << defName << "in" << def.name;
136 }
137 } else {
138 keywords = def.keywordList(name: kw_include);
139 }
140
141 if (keywords) {
142 if (this != keywords) {
143 keywords->resolveIncludeKeywords(def);
144 }
145 m_keywords += keywords->m_keywords;
146 } else {
147 qCWarning(Log) << "Unresolved include keyword" << kw_include << "in" << def.name;
148 }
149 }
150}
151

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