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