1 | // Scintilla source code edit control |
2 | /** @file LexScriptol.cxx |
3 | ** Lexer for Scriptol. |
4 | **/ |
5 | |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | #include <stdio.h> |
9 | #include <stdarg.h> |
10 | #include <assert.h> |
11 | #include <ctype.h> |
12 | |
13 | #include <string> |
14 | #include <string_view> |
15 | |
16 | #include "ILexer.h" |
17 | #include "Scintilla.h" |
18 | #include "SciLexer.h" |
19 | |
20 | #include "WordList.h" |
21 | #include "LexAccessor.h" |
22 | #include "Accessor.h" |
23 | #include "StyleContext.h" |
24 | #include "CharacterSet.h" |
25 | #include "LexerModule.h" |
26 | |
27 | using namespace Lexilla; |
28 | |
29 | static void ClassifyWordSol(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler, char *prevWord) |
30 | { |
31 | char s[100] = "" ; |
32 | bool wordIsNumber = isdigit(styler[start]) != 0; |
33 | for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) |
34 | { |
35 | s[i] = styler[start + i]; |
36 | s[i + 1] = '\0'; |
37 | } |
38 | char chAttr = SCE_SCRIPTOL_IDENTIFIER; |
39 | if (0 == strcmp(prevWord, "class" )) chAttr = SCE_SCRIPTOL_CLASSNAME; |
40 | else if (wordIsNumber) chAttr = SCE_SCRIPTOL_NUMBER; |
41 | else if (keywords.InList(s)) chAttr = SCE_SCRIPTOL_KEYWORD; |
42 | else for (Sci_PositionU i = 0; i < end - start + 1; i++) // test dotted idents |
43 | { |
44 | if (styler[start + i] == '.') |
45 | { |
46 | styler.ColourTo(start + i - 1, chAttr); |
47 | styler.ColourTo(start + i, SCE_SCRIPTOL_OPERATOR); |
48 | } |
49 | } |
50 | styler.ColourTo(end, chAttr); |
51 | strcpy(prevWord, s); |
52 | } |
53 | |
54 | static bool (Accessor &styler, Sci_Position pos, Sci_Position len) |
55 | { |
56 | if(len > 0) |
57 | { |
58 | char c = styler[pos]; |
59 | if(c == '`') return true; |
60 | if(len > 1) |
61 | { |
62 | if(c == '/') |
63 | { |
64 | c = styler[pos + 1]; |
65 | if(c == '/') return true; |
66 | if(c == '*') return true; |
67 | } |
68 | } |
69 | } |
70 | return false; |
71 | } |
72 | |
73 | static bool IsSolStringStart(char ch) |
74 | { |
75 | if (ch == '\'' || ch == '"') return true; |
76 | return false; |
77 | } |
78 | |
79 | static bool IsSolWordStart(char ch) |
80 | { |
81 | return (iswordchar(ch) && !IsSolStringStart(ch)); |
82 | } |
83 | |
84 | |
85 | static int GetSolStringState(Accessor &styler, Sci_Position i, Sci_Position *nextIndex) |
86 | { |
87 | char ch = styler.SafeGetCharAt(i); |
88 | char chNext = styler.SafeGetCharAt(i + 1); |
89 | |
90 | if (ch != '\"' && ch != '\'') |
91 | { |
92 | *nextIndex = i + 1; |
93 | return SCE_SCRIPTOL_DEFAULT; |
94 | } |
95 | // ch is either single or double quotes in string |
96 | // code below seem non-sense but is here for future extensions |
97 | if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) |
98 | { |
99 | *nextIndex = i + 3; |
100 | if(ch == '\"') return SCE_SCRIPTOL_TRIPLE; |
101 | if(ch == '\'') return SCE_SCRIPTOL_TRIPLE; |
102 | return SCE_SCRIPTOL_STRING; |
103 | } |
104 | else |
105 | { |
106 | *nextIndex = i + 1; |
107 | if (ch == '"') return SCE_SCRIPTOL_STRING; |
108 | else return SCE_SCRIPTOL_STRING; |
109 | } |
110 | } |
111 | |
112 | |
113 | static void ColouriseSolDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, |
114 | WordList *keywordlists[], Accessor &styler) |
115 | { |
116 | |
117 | Sci_Position lengthDoc = startPos + length; |
118 | char stringType = '\"'; |
119 | |
120 | if (startPos > 0) |
121 | { |
122 | Sci_Position lineCurrent = styler.GetLine(startPos); |
123 | if (lineCurrent > 0) |
124 | { |
125 | startPos = styler.LineStart(lineCurrent-1); |
126 | if (startPos == 0) initStyle = SCE_SCRIPTOL_DEFAULT; |
127 | else initStyle = styler.StyleAt(startPos-1); |
128 | } |
129 | } |
130 | |
131 | styler.StartAt(startPos); |
132 | |
133 | WordList &keywords = *keywordlists[0]; |
134 | |
135 | char prevWord[200]; |
136 | prevWord[0] = '\0'; |
137 | if (length == 0) return; |
138 | |
139 | int state = initStyle & 31; |
140 | |
141 | Sci_Position nextIndex = 0; |
142 | char chPrev = ' '; |
143 | char chPrev2 = ' '; |
144 | char chNext = styler[startPos]; |
145 | styler.StartSegment(startPos); |
146 | for (Sci_Position i = startPos; i < lengthDoc; i++) |
147 | { |
148 | |
149 | char ch = chNext; |
150 | chNext = styler.SafeGetCharAt(i + 1); |
151 | |
152 | if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) |
153 | { |
154 | if ((state == SCE_SCRIPTOL_DEFAULT) || |
155 | (state == SCE_SCRIPTOL_TRIPLE) || |
156 | (state == SCE_SCRIPTOL_COMMENTBLOCK)) |
157 | { |
158 | styler.ColourTo(i, state); |
159 | } |
160 | } |
161 | |
162 | if (styler.IsLeadByte(ch)) |
163 | { |
164 | chNext = styler.SafeGetCharAt(i + 2); |
165 | chPrev = ' '; |
166 | chPrev2 = ' '; |
167 | i += 1; |
168 | continue; |
169 | } |
170 | |
171 | if (state == SCE_SCRIPTOL_STRINGEOL) |
172 | { |
173 | if (ch != '\r' && ch != '\n') |
174 | { |
175 | styler.ColourTo(i - 1, state); |
176 | state = SCE_SCRIPTOL_DEFAULT; |
177 | } |
178 | } |
179 | |
180 | if (state == SCE_SCRIPTOL_DEFAULT) |
181 | { |
182 | if (IsSolWordStart(ch)) |
183 | { |
184 | styler.ColourTo(i - 1, state); |
185 | state = SCE_SCRIPTOL_KEYWORD; |
186 | } |
187 | else if (ch == '`') |
188 | { |
189 | styler.ColourTo(i - 1, state); |
190 | state = SCE_SCRIPTOL_COMMENTLINE; |
191 | } |
192 | else if (ch == '/') |
193 | { |
194 | styler.ColourTo(i - 1, state); |
195 | if(chNext == '/') state = SCE_SCRIPTOL_CSTYLE; |
196 | if(chNext == '*') state = SCE_SCRIPTOL_COMMENTBLOCK; |
197 | } |
198 | |
199 | else if (IsSolStringStart(ch)) |
200 | { |
201 | styler.ColourTo(i - 1, state); |
202 | state = GetSolStringState(styler, i, &nextIndex); |
203 | if(state == SCE_SCRIPTOL_STRING) |
204 | { |
205 | stringType = ch; |
206 | } |
207 | if (nextIndex != i + 1) |
208 | { |
209 | i = nextIndex - 1; |
210 | ch = ' '; |
211 | chPrev = ' '; |
212 | chNext = styler.SafeGetCharAt(i + 1); |
213 | } |
214 | } |
215 | else if (isoperator(ch)) |
216 | { |
217 | styler.ColourTo(i - 1, state); |
218 | styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR); |
219 | } |
220 | } |
221 | else if (state == SCE_SCRIPTOL_KEYWORD) |
222 | { |
223 | if (!iswordchar(ch)) |
224 | { |
225 | ClassifyWordSol(styler.GetStartSegment(), i - 1, keywords, styler, prevWord); |
226 | state = SCE_SCRIPTOL_DEFAULT; |
227 | if (ch == '`') |
228 | { |
229 | state = chNext == '`' ? SCE_SCRIPTOL_PERSISTENT : SCE_SCRIPTOL_COMMENTLINE; |
230 | } |
231 | else if (IsSolStringStart(ch)) |
232 | { |
233 | styler.ColourTo(i - 1, state); |
234 | state = GetSolStringState(styler, i, &nextIndex); |
235 | if (nextIndex != i + 1) |
236 | { |
237 | i = nextIndex - 1; |
238 | ch = ' '; |
239 | chPrev = ' '; |
240 | chNext = styler.SafeGetCharAt(i + 1); |
241 | } |
242 | } |
243 | else if (isoperator(ch)) |
244 | { |
245 | styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR); |
246 | } |
247 | } |
248 | } |
249 | else |
250 | { |
251 | if (state == SCE_SCRIPTOL_COMMENTLINE || |
252 | state == SCE_SCRIPTOL_PERSISTENT || |
253 | state == SCE_SCRIPTOL_CSTYLE) |
254 | { |
255 | if (ch == '\r' || ch == '\n') |
256 | { |
257 | styler.ColourTo(i - 1, state); |
258 | state = SCE_SCRIPTOL_DEFAULT; |
259 | } |
260 | } |
261 | else if(state == SCE_SCRIPTOL_COMMENTBLOCK) |
262 | { |
263 | if(chPrev == '*' && ch == '/') |
264 | { |
265 | styler.ColourTo(i, state); |
266 | state = SCE_SCRIPTOL_DEFAULT; |
267 | } |
268 | } |
269 | else if ((state == SCE_SCRIPTOL_STRING) || |
270 | (state == SCE_SCRIPTOL_CHARACTER)) |
271 | { |
272 | if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) |
273 | { |
274 | styler.ColourTo(i - 1, state); |
275 | state = SCE_SCRIPTOL_STRINGEOL; |
276 | } |
277 | else if (ch == '\\') |
278 | { |
279 | if (chNext == '\"' || chNext == '\'' || chNext == '\\') |
280 | { |
281 | i++; |
282 | ch = chNext; |
283 | chNext = styler.SafeGetCharAt(i + 1); |
284 | } |
285 | } |
286 | else if ((ch == '\"') || (ch == '\'')) |
287 | { |
288 | // must match the entered quote type |
289 | if(ch == stringType) |
290 | { |
291 | styler.ColourTo(i, state); |
292 | state = SCE_SCRIPTOL_DEFAULT; |
293 | } |
294 | } |
295 | } |
296 | else if (state == SCE_SCRIPTOL_TRIPLE) |
297 | { |
298 | if ((ch == '\'' && chPrev == '\'' && chPrev2 == '\'') || |
299 | (ch == '\"' && chPrev == '\"' && chPrev2 == '\"')) |
300 | { |
301 | styler.ColourTo(i, state); |
302 | state = SCE_SCRIPTOL_DEFAULT; |
303 | } |
304 | } |
305 | |
306 | } |
307 | chPrev2 = chPrev; |
308 | chPrev = ch; |
309 | } |
310 | if (state == SCE_SCRIPTOL_KEYWORD) |
311 | { |
312 | ClassifyWordSol(styler.GetStartSegment(), |
313 | lengthDoc-1, keywords, styler, prevWord); |
314 | } |
315 | else |
316 | { |
317 | styler.ColourTo(lengthDoc-1, state); |
318 | } |
319 | } |
320 | |
321 | static void FoldSolDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, |
322 | WordList *[], Accessor &styler) |
323 | { |
324 | Sci_Position lengthDoc = startPos + length; |
325 | |
326 | Sci_Position lineCurrent = styler.GetLine(startPos); |
327 | if (startPos > 0) |
328 | { |
329 | if (lineCurrent > 0) |
330 | { |
331 | lineCurrent--; |
332 | startPos = styler.LineStart(lineCurrent); |
333 | if (startPos == 0) |
334 | initStyle = SCE_SCRIPTOL_DEFAULT; |
335 | else |
336 | initStyle = styler.StyleAt(startPos-1); |
337 | } |
338 | } |
339 | int state = initStyle & 31; |
340 | int spaceFlags = 0; |
341 | int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsSolComment); |
342 | if (state == SCE_SCRIPTOL_TRIPLE) |
343 | indentCurrent |= SC_FOLDLEVELWHITEFLAG; |
344 | char chNext = styler[startPos]; |
345 | for (Sci_Position i = startPos; i < lengthDoc; i++) |
346 | { |
347 | char ch = chNext; |
348 | chNext = styler.SafeGetCharAt(i + 1); |
349 | int style = styler.StyleAt(i) & 31; |
350 | |
351 | if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) |
352 | { |
353 | int lev = indentCurrent; |
354 | int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsSolComment); |
355 | if (style == SCE_SCRIPTOL_TRIPLE) |
356 | indentNext |= SC_FOLDLEVELWHITEFLAG; |
357 | if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) |
358 | { |
359 | // Only non whitespace lines can be headers |
360 | if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) |
361 | { |
362 | lev |= SC_FOLDLEVELHEADERFLAG; |
363 | } |
364 | else if (indentNext & SC_FOLDLEVELWHITEFLAG) |
365 | { |
366 | // Line after is blank so check the next - maybe should continue further? |
367 | int spaceFlags2 = 0; |
368 | int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsSolComment); |
369 | if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) |
370 | { |
371 | lev |= SC_FOLDLEVELHEADERFLAG; |
372 | } |
373 | } |
374 | } |
375 | indentCurrent = indentNext; |
376 | styler.SetLevel(lineCurrent, lev); |
377 | lineCurrent++; |
378 | } |
379 | } |
380 | } |
381 | |
382 | LexerModule lmScriptol(SCLEX_SCRIPTOL, ColouriseSolDoc, "scriptol" , FoldSolDoc); |
383 | |