]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexOthers.cxx
This form of the event cloning patch survived my
[wxWidgets.git] / src / stc / scintilla / src / LexOthers.cxx
1 // Scintilla source code edit control
2 /** @file LexOthers.cxx
3 ** Lexers for batch files, diff results, properties files, make files and error lists.
4 ** Also lexer for LaTeX documents.
5 **/
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 static void ColouriseBatchLine(
24 char *lineBuffer,
25 unsigned int lengthLine,
26 unsigned int startLine,
27 unsigned int endPos,
28 WordList &keywords,
29 Accessor &styler) {
30
31 unsigned int i = 0;
32 unsigned int state = SCE_BAT_DEFAULT;
33
34 while (isspacechar(lineBuffer[i]) && (i < lengthLine)) { // Skip initial spaces
35 i++;
36 }
37 if (lineBuffer[i] == '@') { // Hide command (ECHO OFF)
38 styler.ColourTo(startLine + i, SCE_BAT_HIDE);
39 i++;
40 while (isspacechar(lineBuffer[i]) && (i < lengthLine)) { // Skip next spaces
41 i++;
42 }
43 }
44 if (lineBuffer[i] == ':') {
45 // Label
46 if (lineBuffer[i + 1] == ':') {
47 // :: is a fake label, similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm
48 styler.ColourTo(endPos, SCE_BAT_COMMENT);
49 } else { // Real label
50 styler.ColourTo(endPos, SCE_BAT_LABEL);
51 }
52 } else {
53 // Check if initial word is a keyword
54 char wordBuffer[21];
55 unsigned int wbl = 0, offset = i;
56 // Copy word in buffer
57 for (; offset < lengthLine && wbl < 20 &&
58 !isspacechar(lineBuffer[offset]); wbl++, offset++) {
59 wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset]));
60 }
61 wordBuffer[wbl] = '\0';
62 // Check if it is a comment
63 if (CompareCaseInsensitive(wordBuffer, "rem") == 0) {
64 styler.ColourTo(endPos, SCE_BAT_COMMENT);
65 return ;
66 }
67 // Check if it is in the list
68 if (keywords.InList(wordBuffer)) {
69 styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); // Regular keyword
70 } else {
71 // Search end of word (can be a long path)
72 while (offset < lengthLine &&
73 !isspacechar(lineBuffer[offset])) {
74 offset++;
75 }
76 styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); // External command / program
77 }
78 // Remainder of the line: colourise the variables.
79
80 while (offset < lengthLine) {
81 if (state == SCE_BAT_DEFAULT && lineBuffer[offset] == '%') {
82 styler.ColourTo(startLine + offset - 1, state);
83 if (isdigit(lineBuffer[offset + 1])) {
84 styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER);
85 offset += 2;
86 } else if (lineBuffer[offset + 1] == '%' &&
87 !isspacechar(lineBuffer[offset + 2])) {
88 // Should be safe, as there is CRLF at the end of the line...
89 styler.ColourTo(startLine + offset + 2, SCE_BAT_IDENTIFIER);
90 offset += 3;
91 } else {
92 state = SCE_BAT_IDENTIFIER;
93 }
94 } else if (state == SCE_BAT_IDENTIFIER && lineBuffer[offset] == '%') {
95 styler.ColourTo(startLine + offset, state);
96 state = SCE_BAT_DEFAULT;
97 } else if (state == SCE_BAT_DEFAULT &&
98 (lineBuffer[offset] == '*' ||
99 lineBuffer[offset] == '?' ||
100 lineBuffer[offset] == '=' ||
101 lineBuffer[offset] == '<' ||
102 lineBuffer[offset] == '>' ||
103 lineBuffer[offset] == '|')) {
104 styler.ColourTo(startLine + offset - 1, state);
105 styler.ColourTo(startLine + offset, SCE_BAT_OPERATOR);
106 }
107 offset++;
108 }
109 // if (endPos > startLine + offset - 1) {
110 styler.ColourTo(endPos, SCE_BAT_DEFAULT); // Remainder of line, currently not lexed
111 // }
112 }
113
114 }
115 // ToDo: (not necessarily at beginning of line) GOTO, [IF] NOT, ERRORLEVEL
116 // IF [NO] (test) (command) -- test is EXIST (filename) | (string1)==(string2) | ERRORLEVEL (number)
117 // FOR %%(variable) IN (set) DO (command) -- variable is [a-zA-Z] -- eg for %%X in (*.txt) do type %%X
118 // ToDo: %n (parameters), %EnvironmentVariable% colourising
119 // ToDo: Colourise = > >> < | "
120
121 static void ColouriseBatchDoc(
122 unsigned int startPos,
123 int length,
124 int /*initStyle*/,
125 WordList *keywordlists[],
126 Accessor &styler) {
127
128 char lineBuffer[1024];
129 WordList &keywords = *keywordlists[0];
130
131 styler.StartAt(startPos);
132 styler.StartSegment(startPos);
133 unsigned int linePos = 0, startLine = startPos;
134 for (unsigned int i = startPos; i <= startPos + length; i++) {
135 lineBuffer[linePos++] = styler[i];
136 if (styler[i] == '\r' || styler[i] == '\n' || (linePos >=
137 sizeof(lineBuffer) - 1)) {
138 // End of line (or of line buffer) met, colourise it
139 if (styler[i + 1] == '\n') {
140 lineBuffer[linePos++] = styler[++i];
141 }
142 lineBuffer[linePos] = '\0';
143 ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywords, styler);
144 linePos = 0;
145 startLine = i + 1;
146 }
147 }
148 if (linePos > 0) {
149 ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length,
150 keywords, styler);
151 }
152 }
153
154 static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) {
155 // It is needed to remember the current state to recognize starting
156 // comment lines before the first "diff " or "--- ". If a real
157 // difference starts then each line starting with ' ' is a whitespace
158 // otherwise it is considered a comment (Only in..., Binary file...)
159 if (0 == strncmp(lineBuffer, "diff ", 3)) {
160 styler.ColourTo(endLine, 2);
161 } else if (0 == strncmp(lineBuffer, "--- ", 3)) {
162 styler.ColourTo(endLine, 3);
163 } else if (0 == strncmp(lineBuffer, "+++ ", 3)) {
164 styler.ColourTo(endLine, 3);
165 } else if (lineBuffer[0] == '@') {
166 styler.ColourTo(endLine, 4);
167 } else if (lineBuffer[0] == '-') {
168 styler.ColourTo(endLine, 5);
169 } else if (lineBuffer[0] == '+') {
170 styler.ColourTo(endLine, 6);
171 } else if (lineBuffer[0] != ' ') {
172 styler.ColourTo(endLine, 1);
173 } else {
174 styler.ColourTo(endLine, 0);
175 }
176 }
177
178 static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
179 char lineBuffer[1024];
180 styler.StartAt(startPos);
181 styler.StartSegment(startPos);
182 unsigned int linePos = 0;
183 for (unsigned int i = startPos; i < startPos + length; i++) {
184 lineBuffer[linePos++] = styler[i];
185 if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) {
186 ColouriseDiffLine(lineBuffer, i, styler);
187 linePos = 0;
188 }
189 }
190 if (linePos > 0)
191 ColouriseDiffLine(lineBuffer, startPos + length, styler);
192 }
193
194 static void ColourisePropsLine(
195 char *lineBuffer,
196 unsigned int lengthLine,
197 unsigned int startLine,
198 unsigned int endPos,
199 Accessor &styler) {
200
201 unsigned int i = 0;
202 while (isspacechar(lineBuffer[i]) && (i < lengthLine)) // Skip initial spaces
203 i++;
204 if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') {
205 styler.ColourTo(endPos, 1);
206 } else if (lineBuffer[i] == '[') {
207 styler.ColourTo(endPos, 2);
208 } else if (lineBuffer[i] == '@') {
209 styler.ColourTo(startLine + i, 4);
210 if (lineBuffer[++i] == '=')
211 styler.ColourTo(startLine + i, 3);
212 styler.ColourTo(endPos, 0);
213 } else {
214 // Search for the '=' character
215 while (lineBuffer[i] != '=' && (i < lengthLine - 1))
216 i++;
217 if (lineBuffer[i] == '=') {
218 styler.ColourTo(startLine + i - 1, 0);
219 styler.ColourTo(startLine + i, 3);
220 styler.ColourTo(endPos, 0);
221 } else {
222 styler.ColourTo(endPos, 0);
223 }
224 }
225 }
226
227 static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
228 char lineBuffer[1024];
229 styler.StartAt(startPos);
230 styler.StartSegment(startPos);
231 unsigned int linePos = 0, startLine = startPos;
232 for (unsigned int i = startPos; i <= startPos + length; i++) {
233 lineBuffer[linePos++] = styler[i];
234 if ((styler[i] == '\r' && styler.SafeGetCharAt(i + 1) != '\n') ||
235 styler[i] == '\n' ||
236 (linePos >= sizeof(lineBuffer) - 1)) {
237 lineBuffer[linePos] = '\0';
238 ColourisePropsLine(lineBuffer, linePos, startLine, i, styler);
239 linePos = 0;
240 startLine = i + 1;
241 }
242 }
243 if (linePos > 0)
244 ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length, styler);
245 }
246
247 static void ColouriseMakeLine(
248 char *lineBuffer,
249 unsigned int lengthLine,
250 unsigned int startLine,
251 unsigned int endPos,
252 Accessor &styler) {
253
254 unsigned int i = 0;
255 unsigned int lastNonSpace = 0;
256 unsigned int state = SCE_MAKE_DEFAULT;
257 bool bSpecial = false;
258 // Skip initial spaces
259 while (isspacechar(lineBuffer[i]) && (i < lengthLine)) {
260 i++;
261 }
262 if (lineBuffer[i] == '#') { // Comment
263 styler.ColourTo(endPos, SCE_MAKE_COMMENT);
264 return;
265 }
266 if (lineBuffer[i] == '!') { // Special directive
267 styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR);
268 return;
269 }
270 while (i < lengthLine) {
271 if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') {
272 styler.ColourTo(startLine + i - 1, state);
273 state = SCE_MAKE_IDENTIFIER;
274 } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') {
275 styler.ColourTo(startLine + i, state);
276 state = SCE_MAKE_DEFAULT;
277 }
278 if (!bSpecial) {
279 if (lineBuffer[i] == ':') {
280 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);
281 styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
282 styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
283 bSpecial = true; // Only react to the first ':' of the line
284 state = SCE_MAKE_DEFAULT;
285 } else if (lineBuffer[i] == '=') {
286 styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);
287 styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
288 styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
289 bSpecial = true; // Only react to the first '=' of the line
290 state = SCE_MAKE_DEFAULT;
291 }
292 }
293 if (!isspacechar(lineBuffer[i])) {
294 lastNonSpace = i;
295 }
296 i++;
297 }
298 if (state == SCE_MAKE_IDENTIFIER) {
299 styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended
300 } else {
301 styler.ColourTo(endPos, SCE_MAKE_DEFAULT);
302 }
303 }
304
305 static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
306 char lineBuffer[1024];
307 styler.StartAt(startPos);
308 styler.StartSegment(startPos);
309 unsigned int linePos = 0, startLine = startPos;
310 for (unsigned int i = startPos; i <= startPos + length; i++) {
311 lineBuffer[linePos++] = styler[i];
312 if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) {
313 lineBuffer[linePos] = '\0';
314 ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler);
315 linePos = 0;
316 startLine = i + 1;
317 }
318 }
319 if (linePos > 0) {
320 ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length, styler);
321 }
322 }
323
324 static void ColouriseErrorListLine(
325 char *lineBuffer,
326 unsigned int lengthLine,
327 // unsigned int startLine,
328 unsigned int endPos,
329 Accessor &styler) {
330 if (lineBuffer[0] == '>') {
331 // Command or return status
332 styler.ColourTo(endPos, SCE_ERR_CMD);
333 } else if (lineBuffer[0] == '!') {
334 styler.ColourTo(endPos, SCE_ERR_DIFF_CHANGED);
335 } else if (lineBuffer[0] == '+') {
336 styler.ColourTo(endPos, SCE_ERR_DIFF_ADDITION);
337 } else if (lineBuffer[0] == '-' && lineBuffer[1] == '-' && lineBuffer[2] == '-') {
338 styler.ColourTo(endPos, SCE_ERR_DIFF_MESSAGE);
339 } else if (lineBuffer[0] == '-') {
340 styler.ColourTo(endPos, SCE_ERR_DIFF_DELETION);
341 } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) {
342 styler.ColourTo(endPos, SCE_ERR_PYTHON);
343 } else if (0 == strncmp(lineBuffer, "Error ", strlen("Error "))) {
344 // Borland error message
345 styler.ColourTo(endPos, SCE_ERR_BORLAND);
346 } else if (0 == strncmp(lineBuffer, "Warning ", strlen("Warning "))) {
347 // Borland warning message
348 styler.ColourTo(endPos, SCE_ERR_BORLAND);
349 } else if (strstr(lineBuffer, "at line " ) &&
350 strstr(lineBuffer, "at line " ) < lineBuffer + lengthLine &&
351 strstr(lineBuffer, "file ") &&
352 strstr(lineBuffer, "file ") < lineBuffer + lengthLine) {
353 // Lua error message
354 styler.ColourTo(endPos, SCE_ERR_LUA);
355 } else if (strstr(lineBuffer, " at " ) &&
356 strstr(lineBuffer, " at " ) < lineBuffer + lengthLine &&
357 strstr(lineBuffer, " line ") &&
358 strstr(lineBuffer, " line ") < lineBuffer + lengthLine) {
359 // perl error message
360 styler.ColourTo(endPos, SCE_ERR_PERL);
361 } else if ((memcmp(lineBuffer, " at ", 6) == 0) &&
362 strstr(lineBuffer, ":line ")) {
363 // A .NET traceback
364 styler.ColourTo(endPos, SCE_ERR_NET);
365 } else {
366 // Look for <filename>:<line>:message
367 // Look for <filename>(line)message
368 // Look for <filename>(line,pos)message
369 int state = 0;
370 for (unsigned int i = 0; i < lengthLine; i++) {
371 if (state == 0 && lineBuffer[i] == ':' && isdigit(lineBuffer[i + 1])) {
372 state = 1;
373 } else if (state == 0 && lineBuffer[i] == '(') {
374 state = 10;
375 } else if (state == 1 && isdigit(lineBuffer[i])) {
376 state = 2;
377 } else if (state == 2 && lineBuffer[i] == ':') {
378 state = 3;
379 break;
380 } else if (state == 2 && !isdigit(lineBuffer[i])) {
381 state = 99;
382 } else if (state == 10 && isdigit(lineBuffer[i])) {
383 state = 11;
384 } else if (state == 11 && lineBuffer[i] == ',') {
385 state = 14;
386 } else if (state == 11 && lineBuffer[i] == ')') {
387 state = 12;
388 } else if (state == 12 && lineBuffer[i] == ':') {
389 state = 13;
390 } else if (state == 14 && lineBuffer[i] == ')') {
391 state = 15;
392 break;
393 } else if (((state == 11) || (state == 14)) && !((lineBuffer[i] == ' ') || isdigit(lineBuffer[i]))) {
394 state = 99;
395 }
396 }
397 if (state == 3) {
398 styler.ColourTo(endPos, SCE_ERR_GCC);
399 } else if ((state == 13) || (state == 14) || (state == 15)) {
400 styler.ColourTo(endPos, SCE_ERR_MS);
401 } else {
402 styler.ColourTo(endPos, SCE_ERR_DEFAULT);
403 }
404 }
405 }
406
407 static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
408 char lineBuffer[1024];
409 styler.StartAt(startPos);
410 styler.StartSegment(startPos);
411 unsigned int linePos = 0;
412 for (unsigned int i = startPos; i <= startPos + length; i++) {
413 lineBuffer[linePos++] = styler[i];
414 if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) {
415 ColouriseErrorListLine(lineBuffer, linePos, i, styler);
416 linePos = 0;
417 }
418 }
419 if (linePos > 0)
420 ColouriseErrorListLine(lineBuffer, linePos, startPos + length, styler);
421 }
422
423 static int isSpecial(char s) {
424 return (s == '\\') || (s == ',') || (s == ';') || (s == '\'') || (s == ' ') ||
425 (s == '\"') || (s == '`') || (s == '^') || (s == '~');
426 }
427
428 static int isTag(int start, Accessor &styler) {
429 char s[6];
430 unsigned int i = 0, e = 1;
431 while (i < 5 && e) {
432 s[i] = styler[start + i];
433 i++;
434 e = styler[start + i] != '{';
435 }
436 s[i] = '\0';
437 return (strcmp(s, "begin") == 0) || (strcmp(s, "end") == 0);
438 }
439
440 static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle,
441 WordList *[], Accessor &styler) {
442
443 styler.StartAt(startPos);
444
445 int state = initStyle;
446 char chNext = styler[startPos];
447 styler.StartSegment(startPos);
448 int lengthDoc = startPos + length;
449
450 for (int i = startPos; i < lengthDoc; i++) {
451 char ch = chNext;
452 chNext = styler.SafeGetCharAt(i + 1);
453
454 if (styler.IsLeadByte(ch)) {
455 chNext = styler.SafeGetCharAt(i + 2);
456 i++;
457 continue;
458 }
459 switch (state) {
460 case SCE_L_DEFAULT :
461 switch (ch) {
462 case '\\' :
463 styler.ColourTo(i - 1, state);
464 if (isSpecial(styler[i + 1])) {
465 styler.ColourTo(i + 1, SCE_L_COMMAND);
466 i++;
467 chNext = styler.SafeGetCharAt(i + 1);
468 } else {
469 if (isTag(i + 1, styler))
470 state = SCE_L_TAG;
471 else
472 state = SCE_L_COMMAND;
473 }
474 break;
475 case '$' :
476 styler.ColourTo(i - 1, state);
477 state = SCE_L_MATH;
478 if (chNext == '$') {
479 i++;
480 chNext = styler.SafeGetCharAt(i + 1);
481 }
482 break;
483 case '%' :
484 styler.ColourTo(i - 1, state);
485 state = SCE_L_COMMENT;
486 break;
487 }
488 break;
489 case SCE_L_COMMAND :
490 if (chNext == '[' || chNext == '{' || chNext == '}' ||
491 chNext == ' ' || chNext == '\r' || chNext == '\n') {
492 styler.ColourTo(i, state);
493 state = SCE_L_DEFAULT;
494 i++;
495 chNext = styler.SafeGetCharAt(i + 1);
496 }
497 break;
498 case SCE_L_TAG :
499 if (ch == '}') {
500 styler.ColourTo(i, state);
501 state = SCE_L_DEFAULT;
502 }
503 break;
504 case SCE_L_MATH :
505 if (ch == '$') {
506 if (chNext == '$') {
507 i++;
508 chNext = styler.SafeGetCharAt(i + 1);
509 }
510 styler.ColourTo(i, state);
511 state = SCE_L_DEFAULT;
512 }
513 break;
514 case SCE_L_COMMENT :
515 if (ch == '\r' || ch == '\n') {
516 styler.ColourTo(i - 1, state);
517 state = SCE_L_DEFAULT;
518 }
519 }
520 }
521 styler.ColourTo(lengthDoc, state);
522 }
523
524 LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch");
525 LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff");
526 LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props");
527 LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile");
528 LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist");
529 LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex");