]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexOthers.cxx
4f4c1e3258fcabf2c106f7813c12bb48d2c11511
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.
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.
20 #include "Scintilla.h"
23 static bool Is0To9(char ch
) {
24 return (ch
>= '0') && (ch
<= '9');
27 static bool Is1To9(char ch
) {
28 return (ch
>= '1') && (ch
<= '9');
31 static inline bool AtEOL(Accessor
&styler
, unsigned int i
) {
32 return (styler
[i
] == '\n') ||
33 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n'));
36 // Tests for BATCH Operators
37 static bool IsBOperator(char ch
) {
38 return (ch
== '=') || (ch
== '+') || (ch
== '>') || (ch
== '<') ||
39 (ch
== '|') || (ch
== '?') || (ch
== '*');
42 // Tests for BATCH Separators
43 static bool IsBSeparator(char ch
) {
44 return (ch
== ':') || (ch
== '\\') || (ch
== '.') || (ch
== ';') ||
45 (ch
== '\"') || (ch
== '\'') || (ch
== '/') || (ch
== ')');
48 static void ColouriseBatchLine(
50 unsigned int lengthLine
,
51 unsigned int startLine
,
56 unsigned int offset
= 0; // Line Buffer Offset
57 unsigned int enVarEnd
; // Environment Variable End point
58 unsigned int cmdLoc
; // External Command / Program Location
59 char wordBuffer
[81]; // Word Buffer - large to catch long paths
60 unsigned int wbl
; // Word Buffer Length
61 unsigned int wbo
; // Word Buffer Offset - also Special Keyword Buffer Length
62 bool forFound
= false; // No Local Variable without FOR statement
63 // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords
64 // Toggling Regular Keyword Checking off improves readability
65 // Other Regular Keywords and External Commands / Programs might also benefit from toggling
66 // Need a more robust algorithm to properly toggle Regular Keyword Checking
67 bool continueProcessing
= true; // Used to toggle Regular Keyword Checking
68 // Special Keywords are those that allow certain characters without whitespace after the command
69 // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path=
70 // Special Keyword Buffer used to determine if the first n characters is a Keyword
71 char sKeywordBuffer
[10]; // Special Keyword Buffer
72 bool sKeywordFound
; // Exit Special Keyword for-loop if found
74 // Skip initial spaces
75 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
78 // Colorize Default Text
79 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
80 // Set External Command / Program Location
83 // Check for Fake Label (Comment) or Real Label - return if found
84 if (lineBuffer
[offset
] == ':') {
85 if (lineBuffer
[offset
+ 1] == ':') {
86 // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm
87 styler
.ColourTo(endPos
, SCE_BAT_COMMENT
);
89 // Colorize Real Label
90 styler
.ColourTo(endPos
, SCE_BAT_LABEL
);
93 // Check for Drive Change (Drive Change is internal command) - return if found
94 } else if ((isalpha(lineBuffer
[offset
])) &&
95 (lineBuffer
[offset
+ 1] == ':') &&
96 ((isspacechar(lineBuffer
[offset
+ 2])) ||
97 (((lineBuffer
[offset
+ 2] == '\\')) &&
98 (isspacechar(lineBuffer
[offset
+ 3]))))) {
99 // Colorize Regular Keyword
100 styler
.ColourTo(endPos
, SCE_BAT_WORD
);
104 // Check for Hide Command (@ECHO OFF/ON)
105 if (lineBuffer
[offset
] == '@') {
106 styler
.ColourTo(startLine
+ offset
, SCE_BAT_HIDE
);
108 // Check for Argument (%n) or Environment Variable (%x...%)
109 } else if (lineBuffer
[offset
] == '%') {
110 enVarEnd
= offset
+ 1;
111 // Search end of word for second % (can be a long path)
112 while ((enVarEnd
< lengthLine
) &&
113 (!isspacechar(lineBuffer
[enVarEnd
])) &&
114 (lineBuffer
[enVarEnd
] != '%') &&
115 (!IsBOperator(lineBuffer
[enVarEnd
])) &&
116 (!IsBSeparator(lineBuffer
[enVarEnd
]))) {
119 // Check for Argument (%n)
120 if ((Is0To9(lineBuffer
[offset
+ 1])) &&
121 (lineBuffer
[enVarEnd
] != '%')) {
123 styler
.ColourTo(startLine
+ offset
+ 1, SCE_BAT_IDENTIFIER
);
125 // Check for External Command / Program
126 if (!isspacechar(lineBuffer
[offset
])) {
129 // Check for Environment Variable (%x...%)
130 } else if ((lineBuffer
[offset
+ 1] != '%') &&
131 (lineBuffer
[enVarEnd
] == '%')) {
133 // Colorize Environment Variable
134 styler
.ColourTo(startLine
+ offset
, SCE_BAT_IDENTIFIER
);
136 // Check for External Command / Program
137 if (!isspacechar(lineBuffer
[offset
])) {
143 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
147 // Read remainder of line word-at-a-time or remainder-of-word-at-a-time
148 while (offset
< lengthLine
) {
149 if (offset
> startLine
) {
150 // Colorize Default Text
151 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
153 // Copy word from Line Buffer into Word Buffer
155 for (; offset
< lengthLine
&& wbl
< 80 &&
156 !isspacechar(lineBuffer
[offset
]); wbl
++, offset
++) {
157 wordBuffer
[wbl
] = static_cast<char>(tolower(lineBuffer
[offset
]));
159 wordBuffer
[wbl
] = '\0';
162 // Check for Comment - return if found
163 if (CompareCaseInsensitive(wordBuffer
, "rem") == 0) {
164 styler
.ColourTo(endPos
, SCE_BAT_COMMENT
);
167 // Check for Separator
168 if (IsBSeparator(wordBuffer
[0])) {
169 // Check for External Command / Program
170 if ((cmdLoc
== offset
- wbl
) &&
171 ((wordBuffer
[0] == ':') ||
172 (wordBuffer
[0] == '\\') ||
173 (wordBuffer
[0] == '.'))) {
174 // Reset Offset to re-process remainder of word
176 // Colorize External Command / Program
177 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
178 // Reset External Command / Program Location
181 // Reset Offset to re-process remainder of word
183 // Colorize Default Text
184 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
186 // Check for Regular Keyword in list
187 } else if ((keywords
.InList(wordBuffer
)) &&
188 (continueProcessing
)) {
189 // Local Variables do not exist if no FOR statement
190 if (CompareCaseInsensitive(wordBuffer
, "for") == 0) {
193 // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking
194 if ((CompareCaseInsensitive(wordBuffer
, "echo") == 0) ||
195 (CompareCaseInsensitive(wordBuffer
, "goto") == 0) ||
196 (CompareCaseInsensitive(wordBuffer
, "prompt") == 0) ||
197 (CompareCaseInsensitive(wordBuffer
, "set") == 0)) {
198 continueProcessing
= false;
200 // Identify External Command / Program Location for ERRORLEVEL, and EXIST
201 if ((CompareCaseInsensitive(wordBuffer
, "errorlevel") == 0) ||
202 (CompareCaseInsensitive(wordBuffer
, "exist") == 0)) {
203 // Reset External Command / Program Location
206 while ((cmdLoc
< lengthLine
) &&
207 (isspacechar(lineBuffer
[cmdLoc
]))) {
211 while ((cmdLoc
< lengthLine
) &&
212 (!isspacechar(lineBuffer
[cmdLoc
]))) {
216 while ((cmdLoc
< lengthLine
) &&
217 (isspacechar(lineBuffer
[cmdLoc
]))) {
220 // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH
221 } else if ((CompareCaseInsensitive(wordBuffer
, "call") == 0) ||
222 (CompareCaseInsensitive(wordBuffer
, "do") == 0) ||
223 (CompareCaseInsensitive(wordBuffer
, "loadhigh") == 0) ||
224 (CompareCaseInsensitive(wordBuffer
, "lh") == 0)) {
225 // Reset External Command / Program Location
228 while ((cmdLoc
< lengthLine
) &&
229 (isspacechar(lineBuffer
[cmdLoc
]))) {
233 // Colorize Regular keyword
234 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_WORD
);
235 // No need to Reset Offset
236 // Check for Special Keyword in list, External Command / Program, or Default Text
237 } else if ((wordBuffer
[0] != '%') &&
238 (!IsBOperator(wordBuffer
[0])) &&
239 (continueProcessing
)) {
240 // Check for Special Keyword
241 // Affected Commands are in Length range 2-6
242 // Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected
243 sKeywordFound
= false;
244 for (unsigned int keywordLength
= 2; keywordLength
< wbl
&& keywordLength
< 7 && !sKeywordFound
; keywordLength
++) {
246 // Copy Keyword Length from Word Buffer into Special Keyword Buffer
247 for (; wbo
< keywordLength
; wbo
++) {
248 sKeywordBuffer
[wbo
] = static_cast<char>(wordBuffer
[wbo
]);
250 sKeywordBuffer
[wbo
] = '\0';
251 // Check for Special Keyword in list
252 if ((keywords
.InList(sKeywordBuffer
)) &&
253 ((IsBOperator(wordBuffer
[wbo
])) ||
254 (IsBSeparator(wordBuffer
[wbo
])))) {
255 sKeywordFound
= true;
256 // ECHO requires no further Regular Keyword Checking
257 if (CompareCaseInsensitive(sKeywordBuffer
, "echo") == 0) {
258 continueProcessing
= false;
260 // Colorize Special Keyword as Regular Keyword
261 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_WORD
);
262 // Reset Offset to re-process remainder of word
263 offset
-= (wbl
- wbo
);
266 // Check for External Command / Program or Default Text
267 if (!sKeywordFound
) {
269 // Check for External Command / Program
270 if (cmdLoc
== offset
- wbl
) {
271 // Read up to %, Operator or Separator
272 while ((wbo
< wbl
) &&
273 (wordBuffer
[wbo
] != '%') &&
274 (!IsBOperator(wordBuffer
[wbo
])) &&
275 (!IsBSeparator(wordBuffer
[wbo
]))) {
278 // Reset External Command / Program Location
279 cmdLoc
= offset
- (wbl
- wbo
);
280 // Reset Offset to re-process remainder of word
281 offset
-= (wbl
- wbo
);
282 // CHOICE requires no further Regular Keyword Checking
283 if (CompareCaseInsensitive(wordBuffer
, "choice") == 0) {
284 continueProcessing
= false;
286 // Check for START (and its switches) - What follows is External Command \ Program
287 if (CompareCaseInsensitive(wordBuffer
, "start") == 0) {
288 // Reset External Command / Program Location
291 while ((cmdLoc
< lengthLine
) &&
292 (isspacechar(lineBuffer
[cmdLoc
]))) {
295 // Reset External Command / Program Location if command switch detected
296 if (lineBuffer
[cmdLoc
] == '/') {
297 // Skip command switch
298 while ((cmdLoc
< lengthLine
) &&
299 (!isspacechar(lineBuffer
[cmdLoc
]))) {
303 while ((cmdLoc
< lengthLine
) &&
304 (isspacechar(lineBuffer
[cmdLoc
]))) {
309 // Colorize External command / program
310 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
311 // No need to Reset Offset
312 // Check for Default Text
314 // Read up to %, Operator or Separator
315 while ((wbo
< wbl
) &&
316 (wordBuffer
[wbo
] != '%') &&
317 (!IsBOperator(wordBuffer
[wbo
])) &&
318 (!IsBSeparator(wordBuffer
[wbo
]))) {
321 // Colorize Default Text
322 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_DEFAULT
);
323 // Reset Offset to re-process remainder of word
324 offset
-= (wbl
- wbo
);
327 // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a)
328 } else if (wordBuffer
[0] == '%') {
329 // Colorize Default Text
330 styler
.ColourTo(startLine
+ offset
- 1 - wbl
, SCE_BAT_DEFAULT
);
332 // Search to end of word for second % (can be a long path)
333 while ((wbo
< wbl
) &&
334 (wordBuffer
[wbo
] != '%') &&
335 (!IsBOperator(wordBuffer
[wbo
])) &&
336 (!IsBSeparator(wordBuffer
[wbo
]))) {
339 // Check for Argument (%n)
340 if ((Is0To9(wordBuffer
[1])) &&
341 (wordBuffer
[wbo
] != '%')) {
342 // Check for External Command / Program
343 if (cmdLoc
== offset
- wbl
) {
344 cmdLoc
= offset
- (wbl
- 2);
347 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 2), SCE_BAT_IDENTIFIER
);
348 // Reset Offset to re-process remainder of word
350 // Check for Environment Variable (%x...%)
351 } else if ((wordBuffer
[1] != '%') &&
352 (wordBuffer
[wbo
] == '%')) {
354 // Check for External Command / Program
355 if (cmdLoc
== offset
- wbl
) {
356 cmdLoc
= offset
- (wbl
- wbo
);
358 // Colorize Environment Variable
359 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_IDENTIFIER
);
360 // Reset Offset to re-process remainder of word
361 offset
-= (wbl
- wbo
);
362 // Check for Local Variable (%%a)
363 } else if ((forFound
) &&
364 (wordBuffer
[1] == '%') &&
365 (wordBuffer
[2] != '%') &&
366 (!IsBOperator(wordBuffer
[2])) &&
367 (!IsBSeparator(wordBuffer
[2]))) {
368 // Check for External Command / Program
369 if (cmdLoc
== offset
- wbl
) {
370 cmdLoc
= offset
- (wbl
- 3);
372 // Colorize Local Variable
373 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 3), SCE_BAT_IDENTIFIER
);
374 // Reset Offset to re-process remainder of word
377 // Check for Operator
378 } else if (IsBOperator(wordBuffer
[0])) {
379 // Colorize Default Text
380 styler
.ColourTo(startLine
+ offset
- 1 - wbl
, SCE_BAT_DEFAULT
);
381 // Check for Comparison Operator
382 if ((wordBuffer
[0] == '=') && (wordBuffer
[1] == '=')) {
383 // Identify External Command / Program Location for IF
386 while ((cmdLoc
< lengthLine
) &&
387 (isspacechar(lineBuffer
[cmdLoc
]))) {
390 // Colorize Comparison Operator
391 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 2), SCE_BAT_OPERATOR
);
392 // Reset Offset to re-process remainder of word
394 // Check for Pipe Operator
395 } else if (wordBuffer
[0] == '|') {
396 // Reset External Command / Program Location
397 cmdLoc
= offset
- wbl
+ 1;
399 while ((cmdLoc
< lengthLine
) &&
400 (isspacechar(lineBuffer
[cmdLoc
]))) {
403 // Colorize Pipe Operator
404 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 1), SCE_BAT_OPERATOR
);
405 // Reset Offset to re-process remainder of word
407 // Check for Other Operator
409 // Check for > Operator
410 if (wordBuffer
[0] == '>') {
411 // Turn Keyword and External Command / Program checking back on
412 continueProcessing
= true;
414 // Colorize Other Operator
415 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 1), SCE_BAT_OPERATOR
);
416 // Reset Offset to re-process remainder of word
419 // Check for Default Text
421 // Read up to %, Operator or Separator
422 while ((wbo
< wbl
) &&
423 (wordBuffer
[wbo
] != '%') &&
424 (!IsBOperator(wordBuffer
[wbo
])) &&
425 (!IsBSeparator(wordBuffer
[wbo
]))) {
428 // Colorize Default Text
429 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_DEFAULT
);
430 // Reset Offset to re-process remainder of word
431 offset
-= (wbl
- wbo
);
433 // Skip next spaces - nothing happens if Offset was Reset
434 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
438 // Colorize Default Text for remainder of line - currently not lexed
439 styler
.ColourTo(endPos
, SCE_BAT_DEFAULT
);
442 static void ColouriseBatchDoc(
443 unsigned int startPos
,
446 WordList
*keywordlists
[],
449 char lineBuffer
[1024];
450 WordList
&keywords
= *keywordlists
[0];
452 styler
.StartAt(startPos
);
453 styler
.StartSegment(startPos
);
454 unsigned int linePos
= 0;
455 unsigned int startLine
= startPos
;
456 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
457 lineBuffer
[linePos
++] = styler
[i
];
458 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
459 // End of line (or of line buffer) met, colourise it
460 lineBuffer
[linePos
] = '\0';
461 ColouriseBatchLine(lineBuffer
, linePos
, startLine
, i
, keywords
, styler
);
466 if (linePos
> 0) { // Last line does not have ending characters
467 ColouriseBatchLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1,
472 static void ColouriseDiffLine(char *lineBuffer
, int endLine
, Accessor
&styler
) {
473 // It is needed to remember the current state to recognize starting
474 // comment lines before the first "diff " or "--- ". If a real
475 // difference starts then each line starting with ' ' is a whitespace
476 // otherwise it is considered a comment (Only in..., Binary file...)
477 if (0 == strncmp(lineBuffer
, "diff ", 5)) {
478 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
479 } else if (0 == strncmp(lineBuffer
, "--- ", 4)) {
480 // In a context diff, --- appears in both the header and the position markers
481 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
482 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
484 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
485 } else if (0 == strncmp(lineBuffer
, "+++ ", 4)) {
486 // I don't know of any diff where "+++ " is a position marker, but for
487 // consistency, do the same as with "--- " and "*** ".
488 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
489 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
491 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
492 } else if (0 == strncmp(lineBuffer
, "====", 4)) { // For p4's diff
493 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
494 } else if (0 == strncmp(lineBuffer
, "***", 3)) {
495 // In a context diff, *** appears in both the header and the position markers.
496 // Also ******** is a chunk header, but here it's treated as part of the
497 // position marker since there is no separate style for a chunk header.
498 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
499 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
500 else if (lineBuffer
[3] == '*')
501 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
503 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
504 } else if (0 == strncmp(lineBuffer
, "? ", 2)) { // For difflib
505 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
506 } else if (lineBuffer
[0] == '@') {
507 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
508 } else if (lineBuffer
[0] >= '0' && lineBuffer
[0] <= '9') {
509 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
510 } else if (lineBuffer
[0] == '-' || lineBuffer
[0] == '<') {
511 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
512 } else if (lineBuffer
[0] == '+' || lineBuffer
[0] == '>') {
513 styler
.ColourTo(endLine
, SCE_DIFF_ADDED
);
514 } else if (lineBuffer
[0] != ' ') {
515 styler
.ColourTo(endLine
, SCE_DIFF_COMMENT
);
517 styler
.ColourTo(endLine
, SCE_DIFF_DEFAULT
);
521 static void ColouriseDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
522 char lineBuffer
[1024];
523 styler
.StartAt(startPos
);
524 styler
.StartSegment(startPos
);
525 unsigned int linePos
= 0;
526 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
527 lineBuffer
[linePos
++] = styler
[i
];
528 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
529 // End of line (or of line buffer) met, colourise it
530 lineBuffer
[linePos
] = '\0';
531 ColouriseDiffLine(lineBuffer
, i
, styler
);
535 if (linePos
> 0) { // Last line does not have ending characters
536 ColouriseDiffLine(lineBuffer
, startPos
+ length
- 1, styler
);
540 static void FoldDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
541 int curLine
= styler
.GetLine(startPos
);
542 int prevLevel
= SC_FOLDLEVELBASE
;
544 prevLevel
= styler
.LevelAt(curLine
-1);
546 int curLineStart
= styler
.LineStart(curLine
);
548 int nextLevel
= prevLevel
;
549 if (prevLevel
& SC_FOLDLEVELHEADERFLAG
)
550 nextLevel
= (prevLevel
& SC_FOLDLEVELNUMBERMASK
) + 1;
552 int lineType
= styler
.StyleAt(curLineStart
);
553 if (lineType
== SCE_DIFF_COMMAND
)
554 nextLevel
= (SC_FOLDLEVELBASE
+ 1) | SC_FOLDLEVELHEADERFLAG
;
555 else if (lineType
== SCE_DIFF_HEADER
) {
556 nextLevel
= (SC_FOLDLEVELBASE
+ 2) | SC_FOLDLEVELHEADERFLAG
;
557 } else if (lineType
== SCE_DIFF_POSITION
)
558 nextLevel
= (SC_FOLDLEVELBASE
+ 3) | SC_FOLDLEVELHEADERFLAG
;
560 if ((nextLevel
& SC_FOLDLEVELHEADERFLAG
) && (nextLevel
== prevLevel
))
561 styler
.SetLevel(curLine
-1, prevLevel
& ~SC_FOLDLEVELHEADERFLAG
);
563 styler
.SetLevel(curLine
, nextLevel
);
564 prevLevel
= nextLevel
;
566 curLineStart
= styler
.LineStart(++curLine
);
567 } while (static_cast<int>(startPos
) + length
> curLineStart
);
571 static void ColourisePropsLine(
573 unsigned int lengthLine
,
574 unsigned int startLine
,
579 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) // Skip initial spaces
581 if (i
< lengthLine
) {
582 if (lineBuffer
[i
] == '#' || lineBuffer
[i
] == '!' || lineBuffer
[i
] == ';') {
583 styler
.ColourTo(endPos
, SCE_PROPS_COMMENT
);
584 } else if (lineBuffer
[i
] == '[') {
585 styler
.ColourTo(endPos
, SCE_PROPS_SECTION
);
586 } else if (lineBuffer
[i
] == '@') {
587 styler
.ColourTo(startLine
+ i
, SCE_PROPS_DEFVAL
);
588 if (lineBuffer
[++i
] == '=')
589 styler
.ColourTo(startLine
+ i
, SCE_PROPS_ASSIGNMENT
);
590 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
592 // Search for the '=' character
593 while ((i
< lengthLine
) && (lineBuffer
[i
] != '='))
595 if ((i
< lengthLine
) && (lineBuffer
[i
] == '=')) {
596 styler
.ColourTo(startLine
+ i
- 1, SCE_PROPS_DEFAULT
);
597 styler
.ColourTo(startLine
+ i
, 3);
598 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
600 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
604 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
608 static void ColourisePropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
609 char lineBuffer
[1024];
610 styler
.StartAt(startPos
);
611 styler
.StartSegment(startPos
);
612 unsigned int linePos
= 0;
613 unsigned int startLine
= startPos
;
614 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
615 lineBuffer
[linePos
++] = styler
[i
];
616 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
617 // End of line (or of line buffer) met, colourise it
618 lineBuffer
[linePos
] = '\0';
619 ColourisePropsLine(lineBuffer
, linePos
, startLine
, i
, styler
);
624 if (linePos
> 0) { // Last line does not have ending characters
625 ColourisePropsLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
629 // adaption by ksc, using the "} else {" trick of 1.53
631 static void FoldPropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
632 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
634 unsigned int endPos
= startPos
+ length
;
635 int visibleChars
= 0;
636 int lineCurrent
= styler
.GetLine(startPos
);
638 char chNext
= styler
[startPos
];
639 int styleNext
= styler
.StyleAt(startPos
);
640 bool headerPoint
= false;
643 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
645 chNext
= styler
[i
+1];
647 int style
= styleNext
;
648 styleNext
= styler
.StyleAt(i
+ 1);
649 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
651 if (style
== SCE_PROPS_SECTION
) {
656 lev
= SC_FOLDLEVELBASE
;
658 if (lineCurrent
> 0) {
659 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
661 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
662 lev
= SC_FOLDLEVELBASE
+ 1;
664 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
669 lev
= SC_FOLDLEVELBASE
;
671 if (visibleChars
== 0 && foldCompact
)
672 lev
|= SC_FOLDLEVELWHITEFLAG
;
675 lev
|= SC_FOLDLEVELHEADERFLAG
;
677 if (lev
!= styler
.LevelAt(lineCurrent
)) {
678 styler
.SetLevel(lineCurrent
, lev
);
685 if (!isspacechar(ch
))
689 if (lineCurrent
> 0) {
690 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
691 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
692 lev
= SC_FOLDLEVELBASE
+ 1;
694 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
697 lev
= SC_FOLDLEVELBASE
;
699 int flagsNext
= styler
.LevelAt(lineCurrent
);
700 styler
.SetLevel(lineCurrent
, lev
| flagsNext
& ~SC_FOLDLEVELNUMBERMASK
);
703 static void ColouriseMakeLine(
705 unsigned int lengthLine
,
706 unsigned int startLine
,
711 int lastNonSpace
= -1;
712 unsigned int state
= SCE_MAKE_DEFAULT
;
713 bool bSpecial
= false;
714 // Skip initial spaces
715 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) {
718 if (lineBuffer
[i
] == '#') { // Comment
719 styler
.ColourTo(endPos
, SCE_MAKE_COMMENT
);
722 if (lineBuffer
[i
] == '!') { // Special directive
723 styler
.ColourTo(endPos
, SCE_MAKE_PREPROCESSOR
);
726 while (i
< lengthLine
) {
727 if (lineBuffer
[i
] == '$' && lineBuffer
[i
+ 1] == '(') {
728 styler
.ColourTo(startLine
+ i
- 1, state
);
729 state
= SCE_MAKE_IDENTIFIER
;
730 } else if (state
== SCE_MAKE_IDENTIFIER
&& lineBuffer
[i
] == ')') {
731 styler
.ColourTo(startLine
+ i
, state
);
732 state
= SCE_MAKE_DEFAULT
;
735 if (lineBuffer
[i
] == ':') {
736 // We should check that no colouring was made since the beginning of the line,
737 // to avoid colouring stuff like /OUT:file
738 if (lastNonSpace
>= 0)
739 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_TARGET
);
740 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
741 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
742 bSpecial
= true; // Only react to the first ':' of the line
743 state
= SCE_MAKE_DEFAULT
;
744 } else if (lineBuffer
[i
] == '=') {
745 if (lastNonSpace
>= 0)
746 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_IDENTIFIER
);
747 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
748 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
749 bSpecial
= true; // Only react to the first '=' of the line
750 state
= SCE_MAKE_DEFAULT
;
753 if (!isspacechar(lineBuffer
[i
])) {
758 if (state
== SCE_MAKE_IDENTIFIER
) {
759 styler
.ColourTo(endPos
, SCE_MAKE_IDEOL
); // Error, variable reference not ended
761 styler
.ColourTo(endPos
, SCE_MAKE_DEFAULT
);
765 static void ColouriseMakeDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
766 char lineBuffer
[1024];
767 styler
.StartAt(startPos
);
768 styler
.StartSegment(startPos
);
769 unsigned int linePos
= 0;
770 unsigned int startLine
= startPos
;
771 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
772 lineBuffer
[linePos
++] = styler
[i
];
773 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
774 // End of line (or of line buffer) met, colourise it
775 lineBuffer
[linePos
] = '\0';
776 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, i
, styler
);
781 if (linePos
> 0) { // Last line does not have ending characters
782 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
786 static bool strstart(const char *haystack
, const char *needle
) {
787 return strncmp(haystack
, needle
, strlen(needle
)) == 0;
790 static int RecogniseErrorListLine(const char *lineBuffer
, unsigned int lengthLine
) {
791 if (lineBuffer
[0] == '>') {
792 // Command or return status
794 } else if (lineBuffer
[0] == '<') {
795 // Diff removal, but not interested. Trapped to avoid hitting CTAG cases.
796 return SCE_ERR_DEFAULT
;
797 } else if (lineBuffer
[0] == '!') {
798 return SCE_ERR_DIFF_CHANGED
;
799 } else if (lineBuffer
[0] == '+') {
800 if (strstart(lineBuffer
, "+++ ")) {
801 return SCE_ERR_DIFF_MESSAGE
;
803 return SCE_ERR_DIFF_ADDITION
;
805 } else if (lineBuffer
[0] == '-') {
806 if (strstart(lineBuffer
, "--- ")) {
807 return SCE_ERR_DIFF_MESSAGE
;
809 return SCE_ERR_DIFF_DELETION
;
811 } else if (strstart(lineBuffer
, "cf90-")) {
812 // Absoft Pro Fortran 90/95 v8.2 error and/or warning message
814 } else if (strstart(lineBuffer
, "fortcom:")) {
815 // Intel Fortran Compiler v8.0 error/warning message
816 return SCE_ERR_IFORT
;
817 } else if (strstr(lineBuffer
, "File \"") && strstr(lineBuffer
, ", line ")) {
818 return SCE_ERR_PYTHON
;
819 } else if (strstr(lineBuffer
, " in ") && strstr(lineBuffer
, " on line ")) {
821 } else if ((strstart(lineBuffer
, "Error ") ||
822 strstart(lineBuffer
, "Warning ")) &&
823 strstr(lineBuffer
, " at (") &&
824 strstr(lineBuffer
, ") : ") &&
825 (strstr(lineBuffer
, " at (") < strstr(lineBuffer
, ") : "))) {
826 // Intel Fortran Compiler error/warning message
828 } else if (strstart(lineBuffer
, "Error ")) {
829 // Borland error message
830 return SCE_ERR_BORLAND
;
831 } else if (strstart(lineBuffer
, "Warning ")) {
832 // Borland warning message
833 return SCE_ERR_BORLAND
;
834 } else if (strstr(lineBuffer
, "at line " ) &&
835 (strstr(lineBuffer
, "at line " ) < (lineBuffer
+ lengthLine
)) &&
836 strstr(lineBuffer
, "file ") &&
837 (strstr(lineBuffer
, "file ") < (lineBuffer
+ lengthLine
))) {
838 // Lua 4 error message
840 } else if (strstr(lineBuffer
, " at " ) &&
841 (strstr(lineBuffer
, " at " ) < (lineBuffer
+ lengthLine
)) &&
842 strstr(lineBuffer
, " line ") &&
843 (strstr(lineBuffer
, " line ") < (lineBuffer
+ lengthLine
)) &&
844 (strstr(lineBuffer
, " at " ) < (strstr(lineBuffer
, " line ")))) {
845 // perl error message
847 } else if ((memcmp(lineBuffer
, " at ", 6) == 0) &&
848 strstr(lineBuffer
, ":line ")) {
851 } else if (strstart(lineBuffer
, "Line ") &&
852 strstr(lineBuffer
, ", file ")) {
853 // Essential Lahey Fortran error message
855 } else if (strstart(lineBuffer
, "line ") &&
856 strstr(lineBuffer
, " column ")) {
857 // HTML tidy style: line 42 column 1
859 } else if (strstart(lineBuffer
, "\tat ") &&
860 strstr(lineBuffer
, "(") &&
861 strstr(lineBuffer
, ".java:")) {
862 // Java stack back trace
863 return SCE_ERR_JAVA_STACK
;
865 // Look for one of the following formats:
866 // GCC: <filename>:<line>:<message>
867 // Microsoft: <filename>(<line>) :<message>
868 // Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal
869 // Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal
870 // Microsoft: <filename>(<line>,<column>)<message>
871 // CTags: \t<message>
872 // Lua 5 traceback: \t<filename>:<line>:<message>
873 bool initialTab
= (lineBuffer
[0] == '\t');
875 stGccStart
, stGccDigit
, stGcc
,
876 stMsStart
, stMsDigit
, stMsBracket
, stMsVc
, stMsDigitComma
, stMsDotNet
,
877 stCtagsStart
, stCtagsStartString
, stCtagsStringDollar
, stCtags
,
880 for (unsigned int i
= 0; i
< lengthLine
; i
++) {
881 char ch
= lineBuffer
[i
];
883 if ((i
+ 1) < lengthLine
)
884 chNext
= lineBuffer
[i
+ 1];
885 if (state
== stInitial
) {
887 // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)
888 if ((chNext
!= '\\') && (chNext
!= '/')) {
889 // This check is not completely accurate as may be on
890 // GTK+ with a file name that includes ':'.
893 } else if ((ch
== '(') && Is1To9(chNext
) && (!initialTab
)) {
895 // Check against '0' often removes phone numbers
897 } else if ((ch
== '\t') && (!initialTab
)) {
899 state
= stCtagsStart
;
901 } else if (state
== stGccStart
) { // <filename>:
902 state
= Is1To9(ch
) ? stGccDigit
: stUnrecognized
;
903 } else if (state
== stGccDigit
) { // <filename>:<line>
905 state
= stGcc
; // :9.*: is GCC
907 } else if (!Is0To9(ch
)) {
908 state
= stUnrecognized
;
910 } else if (state
== stMsStart
) { // <filename>(
911 state
= Is0To9(ch
) ? stMsDigit
: stUnrecognized
;
912 } else if (state
== stMsDigit
) { // <filename>(<line>
914 state
= stMsDigitComma
;
915 } else if (ch
== ')') {
917 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
918 state
= stUnrecognized
;
920 } else if (state
== stMsBracket
) { // <filename>(<line>)
921 if ((ch
== ' ') && (chNext
== ':')) {
923 } else if ((ch
== ':' && chNext
== ' ') || (ch
== ' ')) {
924 // Possibly Delphi.. don't test against chNext as it's one of the strings below.
926 unsigned int j
, chPos
;
930 numstep
= 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.
932 numstep
= 2; // otherwise add 2.
933 for (j
= i
+ numstep
; j
< lengthLine
&& isalpha(lineBuffer
[j
]) && chPos
< sizeof(word
) - 1; j
++)
934 word
[chPos
++] = lineBuffer
[j
];
936 if (!CompareCaseInsensitive(word
, "error") || !CompareCaseInsensitive(word
, "warning") ||
937 !CompareCaseInsensitive(word
, "fatal") || !CompareCaseInsensitive(word
, "catastrophic") ||
938 !CompareCaseInsensitive(word
, "note") || !CompareCaseInsensitive(word
, "remark")) {
941 state
= stUnrecognized
;
943 state
= stUnrecognized
;
945 } else if (state
== stMsDigitComma
) { // <filename>(<line>,
949 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
950 state
= stUnrecognized
;
952 } else if (state
== stCtagsStart
) {
953 if ((lineBuffer
[i
- 1] == '\t') &&
954 ((ch
== '/' && lineBuffer
[i
+ 1] == '^') || Is0To9(ch
))) {
957 } else if ((ch
== '/') && (lineBuffer
[i
+ 1] == '^')) {
958 state
= stCtagsStartString
;
960 } else if ((state
== stCtagsStartString
) && ((lineBuffer
[i
] == '$') && (lineBuffer
[i
+ 1] == '/'))) {
961 state
= stCtagsStringDollar
;
965 if (state
== stGcc
) {
967 } else if ((state
== stMsVc
) || (state
== stMsDotNet
)) {
969 } else if ((state
== stCtagsStringDollar
) || (state
== stCtags
)) {
972 return SCE_ERR_DEFAULT
;
977 static void ColouriseErrorListLine(
979 unsigned int lengthLine
,
982 styler
.ColourTo(endPos
, RecogniseErrorListLine(lineBuffer
, lengthLine
));
985 static void ColouriseErrorListDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
986 char lineBuffer
[10000];
987 styler
.StartAt(startPos
);
988 styler
.StartSegment(startPos
);
989 unsigned int linePos
= 0;
990 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
991 lineBuffer
[linePos
++] = styler
[i
];
992 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
993 // End of line (or of line buffer) met, colourise it
994 lineBuffer
[linePos
] = '\0';
995 ColouriseErrorListLine(lineBuffer
, linePos
, i
, styler
);
999 if (linePos
> 0) { // Last line does not have ending characters
1000 ColouriseErrorListLine(lineBuffer
, linePos
, startPos
+ length
- 1, styler
);
1004 static int isSpecial(char s
) {
1005 return (s
== '\\') || (s
== ',') || (s
== ';') || (s
== '\'') || (s
== ' ') ||
1006 (s
== '\"') || (s
== '`') || (s
== '^') || (s
== '~');
1009 static int isTag(int start
, Accessor
&styler
) {
1011 unsigned int i
= 0, e
= 1;
1012 while (i
< 5 && e
) {
1013 s
[i
] = styler
[start
+ i
];
1015 e
= styler
[start
+ i
] != '{';
1018 return (strcmp(s
, "begin") == 0) || (strcmp(s
, "end") == 0);
1021 static void ColouriseLatexDoc(unsigned int startPos
, int length
, int initStyle
,
1022 WordList
*[], Accessor
&styler
) {
1024 styler
.StartAt(startPos
);
1026 int state
= initStyle
;
1027 char chNext
= styler
[startPos
];
1028 styler
.StartSegment(startPos
);
1029 int lengthDoc
= startPos
+ length
;
1031 for (int i
= startPos
; i
< lengthDoc
; i
++) {
1033 chNext
= styler
.SafeGetCharAt(i
+ 1);
1035 if (styler
.IsLeadByte(ch
)) {
1036 chNext
= styler
.SafeGetCharAt(i
+ 2);
1041 case SCE_L_DEFAULT
:
1044 styler
.ColourTo(i
- 1, state
);
1045 if (isSpecial(styler
[i
+ 1])) {
1046 styler
.ColourTo(i
+ 1, SCE_L_COMMAND
);
1048 chNext
= styler
.SafeGetCharAt(i
+ 1);
1050 if (isTag(i
+ 1, styler
))
1053 state
= SCE_L_COMMAND
;
1057 styler
.ColourTo(i
- 1, state
);
1059 if (chNext
== '$') {
1061 chNext
= styler
.SafeGetCharAt(i
+ 1);
1065 styler
.ColourTo(i
- 1, state
);
1066 state
= SCE_L_COMMENT
;
1070 case SCE_L_COMMAND
:
1071 if (chNext
== '[' || chNext
== '{' || chNext
== '}' ||
1072 chNext
== ' ' || chNext
== '\r' || chNext
== '\n') {
1073 styler
.ColourTo(i
, state
);
1074 state
= SCE_L_DEFAULT
;
1076 chNext
= styler
.SafeGetCharAt(i
+ 1);
1081 styler
.ColourTo(i
, state
);
1082 state
= SCE_L_DEFAULT
;
1087 if (chNext
== '$') {
1089 chNext
= styler
.SafeGetCharAt(i
+ 1);
1091 styler
.ColourTo(i
, state
);
1092 state
= SCE_L_DEFAULT
;
1095 case SCE_L_COMMENT
:
1096 if (ch
== '\r' || ch
== '\n') {
1097 styler
.ColourTo(i
- 1, state
);
1098 state
= SCE_L_DEFAULT
;
1102 styler
.ColourTo(lengthDoc
-1, state
);
1105 static const char * const batchWordListDesc
[] = {
1110 static const char * const emptyWordListDesc
[] = {
1114 static void ColouriseNullDoc(unsigned int startPos
, int length
, int, WordList
*[],
1116 // Null language means all style bytes are 0 so just mark the end - no need to fill in.
1118 styler
.StartAt(startPos
+ length
- 1);
1119 styler
.StartSegment(startPos
+ length
- 1);
1120 styler
.ColourTo(startPos
+ length
- 1, 0);
1124 LexerModule
lmBatch(SCLEX_BATCH
, ColouriseBatchDoc
, "batch", 0, batchWordListDesc
);
1125 LexerModule
lmDiff(SCLEX_DIFF
, ColouriseDiffDoc
, "diff", FoldDiffDoc
, emptyWordListDesc
);
1126 LexerModule
lmProps(SCLEX_PROPERTIES
, ColourisePropsDoc
, "props", FoldPropsDoc
, emptyWordListDesc
);
1127 LexerModule
lmMake(SCLEX_MAKEFILE
, ColouriseMakeDoc
, "makefile", 0, emptyWordListDesc
);
1128 LexerModule
lmErrorList(SCLEX_ERRORLIST
, ColouriseErrorListDoc
, "errorlist", 0, emptyWordListDesc
);
1129 LexerModule
lmLatex(SCLEX_LATEX
, ColouriseLatexDoc
, "latex", 0, emptyWordListDesc
);
1130 LexerModule
lmNull(SCLEX_NULL
, ColouriseNullDoc
, "null");