aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/syntax-highlighting/src
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2019-06-20 08:09:16 +0200
committerDavid Schulz <david.schulz@qt.io>2019-06-20 12:25:21 +0000
commit7b6ebea648bae91ee4ba014237eae34eb34d3805 (patch)
tree4cd3a24bf7b78d1ae6b41b3bc1c21ad3eba61897 /src/libs/3rdparty/syntax-highlighting/src
parentbd3037464e6d1f6a3af7beb6c40a49b54433efca (diff)
Update KSyntaxHighlighting 5.52 -> 5.59
Task-number: QTCREATORBUG-22558 Change-Id: I2eac03b54f2c2d330ee9b5d0037ee42a6640d76b Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src')
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp4
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp88
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt1
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp77
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp83
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h12
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp54
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp45
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h9
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp40
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.h8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp8
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp8
13 files changed, 336 insertions, 101 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
index 80a15d2589..8334dd32e9 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp
@@ -92,14 +92,14 @@ int main(int argc, char **argv)
Repository repo;
if (parser.isSet(listDefs)) {
- foreach (const auto &def, repo.definitions()) {
+ for (const auto &def : repo.definitions()) {
std::cout << qPrintable(def.name()) << std::endl;
}
return 0;
}
if (parser.isSet(listThemes)) {
- foreach (const auto &theme, repo.themes())
+ for (const auto &theme : repo.themes())
std::cout << qPrintable(theme.name()) << std::endl;
return 0;
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
index 489fbec160..3534cfde90 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp
@@ -194,6 +194,82 @@ bool checkLookAhead(const QString &hlFilename, QXmlStreamReader &xml)
}
/**
+ * Helper class to search for non-existing keyword include.
+ */
+class KeywordIncludeChecker
+{
+public:
+ void processElement(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml)
+ {
+ if (xml.name() == QLatin1String("list")) {
+ auto &keywords = m_keywordMap[hlName];
+ keywords.filename = hlFilename;
+ auto name = xml.attributes().value(QLatin1String("name")).toString();
+ m_currentIncludes = &keywords.includes[name];
+ }
+ else if (xml.name() == QLatin1String("include")) {
+ if (!m_currentIncludes) {
+ qWarning() << hlFilename << "line" << xml.lineNumber() << "<include> tag ouside <list>";
+ m_success = false;
+ } else {
+ m_currentIncludes->push_back({xml.lineNumber(), xml.readElementText()});
+ }
+ }
+ }
+
+ bool check() const
+ {
+ bool success = m_success;
+ for (auto &keywords : m_keywordMap) {
+ QMapIterator<QString, QVector<Keywords::Include>> includes(keywords.includes);
+ while (includes.hasNext()) {
+ includes.next();
+ for (auto &include : includes.value()) {
+ bool containsKeywordName = true;
+ int const idx = include.name.indexOf(QStringLiteral("##"));
+ if (idx == -1) {
+ auto &keywordName = includes.key();
+ containsKeywordName = keywords.includes.contains(keywordName);
+ }
+ else {
+ auto defName = include.name.mid(idx + 2);
+ auto listName = include.name.left(idx);
+ auto it = m_keywordMap.find(defName);
+ if (it == m_keywordMap.end()) {
+ qWarning() << keywords.filename << "line" << include.line << "unknown definition in" << include.name;
+ success = false;
+ } else {
+ containsKeywordName = it->includes.contains(listName);
+ }
+ }
+
+ if (!containsKeywordName) {
+ qWarning() << keywords.filename << "line" << include.line << "unknown keyword name in" << include.name;
+ success = false;
+ }
+ }
+ }
+ }
+ return success;
+ }
+
+private:
+ struct Keywords
+ {
+ QString filename;
+ struct Include
+ {
+ qint64 line;
+ QString name;
+ };
+ QMap<QString, QVector<Include>> includes;
+ };
+ QHash<QString, Keywords> m_keywordMap;
+ QVector<Keywords::Include> *m_currentIncludes = nullptr;
+ bool m_success = true;
+};
+
+/**
* Helper class to search for non-existing or unreferenced keyword lists.
*/
class KeywordChecker
@@ -296,6 +372,7 @@ public:
const auto unusedNames = language.existingContextNames - language.usedContextNames;
if (!unusedNames.isEmpty()) {
qWarning() << language.hlFilename << "Unused contexts:" << unusedNames;
+ success = false;
}
}
@@ -457,9 +534,10 @@ int main(int argc, char *argv[])
// index all given highlightings
ContextChecker contextChecker;
+ KeywordIncludeChecker keywordIncludeChecker;
QVariantMap hls;
int anyError = 0;
- foreach (const QString &hlFilename, hlFilenames) {
+ for (const QString &hlFilename : qAsConst(hlFilenames)) {
QFile hlFile(hlFilename);
if (!hlFile.open(QIODevice::ReadOnly)) {
qWarning ("Failed to open %s", qPrintable(hlFilename));
@@ -493,7 +571,7 @@ int main(int argc, char *argv[])
QVariantMap hl;
// transfer text attributes
- Q_FOREACH (const QString &attribute, textAttributes) {
+ for (const QString &attribute : qAsConst(textAttributes)) {
hl[attribute] = xml.attributes().value(attribute).toString();
}
@@ -528,6 +606,9 @@ int main(int argc, char *argv[])
// search for used/existing contexts if applicable
contextChecker.processElement(hlFilename, hlName, xml);
+ // search for existing keyword includes
+ keywordIncludeChecker.processElement(hlFilename, hlName, xml);
+
// search for used/existing attributes if applicable
attributeChecker.processElement(xml);
@@ -571,6 +652,9 @@ int main(int argc, char *argv[])
if (!contextChecker.check())
anyError = 7;
+ if (!keywordIncludeChecker.check())
+ anyError = 7;
+
// bail out if any problem was seen
if (anyError)
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
index bf729fca71..95bf4c349e 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
@@ -40,6 +40,7 @@ ecm_generate_headers(SyntaxHighlighting_HEADERS
HEADER_NAMES
AbstractHighlighter
Definition
+ DefinitionDownloader
FoldingRegion
Format
Repository
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
index f69944debd..c4ef86a771 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
@@ -53,7 +53,7 @@ void AbstractHighlighterPrivate::ensureDefinitionLoaded()
defData = DefinitionData::get(m_definition);
}
- if (Q_UNLIKELY(!defData->repo && !defData->name.isEmpty()))
+ if (Q_UNLIKELY(!defData->repo && !defData->fileName.isEmpty()))
qCCritical(Log) << "Repository got deleted while a highlighter is still active!";
if (m_definition.isValid())
@@ -118,13 +118,13 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
// verify definition, deal with no highlighting being enabled
d->ensureDefinitionLoaded();
- if (!d->m_definition.isValid()) {
+ const auto defData = DefinitionData::get(d->m_definition);
+ if (!d->m_definition.isValid() || !defData->isLoaded()) {
applyFormat(0, text.size(), Format());
return State();
}
// verify/initialize state
- auto defData = DefinitionData::get(d->m_definition);
auto newState = state;
auto stateData = StateData::get(newState);
const DefinitionRef currentDefRef(d->m_definition);
@@ -139,9 +139,37 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
// process empty lines
if (text.isEmpty()) {
- while (!stateData->topContext()->lineEmptyContext().isStay()) {
- if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList()))
+ /**
+ * handle line empty context switches
+ * guard against endless loops
+ * see https://phabricator.kde.org/D18509
+ */
+ int endlessLoopingCounter = 0;
+ while (!stateData->topContext()->lineEmptyContext().isStay() || (stateData->topContext()->lineEmptyContext().isStay() && !stateData->topContext()->lineEndContext().isStay())) {
+ /**
+ * line empty context switches
+ */
+ if (!stateData->topContext()->lineEmptyContext().isStay()) {
+ if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList())) {
+ /**
+ * end when trying to #pop the main context
+ */
+ break;
+ }
+ /**
+ * line end context switches only when lineEmptyContext is #stay. This avoids
+ * skipping empty lines after a line continuation character (see bug 405903)
+ */
+ } else if (!stateData->topContext()->lineEndContext().isStay() &&
+ !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
break;
+
+ // guard against endless loops
+ ++endlessLoopingCounter;
+ if (endlessLoopingCounter > 1024) {
+ qCDebug(Log) << "Endless switch context transitions for line empty context, aborting highlighting of line.";
+ break;
+ }
}
auto context = stateData->topContext();
applyFormat(0, 0, context->attributeFormat());
@@ -238,11 +266,18 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
if (newOffset <= offset)
continue;
- // apply folding
- if (rule->endRegion().isValid())
- applyFolding(offset, newOffset - offset, rule->endRegion());
+ /**
+ * apply folding.
+ * special cases:
+ * - rule with endRegion + beginRegion: in endRegion, the length is 0
+ * - rule with lookAhead: length is 0
+ */
+ if (rule->endRegion().isValid() && rule->beginRegion().isValid())
+ applyFolding(offset, 0, rule->endRegion());
+ else if (rule->endRegion().isValid())
+ applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->endRegion());
if (rule->beginRegion().isValid())
- applyFolding(offset, newOffset - offset, rule->beginRegion());
+ applyFolding(offset, rule->isLookAhead() ? 0 : newOffset - offset, rule->beginRegion());
if (rule->isLookAhead()) {
Q_ASSERT(!rule->context().isStay());
@@ -293,12 +328,30 @@ State AbstractHighlighter::highlightLine(const QString& text, const State &state
} while (offset < text.size());
+ /**
+ * apply format for remaining text, if any
+ */
if (beginOffset < offset)
applyFormat(beginOffset, text.size() - beginOffset, *currentFormat);
- while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) {
- if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
- break;
+ /**
+ * handle line end context switches
+ * guard against endless loops
+ * see https://phabricator.kde.org/D18509
+ */
+ {
+ int endlessLoopingCounter = 0;
+ while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) {
+ if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
+ break;
+
+ // guard against endless loops
+ ++endlessLoopingCounter;
+ if (endlessLoopingCounter > 1024) {
+ qCDebug(Log) << "Endless switch context transitions for line end context, aborting highlighting of line.";
+ break;
+ }
+ }
}
return newState;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
index c03d23dc48..ae95a6b235 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
@@ -31,6 +31,7 @@
#include "context_p.h"
#include "format.h"
#include "format_p.h"
+#include "repository.h"
#include "repository_p.h"
#include "rule_p.h"
#include "ksyntaxhighlighting_logging.h"
@@ -222,13 +223,13 @@ QStringList Definition::foldingIgnoreList() const
QStringList Definition::keywordLists() const
{
- d->load();
+ d->load(DefinitionData::OnlyKeywords(true));
return d->keywordLists.keys();
}
QStringList Definition::keywordList(const QString& name) const
{
- d->load();
+ d->load(DefinitionData::OnlyKeywords(true));
const auto list = d->keywordList(name);
return list ? list->keywords() : QStringList();
}
@@ -323,18 +324,18 @@ Context* DefinitionData::initialContext() const
return contexts.first();
}
-Context* DefinitionData::contextByName(const QString& name) const
+Context* DefinitionData::contextByName(const QString& wantedName) const
{
- foreach (auto context, contexts) {
- if (context->name() == name)
+ for (const auto context : contexts) {
+ if (context->name() == wantedName)
return context;
}
return nullptr;
}
-KeywordList *DefinitionData::keywordList(const QString& name)
+KeywordList *DefinitionData::keywordList(const QString& wantedName)
{
- auto it = keywordLists.find(name);
+ auto it = keywordLists.find(wantedName);
return (it == keywordLists.end()) ? nullptr : &it.value();
}
@@ -343,9 +344,9 @@ bool DefinitionData::isWordDelimiter(QChar c) const
return std::binary_search(wordDelimiters.constBegin(), wordDelimiters.constEnd(), c);
}
-Format DefinitionData::formatByName(const QString& name) const
+Format DefinitionData::formatByName(const QString& wantedName) const
{
- const auto it = formats.constFind(name);
+ const auto it = formats.constFind(wantedName);
if (it != formats.constEnd())
return it.value();
@@ -357,7 +358,7 @@ bool DefinitionData::isLoaded() const
return !contexts.isEmpty();
}
-bool DefinitionData::load()
+bool DefinitionData::load(OnlyKeywords onlyKeywords)
{
if (fileName.isEmpty())
return false;
@@ -365,6 +366,9 @@ bool DefinitionData::load()
if (isLoaded())
return true;
+ if (bool(onlyKeywords) && keywordIsLoaded)
+ return true;
+
QFile file(fileName);
if (!file.open(QFile::ReadOnly))
return false;
@@ -375,17 +379,22 @@ bool DefinitionData::load()
if (token != QXmlStreamReader::StartElement)
continue;
- if (reader.name() == QLatin1String("highlighting"))
- loadHighlighting(reader);
+ if (reader.name() == QLatin1String("highlighting")) {
+ loadHighlighting(reader, onlyKeywords);
+ if (bool(onlyKeywords)) {
+ return true;
+ }
+ }
else if (reader.name() == QLatin1String("general"))
loadGeneral(reader);
}
- for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it)
- (*it).setCaseSensitivity(caseSensitive);
+ for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it) {
+ it->setCaseSensitivity(caseSensitive);
+ }
- foreach (auto context, contexts) {
+ for (const auto context : qAsConst(contexts)) {
context->resolveContexts();
context->resolveIncludes();
context->resolveAttributeFormat();
@@ -454,10 +463,10 @@ bool DefinitionData::loadMetaData(const QString &file, const QJsonObject &obj)
fileName = file;
const auto exts = obj.value(QLatin1String("extensions")).toString();
- foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
extensions.push_back(ext);
const auto mts = obj.value(QLatin1String("mimetype")).toString();
- foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ for (const auto &mt : mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
mimetypes.push_back(mt);
return true;
@@ -482,29 +491,42 @@ bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
author = reader.attributes().value(QStringLiteral("author")).toString();
license = reader.attributes().value(QStringLiteral("license")).toString();
const auto exts = reader.attributes().value(QStringLiteral("extensions")).toString();
- foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ for (const auto &ext : exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
extensions.push_back(ext);
const auto mts = reader.attributes().value(QStringLiteral("mimetype")).toString();
- foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ 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;
return true;
}
-void DefinitionData::loadHighlighting(QXmlStreamReader& reader)
+void DefinitionData::loadHighlighting(QXmlStreamReader& reader, OnlyKeywords onlyKeywords)
{
Q_ASSERT(reader.name() == QLatin1String("highlighting"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ // skip highlighting
+ reader.readNext();
+
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
if (reader.name() == QLatin1String("list")) {
- KeywordList keywords;
- keywords.load(reader);
- keywordLists.insert(keywords.name(), keywords);
+ 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")) {
@@ -522,6 +544,19 @@ void DefinitionData::loadHighlighting(QXmlStreamReader& reader)
}
}
+void DefinitionData::resolveIncludeKeywords()
+{
+ if (keywordIsLoaded) {
+ return;
+ }
+
+ keywordIsLoaded = true;
+
+ for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it) {
+ it->resolveIncludeKeywords(*this);
+ }
+}
+
void DefinitionData::loadContexts(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("contexts"));
@@ -598,7 +633,7 @@ void DefinitionData::loadGeneral(QXmlStreamReader& reader)
std::sort(wordDelimiters.begin(), wordDelimiters.end());
auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
- foreach (const auto c, reader.attributes().value(QLatin1String("weakDeliminator")))
+ for (const auto c : reader.attributes().value(QLatin1String("weakDeliminator")))
wordDelimiters.remove(c);
// adaptWordWrapDelimiters, and sort
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
index ab95a9552c..9bbf59691c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
@@ -46,6 +46,9 @@ public:
DefinitionData();
~DefinitionData();
+ DefinitionData(const DefinitionData &) = delete;
+ DefinitionData &operator=(const DefinitionData &) = delete;
+
static DefinitionData* get(const Definition &def);
bool isLoaded() const;
@@ -54,9 +57,11 @@ public:
void clear();
- bool load();
+ enum class OnlyKeywords : bool;
+
+ bool load(OnlyKeywords onlyKeywords = OnlyKeywords(false));
bool loadLanguage(QXmlStreamReader &reader);
- void loadHighlighting(QXmlStreamReader &reader);
+ void loadHighlighting(QXmlStreamReader &reader, OnlyKeywords onlyKeywords);
void loadContexts(QXmlStreamReader &reader);
void loadItemData(QXmlStreamReader &reader);
void loadGeneral(QXmlStreamReader &reader);
@@ -65,6 +70,8 @@ public:
void loadSpellchecking(QXmlStreamReader &reader);
bool checkKateVersion(const QStringRef &verStr);
+ void resolveIncludeKeywords();
+
KeywordList *keywordList(const QString &name);
bool isWordDelimiter(QChar c) const;
@@ -83,6 +90,7 @@ public:
QHash<QString, Format> formats;
QString wordDelimiters;
QString wordWrapDelimiters;
+ bool keywordIsLoaded = false;
bool hasFoldingRegions = false;
bool indentationBasedFolding = false;
QStringList foldingIgnoreList;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
index 397da6d700..d1808cafef 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
@@ -213,52 +213,52 @@ void FormatPrivate::load(QXmlStreamReader& reader)
name = reader.attributes().value(QStringLiteral("name")).toString();
defaultStyle = stringToDefaultFormat(reader.attributes().value(QStringLiteral("defStyleNum")));
- QStringRef ref = reader.attributes().value(QStringLiteral("color"));
- if (!ref.isEmpty()) {
- style.textColor = QColor(ref.toString()).rgba();
+ QStringRef attribute = reader.attributes().value(QStringLiteral("color"));
+ if (!attribute.isEmpty()) {
+ style.textColor = QColor(attribute.toString()).rgba();
}
- ref = reader.attributes().value(QStringLiteral("selColor"));
- if (!ref.isEmpty()) {
- style.selectedTextColor = QColor(ref.toString()).rgba();
+ attribute = reader.attributes().value(QStringLiteral("selColor"));
+ if (!attribute.isEmpty()) {
+ style.selectedTextColor = QColor(attribute.toString()).rgba();
}
- ref = reader.attributes().value(QStringLiteral("backgroundColor"));
- if (!ref.isEmpty()) {
- style.backgroundColor = QColor(ref.toString()).rgba();
+ attribute = reader.attributes().value(QStringLiteral("backgroundColor"));
+ if (!attribute.isEmpty()) {
+ style.backgroundColor = QColor(attribute.toString()).rgba();
}
- ref = reader.attributes().value(QStringLiteral("selBackgroundColor"));
- if (!ref.isEmpty()) {
- style.selectedBackgroundColor = QColor(ref.toString()).rgba();
+ attribute = reader.attributes().value(QStringLiteral("selBackgroundColor"));
+ if (!attribute.isEmpty()) {
+ style.selectedBackgroundColor = QColor(attribute.toString()).rgba();
}
- ref = reader.attributes().value(QStringLiteral("italic"));
- if (!ref.isEmpty()) {
+ attribute = reader.attributes().value(QStringLiteral("italic"));
+ if (!attribute.isEmpty()) {
style.hasItalic = true;
- style.italic = Xml::attrToBool(ref);
+ style.italic = Xml::attrToBool(attribute);
}
- ref = reader.attributes().value(QStringLiteral("bold"));
- if (!ref.isEmpty()) {
+ attribute = reader.attributes().value(QStringLiteral("bold"));
+ if (!attribute.isEmpty()) {
style.hasBold = true;
- style.bold = Xml::attrToBool(ref);
+ style.bold = Xml::attrToBool(attribute);
}
- ref = reader.attributes().value(QStringLiteral("underline"));
- if (!ref.isEmpty()) {
+ attribute = reader.attributes().value(QStringLiteral("underline"));
+ if (!attribute.isEmpty()) {
style.hasUnderline = true;
- style.underline = Xml::attrToBool(ref);
+ style.underline = Xml::attrToBool(attribute);
}
- ref = reader.attributes().value(QStringLiteral("strikeOut"));
- if (!ref.isEmpty()) {
+ attribute = reader.attributes().value(QStringLiteral("strikeOut"));
+ if (!attribute.isEmpty()) {
style.hasStrikeThrough = true;
- style.strikeThrough = Xml::attrToBool(ref);
+ style.strikeThrough = Xml::attrToBool(attribute);
}
- ref = reader.attributes().value(QStringLiteral("spellChecking"));
- if (!ref.isEmpty()) {
- spellCheck = Xml::attrToBool(ref);
+ attribute = reader.attributes().value(QStringLiteral("spellChecking"));
+ if (!attribute.isEmpty()) {
+ spellCheck = Xml::attrToBool(attribute);
}
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
index fe5f77586a..f042baac27 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -22,6 +22,9 @@
*/
#include "keywordlist_p.h"
+#include "repository.h"
+#include "definition_p.h"
+#include "ksyntaxhighlighting_logging.h"
#include <QDebug>
#include <QXmlStreamReader>
@@ -58,6 +61,11 @@ void KeywordList::load(QXmlStreamReader& reader)
reader.readNextStartElement();
break;
}
+ else if (reader.name() == QLatin1String("include")) {
+ m_includes.append(reader.readElementText().trimmed());
+ reader.readNextStartElement();
+ break;
+ }
reader.readNext();
break;
case QXmlStreamReader::EndElement:
@@ -102,3 +110,40 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive
*/
std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
}
+
+void KeywordList::resolveIncludeKeywords(DefinitionData &def)
+{
+ while (!m_includes.isEmpty()) {
+ const auto kw_include = std::move(m_includes.back());
+ m_includes.pop_back();
+
+ const auto idx = kw_include.indexOf(QLatin1String("##"));
+ KeywordList *keywords = nullptr;
+
+ if (idx >= 0) {
+ auto listName = kw_include.left(idx);
+ auto defName = kw_include.mid(idx + 2);
+ auto includeDef = def.repo->definitionForName(defName);
+ if (includeDef.isValid()) {
+ auto defData = DefinitionData::get(includeDef);
+ defData->load(DefinitionData::OnlyKeywords(true));
+ keywords = defData->keywordList(listName);
+ }
+ else {
+ qCWarning(Log) << "Unable to resolve external include keyword for definition" << defName << "in" << def.name;
+ }
+ } else {
+ keywords = def.keywordList(kw_include);
+ }
+
+ if (keywords) {
+ if (this != keywords) {
+ keywords->resolveIncludeKeywords(def);
+ }
+ m_keywords += keywords->m_keywords;
+ }
+ else {
+ qCWarning(Log) << "Unresolved include keyword" << kw_include << "in" << def.name;
+ }
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
index 8c41aabe0c..25d0022dbe 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
@@ -36,6 +36,9 @@ QT_END_NAMESPACE
namespace KSyntaxHighlighting {
+class Repository;
+class DefinitionData;
+
class KeywordList
{
public:
@@ -69,6 +72,7 @@ public:
void load(QXmlStreamReader &reader);
void setCaseSensitivity(Qt::CaseSensitivity caseSensitive);
void initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive);
+ void resolveIncludeKeywords(DefinitionData &def);
private:
/**
@@ -82,6 +86,11 @@ private:
QStringList m_keywords;
/**
+ * raw list of include keywords, as seen in XML (but trimmed)
+ */
+ QStringList m_includes;
+
+ /**
* default case-sensitivity setting
*/
Qt::CaseSensitivity m_caseSensitive = Qt::CaseSensitive;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
index 922225a7e1..aaba9616dc 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -69,7 +69,7 @@ Repository::~Repository()
{
// reset repo so we can detect in still alive definition instances
// that the repo was deleted
- foreach (const auto &def, d->m_sortedDefs)
+ for (const auto &def : qAsConst(d->m_sortedDefs))
DefinitionData::get(def)->repo = nullptr;
}
@@ -78,21 +78,16 @@ Definition Repository::definitionForName(const QString& defName) const
return d->m_defs.value(defName);
}
-static Definition bestCandidate(QVector<Definition> &&candidates)
+static void sortDefinitions(QVector<Definition> &definitions)
{
- if (candidates.isEmpty())
- return Definition();
-
- std::partial_sort(candidates.begin(), candidates.begin() + 1, candidates.end(), [](const Definition &lhs, const Definition &rhs) {
+ std::stable_sort(definitions.begin(), definitions.end(), [](const Definition &lhs, const Definition &rhs) {
return lhs.priority() > rhs.priority();
});
-
- return candidates.at(0);
}
Definition Repository::definitionForFileName(const QString& fileName) const
{
- return bestCandidate(definitionsForFileName(fileName));
+ return definitionsForFileName(fileName).value(0);
}
QVector<Definition> Repository::definitionsForFileName(const QString &fileName) const
@@ -101,9 +96,8 @@ QVector<Definition> Repository::definitionsForFileName(const QString &fileName)
const auto name = fi.fileName();
QVector<Definition> candidates;
- for (auto it = d->m_defs.constBegin(); it != d->m_defs.constEnd(); ++it) {
- auto def = it.value();
- foreach (const auto &pattern, def.extensions()) {
+ for (const Definition &def : qAsConst(d->m_sortedDefs)) {
+ for (const auto &pattern : def.extensions()) {
if (WildcardMatcher::exactMatch(name, pattern)) {
candidates.push_back(def);
break;
@@ -111,26 +105,28 @@ QVector<Definition> Repository::definitionsForFileName(const QString &fileName)
}
}
+ sortDefinitions(candidates);
return candidates;
}
Definition Repository::definitionForMimeType(const QString& mimeType) const
{
- return bestCandidate(definitionsForMimeType(mimeType));
+ return definitionsForMimeType(mimeType).value(0);
}
QVector<Definition> Repository::definitionsForMimeType(const QString &mimeType) const
{
QVector<Definition> candidates;
- for (auto it = d->m_defs.constBegin(); it != d->m_defs.constEnd(); ++it) {
- auto def = it.value();
- foreach (const auto &matchType, def.mimeTypes()) {
+ for (const Definition &def : qAsConst(d->m_sortedDefs)) {
+ for (const auto &matchType : def.mimeTypes()) {
if (mimeType == matchType) {
candidates.push_back(def);
break;
}
}
}
+
+ sortDefinitions(candidates);
return candidates;
}
@@ -169,11 +165,11 @@ void RepositoryPrivate::load(Repository *repo)
// do lookup in standard paths, if not disabled
#ifndef NO_STANDARD_PATHS
- foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory))
+ for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory))
loadSyntaxFolder(repo, dir);
// backward compatibility with Kate
- foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory))
+ for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory))
loadSyntaxFolder(repo, dir);
#endif
@@ -181,7 +177,7 @@ void RepositoryPrivate::load(Repository *repo)
loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax"));
// user given extra paths
- foreach (const auto &path, m_customSearchPaths)
+ for (const auto &path : qAsConst(m_customSearchPaths))
loadSyntaxFolder(repo, path + QStringLiteral("/syntax"));
m_sortedDefs.reserve(m_defs.size());
@@ -198,7 +194,7 @@ void RepositoryPrivate::load(Repository *repo)
// do lookup in standard paths, if not disabled
#ifndef NO_STANDARD_PATHS
- foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory))
+ for (const auto &dir : QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory))
loadThemeFolder(dir);
#endif
@@ -206,7 +202,7 @@ void RepositoryPrivate::load(Repository *repo)
loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes"));
// user given extra paths
- foreach (const auto &path, m_customSearchPaths)
+ for (const auto &path : qAsConst(m_customSearchPaths))
loadThemeFolder(path + QStringLiteral("/themes"));
}
@@ -307,7 +303,7 @@ quint16 RepositoryPrivate::nextFormatId()
void Repository::reload()
{
qCDebug(Log) << "Reloading syntax definitions!";
- foreach (const auto &def, d->m_sortedDefs)
+ for (const auto &def : qAsConst(d->m_sortedDefs))
DefinitionData::get(def)->clear();
d->m_defs.clear();
d->m_sortedDefs.clear();
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
index e4e9bed69f..2bc66965cf 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -167,9 +167,11 @@ public:
Definition definitionForFileName(const QString &fileName) const;
/**
- * Returns all Definition%s for the file named @p fileName.
+ * Returns all Definition%s for the file named @p fileName sorted by priority.
* The match is performed based on the \e extensions and @e mimetype of
* the definition files.
+ *
+ * @since 5.56
*/
QVector<Definition> definitionsForFileName(const QString &fileName) const;
@@ -184,7 +186,9 @@ public:
Definition definitionForMimeType(const QString &mimeType) const;
/**
- * Returns all Definition%s to the type named @p mimeType
+ * Returns all Definition%s to the type named @p mimeType sorted by priority
+ *
+ * @since 5.56
*/
QVector<Definition> definitionsForMimeType(const QString &mimeType) const;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index c48753bf0c..d9cf5eb211 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -59,7 +59,8 @@ static int matchEscapedChar(const QString &text, int offset)
if (controlChars.contains(c))
return offset + 2;
- if (c == QLatin1Char('x')) { // hex encoded character
+ // hex encoded character
+ if (c == QLatin1Char('x')) {
auto newOffset = offset + 2;
for (int i = 0; i < 2 && newOffset + i < text.size(); ++i, ++newOffset) {
if (!isHexChar(text.at(newOffset)))
@@ -70,14 +71,13 @@ static int matchEscapedChar(const QString &text, int offset)
return newOffset;
}
- if (isOctalChar(c)) { // octal encoding
+ // octal encoding, simple \0 is OK, too, unlike simple \x above
+ if (isOctalChar(c)) {
auto newOffset = offset + 2;
for (int i = 0; i < 2 && newOffset + i < text.size(); ++i, ++newOffset) {
if (!isOctalChar(text.at(newOffset)))
break;
}
- if (newOffset == offset + 2)
- return offset;
return newOffset;
}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
index 2bb61a7ae6..4987dc95f0 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -156,15 +156,15 @@ void SyntaxHighlighter::highlightBlock(const QString& text)
void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format)
{
- if (format.isDefaultTextStyle(theme()) || length == 0)
+ if (length == 0)
return;
QTextCharFormat tf;
- if (format.hasTextColor(theme()))
- tf.setForeground(format.textColor(theme()));
+ // always set the foreground color to avoid palette issues
+ tf.setForeground(format.textColor(theme()));
+
if (format.hasBackgroundColor(theme()))
tf.setBackground(format.backgroundColor(theme()));
-
if (format.isBold(theme()))
tf.setFontWeight(QFont::Bold);
if (format.isItalic(theme()))