aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp')
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp217
1 files changed, 75 insertions, 142 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
index 9887b959d0..af269d14d0 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
@@ -1,32 +1,16 @@
/*
- Copyright (C) 2016 Volker Krause <vkrause@kde.org>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
+ SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
+
+ SPDX-License-Identifier: MIT
*/
#include "context_p.h"
#include "definition_p.h"
#include "format.h"
+#include "ksyntaxhighlighting_logging.h"
#include "repository.h"
#include "rule_p.h"
-#include "ksyntaxhighlighting_logging.h"
#include "xml_p.h"
#include <QString>
@@ -34,173 +18,122 @@
using namespace KSyntaxHighlighting;
-Definition Context::definition() const
-{
- return m_def.definition();
-}
-
-void Context::setDefinition(const DefinitionRef &def)
+Context::Context(const DefinitionData &def, const HighlightingContextData &data)
+ : m_name(data.name)
+ , m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute))
+ , m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding)
{
- m_def = def;
+ if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) {
+ qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name;
+ }
}
bool Context::indentationBasedFoldingEnabled() const
{
- if (m_noIndentationBasedFolding)
- return false;
-
- return m_def.definition().indentationBasedFoldingEnabled();
+ return m_indentationBasedFolding;
}
-void Context::load(QXmlStreamReader& reader)
+void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data)
{
- Q_ASSERT(reader.name() == QLatin1String("context"));
- Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
-
- m_name = reader.attributes().value(QStringLiteral("name")).toString();
- m_attribute = reader.attributes().value(QStringLiteral("attribute")).toString();
- m_lineEndContext.parse(reader.attributes().value(QStringLiteral("lineEndContext")));
- m_lineEmptyContext.parse(reader.attributes().value(QStringLiteral("lineEmptyContext")));
- m_fallthrough = Xml::attrToBool(reader.attributes().value(QStringLiteral("fallthrough")));
- m_fallthroughContext.parse(reader.attributes().value(QStringLiteral("fallthroughContext")));
- if (m_fallthroughContext.isStay())
- m_fallthrough = false;
- m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("noIndentationBasedFolding")));
-
- reader.readNext();
- while (!reader.atEnd()) {
- switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- {
- auto rule = Rule::create(reader.name());
- if (rule) {
- rule->setDefinition(m_def.definition());
- if (rule->load(reader))
- m_rules.push_back(rule);
- } else {
- reader.skipCurrentElement();
- }
- reader.readNext();
- break;
- }
- case QXmlStreamReader::EndElement:
- return;
- default:
- reader.readNext();
- break;
- }
- }
-}
+ m_lineEndContext.resolve(def, data.lineEndContext);
+ m_lineEmptyContext.resolve(def, data.lineEmptyContext);
+ m_fallthroughContext.resolve(def, data.fallthroughContext);
+ m_stopEmptyLineContextSwitchLoop = data.stopEmptyLineContextSwitchLoop;
-void Context::resolveContexts()
-{
- const auto def = m_def.definition();
- m_lineEndContext.resolve(def);
- m_lineEmptyContext.resolve(def);
- m_fallthroughContext.resolve(def);
- for (const auto &rule : m_rules)
- rule->resolveContext();
-}
+ /**
+ * line end context switches only when lineEmptyContext is #stay. This avoids
+ * skipping empty lines after a line continuation character (see bug 405903)
+ */
+ if (m_lineEmptyContext.isStay()) {
+ m_lineEmptyContext = m_lineEndContext;
+ }
-Context::ResolveState Context::resolveState()
-{
- if (m_resolveState == Unknown) {
- for (const auto &rule : m_rules) {
- auto inc = std::dynamic_pointer_cast<IncludeRules>(rule);
- if (inc) {
- m_resolveState = Unresolved;
- return m_resolveState;
- }
+ m_rules.reserve(data.rules.size());
+ for (const auto &ruleData : data.rules) {
+ m_rules.push_back(Rule::create(def, ruleData, m_name));
+ if (!m_rules.back()) {
+ m_rules.pop_back();
}
- m_resolveState = Resolved;
}
- return m_resolveState;
}
-void Context::resolveIncludes()
+void Context::resolveIncludes(DefinitionData &def)
{
- if (resolveState() == Resolved)
+ if (m_resolveState == Resolved) {
return;
- if (resolveState() == Resolving) {
+ }
+ if (m_resolveState == Resolving) {
qCWarning(Log) << "Cyclic dependency!";
return;
}
- Q_ASSERT(resolveState() == Unresolved);
+ Q_ASSERT(m_resolveState == Unresolved);
m_resolveState = Resolving; // cycle guard
for (auto it = m_rules.begin(); it != m_rules.end();) {
- auto inc = std::dynamic_pointer_cast<IncludeRules>(*it);
- if (!inc) {
+ const IncludeRules *includeRules = it->get()->castToIncludeRules();
+ if (!includeRules) {
+ m_hasDynamicRule = m_hasDynamicRule || it->get()->isDynamic();
++it;
continue;
}
- Context* context = nullptr;
- auto myDefData = DefinitionData::get(m_def.definition());
- if (inc->definitionName().isEmpty()) { // local include
- context = myDefData->contextByName(inc->contextName());
+
+ Context *context = nullptr;
+ DefinitionData *defData = &def;
+
+ const auto &contextName = includeRules->contextName();
+ const int idx = contextName.indexOf(QLatin1String("##"));
+
+ if (idx == -1) { // local include
+ context = def.contextByName(contextName);
} else {
- auto def = myDefData->repo->definitionForName(inc->definitionName());
- if (!def.isValid()) {
- qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name();
+ auto definitionName = contextName.mid(idx + 2);
+ auto includedDef = def.repo->definitionForName(definitionName);
+ if (!includedDef.isValid()) {
+ qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name;
++it;
continue;
}
- auto defData = DefinitionData::get(def);
+ defData = DefinitionData::get(includedDef);
+ def.addImmediateIncludedDefinition(includedDef);
defData->load();
- if (inc->contextName().isEmpty())
+ if (idx == 0) {
context = defData->initialContext();
- else
- context = defData->contextByName(inc->contextName());
+ } else {
+ context = defData->contextByName(QStringView(contextName).left(idx));
+ }
}
+
if (!context) {
- qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" << m_def.definition().name();
+ qCWarning(Log) << "Unable to resolve include rule for definition" << contextName << "in" << def.name;
+ ++it;
+ continue;
+ }
+
+ if (context == this) {
+ qCWarning(Log) << "Unable to resolve self include rule for definition" << contextName << "in" << def.name;
++it;
continue;
}
- context->resolveIncludes();
+
+ if (context->m_resolveState != Resolved) {
+ context->resolveIncludes(*defData);
+ }
+
+ m_hasDynamicRule = m_hasDynamicRule || context->m_hasDynamicRule;
/**
* handle included attribute
* transitive closure: we might include attributes included from somewhere else
*/
- if (inc->includeAttribute()) {
- m_attribute = context->m_attribute;
- m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context;
+ if (includeRules->includeAttribute()) {
+ m_attributeFormat = context->m_attributeFormat;
}
it = m_rules.erase(it);
- for (const auto &rule : context->rules()) {
- it = m_rules.insert(it, rule);
- ++it;
- }
+ it = m_rules.insert(it, context->rules().begin(), context->rules().end());
+ it += context->rules().size();
}
m_resolveState = Resolved;
}
-
-void Context::resolveAttributeFormat()
-{
- /**
- * try to get our format from the definition we stem from
- * we need to handle included attributes via m_attributeContext
- */
- if (!m_attribute.isEmpty()) {
- const auto def = m_attributeContext ? m_attributeContext->m_def.definition() : m_def.definition();
- m_attributeFormat = DefinitionData::get(def)->formatByName(m_attribute);
- if (!m_attributeFormat.isValid()) {
- if (m_attributeContext) {
- qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name() << "from included context" << m_attributeContext->m_name << "of definition" << def.name();
- } else {
- qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name();
- }
- }
- }
-
- /**
- * lookup formats for our rules
- */
- for (const auto &rule : m_rules) {
- rule->resolveAttributeFormat(this);
- }
-}