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