1// Scintilla source code edit control
2/** @file SubStyles.h
3 ** Manage substyles for a lexer.
4 **/
5// Copyright 2012 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#ifndef SUBSTYLES_H
9#define SUBSTYLES_H
10
11namespace Lexilla {
12
13class WordClassifier {
14 int baseStyle;
15 int firstStyle;
16 int lenStyles;
17 using WordStyleMap = std::map<std::string, int, std::less<>>;
18 WordStyleMap wordToStyle;
19
20public:
21
22 explicit WordClassifier(int baseStyle_) : baseStyle(baseStyle_), firstStyle(0), lenStyles(0) {
23 }
24
25 void Allocate(int firstStyle_, int lenStyles_) {
26 firstStyle = firstStyle_;
27 lenStyles = lenStyles_;
28 wordToStyle.clear();
29 }
30
31 int Base() const noexcept {
32 return baseStyle;
33 }
34
35 int Start() const noexcept {
36 return firstStyle;
37 }
38
39 int Last() const noexcept {
40 return firstStyle + lenStyles - 1;
41 }
42
43 int Length() const noexcept {
44 return lenStyles;
45 }
46
47 void Clear() noexcept {
48 firstStyle = 0;
49 lenStyles = 0;
50 wordToStyle.clear();
51 }
52
53 int ValueFor(std::string_view s) const {
54 WordStyleMap::const_iterator it = wordToStyle.find(s);
55 if (it != wordToStyle.end())
56 return it->second;
57 else
58 return -1;
59 }
60
61 bool IncludesStyle(int style) const noexcept {
62 return (style >= firstStyle) && (style < (firstStyle + lenStyles));
63 }
64
65 void RemoveStyle(int style) noexcept {
66 WordStyleMap::iterator it = wordToStyle.begin();
67 while (it != wordToStyle.end()) {
68 if (it->second == style) {
69 it = wordToStyle.erase(it);
70 } else {
71 ++it;
72 }
73 }
74 }
75
76 void SetIdentifiers(int style, const char *identifiers) {
77 RemoveStyle(style);
78 if (!identifiers)
79 return;
80 while (*identifiers) {
81 const char *cpSpace = identifiers;
82 while (*cpSpace && !(*cpSpace == ' ' || *cpSpace == '\t' || *cpSpace == '\r' || *cpSpace == '\n'))
83 cpSpace++;
84 if (cpSpace > identifiers) {
85 std::string word(identifiers, cpSpace - identifiers);
86 wordToStyle[word] = style;
87 }
88 identifiers = cpSpace;
89 if (*identifiers)
90 identifiers++;
91 }
92 }
93};
94
95class SubStyles {
96 int classifications;
97 const char *baseStyles;
98 int styleFirst;
99 int stylesAvailable;
100 int secondaryDistance;
101 int allocated;
102 std::vector<WordClassifier> classifiers;
103
104 int BlockFromBaseStyle(int baseStyle) const noexcept {
105 for (int b=0; b < classifications; b++) {
106 if (baseStyle == baseStyles[b])
107 return b;
108 }
109 return -1;
110 }
111
112 int BlockFromStyle(int style) const noexcept {
113 int b = 0;
114 for (const WordClassifier &wc : classifiers) {
115 if (wc.IncludesStyle(style))
116 return b;
117 b++;
118 }
119 return -1;
120 }
121
122public:
123
124 SubStyles(const char *baseStyles_, int styleFirst_, int stylesAvailable_, int secondaryDistance_) :
125 classifications(0),
126 baseStyles(baseStyles_),
127 styleFirst(styleFirst_),
128 stylesAvailable(stylesAvailable_),
129 secondaryDistance(secondaryDistance_),
130 allocated(0) {
131 while (baseStyles[classifications]) {
132 classifiers.push_back(WordClassifier(baseStyles[classifications]));
133 classifications++;
134 }
135 }
136
137 int Allocate(int styleBase, int numberStyles) {
138 const int block = BlockFromBaseStyle(styleBase);
139 if (block >= 0) {
140 if ((allocated + numberStyles) > stylesAvailable)
141 return -1;
142 const int startBlock = styleFirst + allocated;
143 allocated += numberStyles;
144 classifiers[block].Allocate(startBlock, numberStyles);
145 return startBlock;
146 } else {
147 return -1;
148 }
149 }
150
151 int Start(int styleBase) noexcept {
152 const int block = BlockFromBaseStyle(styleBase);
153 return (block >= 0) ? classifiers[block].Start() : -1;
154 }
155
156 int Length(int styleBase) noexcept {
157 const int block = BlockFromBaseStyle(styleBase);
158 return (block >= 0) ? classifiers[block].Length() : 0;
159 }
160
161 int BaseStyle(int subStyle) const noexcept {
162 const int block = BlockFromStyle(subStyle);
163 if (block >= 0)
164 return classifiers[block].Base();
165 else
166 return subStyle;
167 }
168
169 int DistanceToSecondaryStyles() const noexcept {
170 return secondaryDistance;
171 }
172
173 int FirstAllocated() const noexcept {
174 int start = 257;
175 for (const WordClassifier &wc : classifiers) {
176 if ((wc.Length() > 0) && (start > wc.Start()))
177 start = wc.Start();
178 }
179 return (start < 256) ? start : -1;
180 }
181
182 int LastAllocated() const noexcept {
183 int last = -1;
184 for (const WordClassifier &wc : classifiers) {
185 if ((wc.Length() > 0) && (last < wc.Last()))
186 last = wc.Last();
187 }
188 return last;
189 }
190
191 void SetIdentifiers(int style, const char *identifiers) {
192 const int block = BlockFromStyle(style);
193 if (block >= 0)
194 classifiers[block].SetIdentifiers(style, identifiers);
195 }
196
197 void Free() noexcept {
198 allocated = 0;
199 for (WordClassifier &wc : classifiers) {
200 wc.Clear();
201 }
202 }
203
204 const WordClassifier &Classifier(int baseStyle) const noexcept {
205 const int block = BlockFromBaseStyle(baseStyle);
206 return classifiers[block >= 0 ? block : 0];
207 }
208};
209
210}
211
212#endif
213