File indexing completed on 2024-05-12 15:50:03

0001 /*
0002     SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org>
0003     SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
0004 
0005     SPDX-License-Identifier: MIT
0006 */
0007 
0008 #include "context_p.h"
0009 #include "definition_p.h"
0010 #include "format.h"
0011 #include "ksyntaxhighlighting_logging.h"
0012 #include "repository.h"
0013 #include "rule_p.h"
0014 #include "xml_p.h"
0015 
0016 #include <QString>
0017 #include <QXmlStreamReader>
0018 
0019 using namespace KSyntaxHighlighting;
0020 
0021 Context::Context(const DefinitionData &def, const HighlightingContextData &data)
0022     : m_name(data.name)
0023     , m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute))
0024     , m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding)
0025 {
0026     if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) {
0027         qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name;
0028     }
0029 }
0030 
0031 bool Context::indentationBasedFoldingEnabled() const
0032 {
0033     return m_indentationBasedFolding;
0034 }
0035 
0036 void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data)
0037 {
0038     m_lineEndContext.resolve(def, data.lineEndContext);
0039     m_lineEmptyContext.resolve(def, data.lineEmptyContext);
0040     m_fallthroughContext.resolve(def, data.fallthroughContext);
0041     m_fallthrough = !m_fallthroughContext.isStay();
0042 
0043     m_rules.reserve(data.rules.size());
0044     for (const auto &ruleData : data.rules) {
0045         m_rules.push_back(Rule::create(def, ruleData, m_name));
0046         if (!m_rules.back()) {
0047             m_rules.pop_back();
0048         }
0049     }
0050 }
0051 
0052 void Context::resolveIncludes(DefinitionData &def)
0053 {
0054     if (m_resolveState == Resolved) {
0055         return;
0056     }
0057     if (m_resolveState == Resolving) {
0058         qCWarning(Log) << "Cyclic dependency!";
0059         return;
0060     }
0061 
0062     Q_ASSERT(m_resolveState == Unresolved);
0063     m_resolveState = Resolving; // cycle guard
0064 
0065     for (auto it = m_rules.begin(); it != m_rules.end();) {
0066         const IncludeRules *includeRules = it->get()->castToIncludeRules();
0067         if (!includeRules) {
0068             ++it;
0069             continue;
0070         }
0071 
0072         Context *context = nullptr;
0073         DefinitionData *defData = &def;
0074 
0075         const auto &contextName = includeRules->contextName();
0076         const int idx = contextName.indexOf(QLatin1String("##"));
0077 
0078         if (idx == -1) { // local include
0079             context = def.contextByName(contextName);
0080         } else {
0081             auto definitionName = contextName.mid(idx + 2);
0082             auto includedDef = def.repo->definitionForName(definitionName);
0083             if (!includedDef.isValid()) {
0084                 qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name;
0085                 ++it;
0086                 continue;
0087             }
0088             defData = DefinitionData::get(includedDef);
0089             def.addImmediateIncludedDefinition(includedDef);
0090             defData->load();
0091             if (idx == 0) {
0092                 context = defData->initialContext();
0093             } else {
0094                 context = defData->contextByName(QStringView(contextName).left(idx));
0095             }
0096         }
0097 
0098         if (!context) {
0099             qCWarning(Log) << "Unable to resolve include rule for definition" << contextName << "in" << def.name;
0100             ++it;
0101             continue;
0102         }
0103 
0104         if (context == this) {
0105             qCWarning(Log) << "Unable to resolve self include rule for definition" << contextName << "in" << def.name;
0106             ++it;
0107             continue;
0108         }
0109 
0110         if (context->m_resolveState != Resolved) {
0111             context->resolveIncludes(*defData);
0112         }
0113 
0114         /**
0115          * handle included attribute
0116          * transitive closure: we might include attributes included from somewhere else
0117          */
0118         if (includeRules->includeAttribute()) {
0119             m_attributeFormat = context->m_attributeFormat;
0120         }
0121 
0122         it = m_rules.erase(it);
0123         it = m_rules.insert(it, context->rules().begin(), context->rules().end());
0124         it += context->rules().size();
0125     }
0126 
0127     m_resolveState = Resolved;
0128 }