TextMateLib 1.0
Modern C++ implementation of the TextMate syntax highlighting engine
Loading...
Searching...
No Matches
registry.cpp
1#include "registry.h"
2#include "grammar.h"
3#include "grammarDependencies.h"
4#include <iostream>
5
6namespace tml {
7
8// SyncRegistry implementation
9
10SyncRegistry::SyncRegistry(Theme* theme, IOnigLib* onigLib)
11 : _theme(theme), _onigLib(onigLib) {
12}
13
14SyncRegistry::~SyncRegistry() {
15 dispose();
16}
17
18void SyncRegistry::dispose() {
19 for (auto& pair : _grammars) {
20 if (pair.second) {
21 pair.second->dispose();
22 delete pair.second;
23 }
24 }
25 _grammars.clear();
26
27 // Note: _rawGrammars are owned by the caller, don't delete them
28 _rawGrammars.clear();
29}
30
31void SyncRegistry::setTheme(Theme* theme) {
32 _theme = theme;
33}
34
35std::vector<std::string> SyncRegistry::getColorMap() {
36 return _theme->getColorMap();
37}
38
39void SyncRegistry::addGrammar(IRawGrammar* grammar, const std::vector<ScopeName>* injectionScopeNames) {
40 _rawGrammars[grammar->scopeName] = grammar;
41
42 if (injectionScopeNames) {
43 _injectionGrammars[grammar->scopeName] = *injectionScopeNames;
44 }
45}
46
47IRawGrammar* SyncRegistry::lookup(const ScopeName& scopeName) {
48 auto it = _rawGrammars.find(scopeName);
49 if (it != _rawGrammars.end()) {
50 return it->second;
51 }
52 return nullptr;
53}
54
55std::vector<ScopeName> SyncRegistry::injections(const ScopeName& scopeName) {
56 auto it = _injectionGrammars.find(scopeName);
57 if (it != _injectionGrammars.end()) {
58 return it->second;
59 }
60 return std::vector<ScopeName>();
61}
62
63StyleAttributes* SyncRegistry::themeMatch(ScopeStack* scopePath) {
64 return _theme->match(scopePath);
65}
66
67StyleAttributes* SyncRegistry::getDefaults() {
68 return _theme->getDefaults();
69}
70
71Grammar* SyncRegistry::grammarForScopeName(
72 const ScopeName& scopeName,
73 int initialLanguage,
74 const EmbeddedLanguagesMap* embeddedLanguages,
75 const TokenTypeMap* tokenTypes,
76 BalancedBracketSelectors* balancedBracketSelectors) {
77
78 auto it = _grammars.find(scopeName);
79 if (it == _grammars.end()) {
80 IRawGrammar* rawGrammar = lookup(scopeName);
81 if (!rawGrammar) {
82 return nullptr;
83 }
84
85 Grammar* grammar = createGrammar(
86 scopeName,
87 rawGrammar,
88 initialLanguage,
89 embeddedLanguages,
90 tokenTypes,
91 balancedBracketSelectors,
92 this,
93 this,
94 _onigLib
95 );
96
97 _grammars[scopeName] = grammar;
98 return grammar;
99 }
100
101 return it->second;
102}
103
104// Registry implementation
105
106Registry::Registry(const RegistryOptions& options)
107 : _options(options) {
108
109 Theme* theme = Theme::createFromRawTheme(options.theme, options.colorMap);
110 _syncRegistry = new SyncRegistry(theme, options.onigLib);
111}
112
113Registry::~Registry() {
114 dispose();
115}
116
117void Registry::dispose() {
118 if (_syncRegistry) {
119 _syncRegistry->dispose();
120 delete _syncRegistry;
121 _syncRegistry = nullptr;
122 }
123}
124
125void Registry::setTheme(const IRawTheme* theme, const std::vector<std::string>* colorMap) {
126 Theme* newTheme = Theme::createFromRawTheme(theme, colorMap);
127 _syncRegistry->setTheme(newTheme);
128}
129
130std::vector<std::string> Registry::getColorMap() {
131 return _syncRegistry->getColorMap();
132}
133
134Grammar* Registry::loadGrammarWithEmbeddedLanguages(
135 const ScopeName& initialScopeName,
136 int initialLanguage,
137 const EmbeddedLanguagesMap& embeddedLanguages) {
138
139 return _loadGrammar(initialScopeName, initialLanguage, &embeddedLanguages, nullptr, nullptr);
140}
141
142Grammar* Registry::loadGrammarWithConfiguration(
143 const ScopeName& initialScopeName,
144 int initialLanguage,
145 const IGrammarConfiguration& configuration) {
146
147 BalancedBracketSelectors* balancedBracketSelectors = nullptr;
148 if (configuration.balancedBracketSelectors || configuration.unbalancedBracketSelectors) {
149 std::vector<std::string> balanced = configuration.balancedBracketSelectors ?
150 *configuration.balancedBracketSelectors : std::vector<std::string>();
151 std::vector<std::string> unbalanced = configuration.unbalancedBracketSelectors ?
152 *configuration.unbalancedBracketSelectors : std::vector<std::string>();
153 balancedBracketSelectors = new BalancedBracketSelectors(balanced, unbalanced);
154 }
155
156 return _loadGrammar(
157 initialScopeName,
158 initialLanguage,
159 configuration.embeddedLanguages,
160 configuration.tokenTypes,
161 balancedBracketSelectors
162 );
163}
164
165Grammar* Registry::loadGrammar(const ScopeName& initialScopeName) {
166 return _loadGrammar(initialScopeName, 0, nullptr, nullptr, nullptr);
167}
168
169Grammar* Registry::addGrammar(
170 IRawGrammar* rawGrammar,
171 const std::vector<std::string>& injections,
172 int initialLanguage,
173 const EmbeddedLanguagesMap* embeddedLanguages) {
174
175 _syncRegistry->addGrammar(rawGrammar, injections.empty() ? nullptr : &injections);
176
177 // Note: Unlike _loadGrammar, addGrammar does NOT automatically load dependencies.
178 // The caller is responsible for ensuring all required grammars are already loaded.
179 // This matches the TypeScript implementation.
180
181 return _grammarForScopeName(rawGrammar->scopeName, initialLanguage, embeddedLanguages);
182}
183
184Grammar* Registry::_loadGrammar(
185 const ScopeName& initialScopeName,
186 int initialLanguage,
187 const EmbeddedLanguagesMap* embeddedLanguages,
188 const TokenTypeMap* tokenTypes,
189 BalancedBracketSelectors* balancedBracketSelectors) {
190
191 ScopeDependencyProcessor dependencyProcessor(_syncRegistry, initialScopeName);
192
193 while (!dependencyProcessor.Q.empty()) {
194 // Save references to process
195 std::vector<AbsoluteRuleReference> toProcess;
196 while (!dependencyProcessor.Q.empty()) {
197 toProcess.push_back(dependencyProcessor.Q.front());
198 dependencyProcessor.Q.pop();
199 }
200
201 // Load the grammars
202 for (const auto& ref : toProcess) {
203 _loadSingleGrammar(ref.scopeName);
204 }
205
206 // Put references back in queue for processQueue to scan
207 for (const auto& ref : toProcess) {
208 dependencyProcessor.Q.push(ref);
209 }
210
211 // Scan those grammars for dependencies
212 dependencyProcessor.processQueue();
213 }
214
215 return _grammarForScopeName(
216 initialScopeName,
217 initialLanguage,
218 embeddedLanguages,
219 tokenTypes,
220 balancedBracketSelectors
221 );
222}
223
224void Registry::_loadSingleGrammar(const ScopeName& scopeName) {
225 if (_ensureGrammarCache.find(scopeName) != _ensureGrammarCache.end()) {
226 return;
227 }
228
229 _ensureGrammarCache[scopeName] = true;
230 _doLoadSingleGrammar(scopeName);
231}
232
233void Registry::_doLoadSingleGrammar(const ScopeName& scopeName) {
234 IRawGrammar* grammar = _options.loadGrammar(scopeName);
235 if (grammar) {
236 std::vector<ScopeName> injections;
237 if (_options.getInjections) {
238 injections = _options.getInjections(scopeName);
239 }
240 _syncRegistry->addGrammar(grammar, injections.empty() ? nullptr : &injections);
241
242 // Also load the injection grammars themselves
243 for (const auto& injectionScopeName : injections) {
244 _loadSingleGrammar(injectionScopeName);
245 }
246 }
247}
248
249Grammar* Registry::_grammarForScopeName(
250 const ScopeName& scopeName,
251 int initialLanguage,
252 const EmbeddedLanguagesMap* embeddedLanguages,
253 const TokenTypeMap* tokenTypes,
254 BalancedBracketSelectors* balancedBracketSelectors) {
255
256 return _syncRegistry->grammarForScopeName(
257 scopeName,
258 initialLanguage,
259 embeddedLanguages,
260 tokenTypes,
261 balancedBracketSelectors
262 );
263}
264
265} // namespace tml