KSyntaxHighlighting

context.cpp
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 "context_p.h"
9#include "definition_p.h"
10#include "format.h"
11#include "ksyntaxhighlighting_logging.h"
12#include "rule_p.h"
13#include "xml_p.h"
14
15#include <QString>
16#include <QXmlStreamReader>
17
18using namespace KSyntaxHighlighting;
19
20Context::Context(const DefinitionData &def, const HighlightingContextData &data)
21 : m_name(data.name)
22 , m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute))
23 , m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding)
24{
25 if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) {
26 qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name;
27 }
28}
29
30bool Context::indentationBasedFoldingEnabled() const
31{
32 return m_indentationBasedFolding;
33}
34
35void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data)
36{
37 m_lineEndContext.resolve(def, data.lineEndContext);
38 m_lineEmptyContext.resolve(def, data.lineEmptyContext);
39 m_fallthroughContext.resolve(def, data.fallthroughContext);
40 m_stopEmptyLineContextSwitchLoop = data.stopEmptyLineContextSwitchLoop;
41
42 /**
43 * line end context switches only when lineEmptyContext is #stay. This avoids
44 * skipping empty lines after a line continuation character (see bug 405903)
45 */
46 if (m_lineEmptyContext.isStay()) {
47 m_lineEmptyContext = m_lineEndContext;
48 }
49
50 m_rules.reserve(data.rules.size());
51 for (const auto &ruleData : data.rules) {
52 m_rules.push_back(Rule::create(def, ruleData, m_name));
53 if (!m_rules.back()) {
54 m_rules.pop_back();
55 }
56 }
57}
58
59void Context::resolveIncludes(DefinitionData &def)
60{
61 if (m_resolveState == Resolved) {
62 return;
63 }
64 if (m_resolveState == Resolving) {
65 qCWarning(Log) << "Cyclic dependency!";
66 return;
67 }
68
69 Q_ASSERT(m_resolveState == Unresolved);
70 m_resolveState = Resolving; // cycle guard
71
72 for (auto it = m_rules.begin(); it != m_rules.end();) {
73 const IncludeRules *includeRules = it->get()->castToIncludeRules();
74 if (!includeRules) {
75 m_hasDynamicRule = m_hasDynamicRule || it->get()->isDynamic();
76 ++it;
77 continue;
78 }
79
80 const QStringView includeContext = includeRules->contextName();
81 const qsizetype idx = includeContext.indexOf(QLatin1String("##"));
82
83 Context *context = nullptr;
84 DefinitionData *defData = &def;
85
86 if (idx <= -1) { // local include
87 context = def.contextByName(includeContext);
88 } else {
89 const auto definitionName = includeContext.sliced(idx + 2);
90 const auto contextName = includeContext.sliced(0, idx);
91 auto resolvedContext = def.resolveIncludedContext(definitionName, contextName);
92 defData = resolvedContext.def;
93 context = resolvedContext.context;
94 if (!defData) {
95 qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name;
96 }
97 }
98
99 if (!context) {
100 qCWarning(Log) << "Unable to resolve include rule for definition" << includeContext << "in" << def.name;
101 ++it;
102 continue;
103 }
104
105 if (context == this) {
106 qCWarning(Log) << "Unable to resolve self include rule for definition" << includeContext << "in" << def.name;
107 ++it;
108 continue;
109 }
110
111 if (context->m_resolveState != Resolved) {
112 context->resolveIncludes(*defData);
113 }
114
115 m_hasDynamicRule = m_hasDynamicRule || context->m_hasDynamicRule;
116
117 /**
118 * handle included attribute
119 * transitive closure: we might include attributes included from somewhere else
120 */
121 if (includeRules->includeAttribute()) {
122 m_attributeFormat = context->m_attributeFormat;
123 }
124
125 it = m_rules.erase(it);
126 it = m_rules.insert(it, context->rules().begin(), context->rules().end());
127 it += context->rules().size();
128 }
129
130 m_resolveState = Resolved;
131}
Describes the format to be used for a specific text fragment.
Definition format.h:28
Represents the raw xml data of a context and its rules.
QString attribute
attribute name, to lookup our format
QString name(const QVariant &location)
Syntax highlighting engine for Kate syntax definitions.
bool isEmpty() const const
qsizetype indexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const const
QStringView sliced(qsizetype pos) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Mar 28 2025 11:51:45 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.