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.
17 #include "Scintilla.h"
21 #include "LexAccessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
28 using namespace Scintilla
;
31 static bool strstart(const char *haystack
, const char *needle
) {
32 return strncmp(haystack
, needle
, strlen(needle
)) == 0;
35 static bool Is0To9(char ch
) {
36 return (ch
>= '0') && (ch
<= '9');
39 static bool Is1To9(char ch
) {
40 return (ch
>= '1') && (ch
<= '9');
43 static bool IsAlphabetic(int ch
) {
44 return isascii(ch
) && isalpha(ch
);
47 static inline bool AtEOL(Accessor
&styler
, unsigned int i
) {
48 return (styler
[i
] == '\n') ||
49 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n'));
52 // Tests for BATCH Operators
53 static bool IsBOperator(char ch
) {
54 return (ch
== '=') || (ch
== '+') || (ch
== '>') || (ch
== '<') ||
55 (ch
== '|') || (ch
== '?') || (ch
== '*');
58 // Tests for BATCH Separators
59 static bool IsBSeparator(char ch
) {
60 return (ch
== '\\') || (ch
== '.') || (ch
== ';') ||
61 (ch
== '\"') || (ch
== '\'') || (ch
== '/');
64 static void ColouriseBatchLine(
66 unsigned int lengthLine
,
67 unsigned int startLine
,
69 WordList
*keywordlists
[],
72 unsigned int offset
= 0; // Line Buffer Offset
73 unsigned int cmdLoc
; // External Command / Program Location
74 char wordBuffer
[81]; // Word Buffer - large to catch long paths
75 unsigned int wbl
; // Word Buffer Length
76 unsigned int wbo
; // Word Buffer Offset - also Special Keyword Buffer Length
77 WordList
&keywords
= *keywordlists
[0]; // Internal Commands
78 WordList
&keywords2
= *keywordlists
[1]; // External Commands (optional)
80 // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords
81 // Toggling Regular Keyword Checking off improves readability
82 // Other Regular Keywords and External Commands / Programs might also benefit from toggling
83 // Need a more robust algorithm to properly toggle Regular Keyword Checking
84 bool continueProcessing
= true; // Used to toggle Regular Keyword Checking
85 // Special Keywords are those that allow certain characters without whitespace after the command
86 // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path=
87 // Special Keyword Buffer used to determine if the first n characters is a Keyword
88 char sKeywordBuffer
[10]; // Special Keyword Buffer
89 bool sKeywordFound
; // Exit Special Keyword for-loop if found
91 // Skip initial spaces
92 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
95 // Colorize Default Text
96 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
97 // Set External Command / Program Location
100 // Check for Fake Label (Comment) or Real Label - return if found
101 if (lineBuffer
[offset
] == ':') {
102 if (lineBuffer
[offset
+ 1] == ':') {
103 // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm
104 styler
.ColourTo(endPos
, SCE_BAT_COMMENT
);
106 // Colorize Real Label
107 styler
.ColourTo(endPos
, SCE_BAT_LABEL
);
110 // Check for Drive Change (Drive Change is internal command) - return if found
111 } else if ((IsAlphabetic(lineBuffer
[offset
])) &&
112 (lineBuffer
[offset
+ 1] == ':') &&
113 ((isspacechar(lineBuffer
[offset
+ 2])) ||
114 (((lineBuffer
[offset
+ 2] == '\\')) &&
115 (isspacechar(lineBuffer
[offset
+ 3]))))) {
116 // Colorize Regular Keyword
117 styler
.ColourTo(endPos
, SCE_BAT_WORD
);
121 // Check for Hide Command (@ECHO OFF/ON)
122 if (lineBuffer
[offset
] == '@') {
123 styler
.ColourTo(startLine
+ offset
, SCE_BAT_HIDE
);
127 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
131 // Read remainder of line word-at-a-time or remainder-of-word-at-a-time
132 while (offset
< lengthLine
) {
133 if (offset
> startLine
) {
134 // Colorize Default Text
135 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
137 // Copy word from Line Buffer into Word Buffer
139 for (; offset
< lengthLine
&& wbl
< 80 &&
140 !isspacechar(lineBuffer
[offset
]); wbl
++, offset
++) {
141 wordBuffer
[wbl
] = static_cast<char>(tolower(lineBuffer
[offset
]));
143 wordBuffer
[wbl
] = '\0';
146 // Check for Comment - return if found
147 if (CompareCaseInsensitive(wordBuffer
, "rem") == 0) {
148 styler
.ColourTo(endPos
, SCE_BAT_COMMENT
);
151 // Check for Separator
152 if (IsBSeparator(wordBuffer
[0])) {
153 // Check for External Command / Program
154 if ((cmdLoc
== offset
- wbl
) &&
155 ((wordBuffer
[0] == ':') ||
156 (wordBuffer
[0] == '\\') ||
157 (wordBuffer
[0] == '.'))) {
158 // Reset Offset to re-process remainder of word
160 // Colorize External Command / Program
162 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
163 } else if (keywords2
.InList(wordBuffer
)) {
164 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
166 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
168 // Reset External Command / Program Location
171 // Reset Offset to re-process remainder of word
173 // Colorize Default Text
174 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
176 // Check for Regular Keyword in list
177 } else if ((keywords
.InList(wordBuffer
)) &&
178 (continueProcessing
)) {
179 // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking
180 if ((CompareCaseInsensitive(wordBuffer
, "echo") == 0) ||
181 (CompareCaseInsensitive(wordBuffer
, "goto") == 0) ||
182 (CompareCaseInsensitive(wordBuffer
, "prompt") == 0) ||
183 (CompareCaseInsensitive(wordBuffer
, "set") == 0)) {
184 continueProcessing
= false;
186 // Identify External Command / Program Location for ERRORLEVEL, and EXIST
187 if ((CompareCaseInsensitive(wordBuffer
, "errorlevel") == 0) ||
188 (CompareCaseInsensitive(wordBuffer
, "exist") == 0)) {
189 // Reset External Command / Program Location
192 while ((cmdLoc
< lengthLine
) &&
193 (isspacechar(lineBuffer
[cmdLoc
]))) {
197 while ((cmdLoc
< lengthLine
) &&
198 (!isspacechar(lineBuffer
[cmdLoc
]))) {
202 while ((cmdLoc
< lengthLine
) &&
203 (isspacechar(lineBuffer
[cmdLoc
]))) {
206 // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH
207 } else if ((CompareCaseInsensitive(wordBuffer
, "call") == 0) ||
208 (CompareCaseInsensitive(wordBuffer
, "do") == 0) ||
209 (CompareCaseInsensitive(wordBuffer
, "loadhigh") == 0) ||
210 (CompareCaseInsensitive(wordBuffer
, "lh") == 0)) {
211 // Reset External Command / Program Location
214 while ((cmdLoc
< lengthLine
) &&
215 (isspacechar(lineBuffer
[cmdLoc
]))) {
219 // Colorize Regular keyword
220 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_WORD
);
221 // No need to Reset Offset
222 // Check for Special Keyword in list, External Command / Program, or Default Text
223 } else if ((wordBuffer
[0] != '%') &&
224 (wordBuffer
[0] != '!') &&
225 (!IsBOperator(wordBuffer
[0])) &&
226 (continueProcessing
)) {
227 // Check for Special Keyword
228 // Affected Commands are in Length range 2-6
229 // Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected
230 sKeywordFound
= false;
231 for (unsigned int keywordLength
= 2; keywordLength
< wbl
&& keywordLength
< 7 && !sKeywordFound
; keywordLength
++) {
233 // Copy Keyword Length from Word Buffer into Special Keyword Buffer
234 for (; wbo
< keywordLength
; wbo
++) {
235 sKeywordBuffer
[wbo
] = static_cast<char>(wordBuffer
[wbo
]);
237 sKeywordBuffer
[wbo
] = '\0';
238 // Check for Special Keyword in list
239 if ((keywords
.InList(sKeywordBuffer
)) &&
240 ((IsBOperator(wordBuffer
[wbo
])) ||
241 (IsBSeparator(wordBuffer
[wbo
])))) {
242 sKeywordFound
= true;
243 // ECHO requires no further Regular Keyword Checking
244 if (CompareCaseInsensitive(sKeywordBuffer
, "echo") == 0) {
245 continueProcessing
= false;
247 // Colorize Special Keyword as Regular Keyword
248 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_WORD
);
249 // Reset Offset to re-process remainder of word
250 offset
-= (wbl
- wbo
);
253 // Check for External Command / Program or Default Text
254 if (!sKeywordFound
) {
256 // Check for External Command / Program
257 if (cmdLoc
== offset
- wbl
) {
258 // Read up to %, Operator or Separator
259 while ((wbo
< wbl
) &&
260 (wordBuffer
[wbo
] != '%') &&
261 (wordBuffer
[wbo
] != '!') &&
262 (!IsBOperator(wordBuffer
[wbo
])) &&
263 (!IsBSeparator(wordBuffer
[wbo
]))) {
266 // Reset External Command / Program Location
267 cmdLoc
= offset
- (wbl
- wbo
);
268 // Reset Offset to re-process remainder of word
269 offset
-= (wbl
- wbo
);
270 // CHOICE requires no further Regular Keyword Checking
271 if (CompareCaseInsensitive(wordBuffer
, "choice") == 0) {
272 continueProcessing
= false;
274 // Check for START (and its switches) - What follows is External Command \ Program
275 if (CompareCaseInsensitive(wordBuffer
, "start") == 0) {
276 // Reset External Command / Program Location
279 while ((cmdLoc
< lengthLine
) &&
280 (isspacechar(lineBuffer
[cmdLoc
]))) {
283 // Reset External Command / Program Location if command switch detected
284 if (lineBuffer
[cmdLoc
] == '/') {
285 // Skip command switch
286 while ((cmdLoc
< lengthLine
) &&
287 (!isspacechar(lineBuffer
[cmdLoc
]))) {
291 while ((cmdLoc
< lengthLine
) &&
292 (isspacechar(lineBuffer
[cmdLoc
]))) {
297 // Colorize External Command / Program
299 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
300 } else if (keywords2
.InList(wordBuffer
)) {
301 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_COMMAND
);
303 styler
.ColourTo(startLine
+ offset
- 1, SCE_BAT_DEFAULT
);
305 // No need to Reset Offset
306 // Check for Default Text
308 // Read up to %, Operator or Separator
309 while ((wbo
< wbl
) &&
310 (wordBuffer
[wbo
] != '%') &&
311 (wordBuffer
[wbo
] != '!') &&
312 (!IsBOperator(wordBuffer
[wbo
])) &&
313 (!IsBSeparator(wordBuffer
[wbo
]))) {
316 // Colorize Default Text
317 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_DEFAULT
);
318 // Reset Offset to re-process remainder of word
319 offset
-= (wbl
- wbo
);
322 // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a)
323 } else if (wordBuffer
[0] == '%') {
324 // Colorize Default Text
325 styler
.ColourTo(startLine
+ offset
- 1 - wbl
, SCE_BAT_DEFAULT
);
327 // Search to end of word for second % (can be a long path)
328 while ((wbo
< wbl
) &&
329 (wordBuffer
[wbo
] != '%') &&
330 (!IsBOperator(wordBuffer
[wbo
])) &&
331 (!IsBSeparator(wordBuffer
[wbo
]))) {
334 // Check for Argument (%n) or (%*)
335 if (((Is0To9(wordBuffer
[1])) || (wordBuffer
[1] == '*')) &&
336 (wordBuffer
[wbo
] != '%')) {
337 // Check for External Command / Program
338 if (cmdLoc
== offset
- wbl
) {
339 cmdLoc
= offset
- (wbl
- 2);
342 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 2), SCE_BAT_IDENTIFIER
);
343 // Reset Offset to re-process remainder of word
345 // Check for Expanded Argument (%~...) / Variable (%%~...)
346 } else if (((wbl
> 1) && (wordBuffer
[1] == '~')) ||
347 ((wbl
> 2) && (wordBuffer
[1] == '%') && (wordBuffer
[2] == '~'))) {
348 // Check for External Command / Program
349 if (cmdLoc
== offset
- wbl
) {
350 cmdLoc
= offset
- (wbl
- wbo
);
352 // Colorize Expanded Argument / Variable
353 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_IDENTIFIER
);
354 // Reset Offset to re-process remainder of word
355 offset
-= (wbl
- wbo
);
356 // Check for Environment Variable (%x...%)
357 } else if ((wordBuffer
[1] != '%') &&
358 (wordBuffer
[wbo
] == '%')) {
360 // Check for External Command / Program
361 if (cmdLoc
== offset
- wbl
) {
362 cmdLoc
= offset
- (wbl
- wbo
);
364 // Colorize Environment Variable
365 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_IDENTIFIER
);
366 // Reset Offset to re-process remainder of word
367 offset
-= (wbl
- wbo
);
368 // Check for Local Variable (%%a)
371 (wordBuffer
[1] == '%') &&
372 (wordBuffer
[2] != '%') &&
373 (!IsBOperator(wordBuffer
[2])) &&
374 (!IsBSeparator(wordBuffer
[2]))) {
375 // Check for External Command / Program
376 if (cmdLoc
== offset
- wbl
) {
377 cmdLoc
= offset
- (wbl
- 3);
379 // Colorize Local Variable
380 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 3), SCE_BAT_IDENTIFIER
);
381 // Reset Offset to re-process remainder of word
384 // Check for Environment Variable (!x...!)
385 } else if (wordBuffer
[0] == '!') {
386 // Colorize Default Text
387 styler
.ColourTo(startLine
+ offset
- 1 - wbl
, SCE_BAT_DEFAULT
);
389 // Search to end of word for second ! (can be a long path)
390 while ((wbo
< wbl
) &&
391 (wordBuffer
[wbo
] != '!') &&
392 (!IsBOperator(wordBuffer
[wbo
])) &&
393 (!IsBSeparator(wordBuffer
[wbo
]))) {
396 if (wordBuffer
[wbo
] == '!') {
398 // Check for External Command / Program
399 if (cmdLoc
== offset
- wbl
) {
400 cmdLoc
= offset
- (wbl
- wbo
);
402 // Colorize Environment Variable
403 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_IDENTIFIER
);
404 // Reset Offset to re-process remainder of word
405 offset
-= (wbl
- wbo
);
407 // Check for Operator
408 } else if (IsBOperator(wordBuffer
[0])) {
409 // Colorize Default Text
410 styler
.ColourTo(startLine
+ offset
- 1 - wbl
, SCE_BAT_DEFAULT
);
411 // Check for Comparison Operator
412 if ((wordBuffer
[0] == '=') && (wordBuffer
[1] == '=')) {
413 // Identify External Command / Program Location for IF
416 while ((cmdLoc
< lengthLine
) &&
417 (isspacechar(lineBuffer
[cmdLoc
]))) {
420 // Colorize Comparison Operator
421 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 2), SCE_BAT_OPERATOR
);
422 // Reset Offset to re-process remainder of word
424 // Check for Pipe Operator
425 } else if (wordBuffer
[0] == '|') {
426 // Reset External Command / Program Location
427 cmdLoc
= offset
- wbl
+ 1;
429 while ((cmdLoc
< lengthLine
) &&
430 (isspacechar(lineBuffer
[cmdLoc
]))) {
433 // Colorize Pipe Operator
434 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 1), SCE_BAT_OPERATOR
);
435 // Reset Offset to re-process remainder of word
437 // Check for Other Operator
439 // Check for > Operator
440 if (wordBuffer
[0] == '>') {
441 // Turn Keyword and External Command / Program checking back on
442 continueProcessing
= true;
444 // Colorize Other Operator
445 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- 1), SCE_BAT_OPERATOR
);
446 // Reset Offset to re-process remainder of word
449 // Check for Default Text
451 // Read up to %, Operator or Separator
452 while ((wbo
< wbl
) &&
453 (wordBuffer
[wbo
] != '%') &&
454 (wordBuffer
[wbo
] != '!') &&
455 (!IsBOperator(wordBuffer
[wbo
])) &&
456 (!IsBSeparator(wordBuffer
[wbo
]))) {
459 // Colorize Default Text
460 styler
.ColourTo(startLine
+ offset
- 1 - (wbl
- wbo
), SCE_BAT_DEFAULT
);
461 // Reset Offset to re-process remainder of word
462 offset
-= (wbl
- wbo
);
464 // Skip next spaces - nothing happens if Offset was Reset
465 while ((offset
< lengthLine
) && (isspacechar(lineBuffer
[offset
]))) {
469 // Colorize Default Text for remainder of line - currently not lexed
470 styler
.ColourTo(endPos
, SCE_BAT_DEFAULT
);
473 static void ColouriseBatchDoc(
474 unsigned int startPos
,
477 WordList
*keywordlists
[],
480 char lineBuffer
[1024];
482 styler
.StartAt(startPos
);
483 styler
.StartSegment(startPos
);
484 unsigned int linePos
= 0;
485 unsigned int startLine
= startPos
;
486 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
487 lineBuffer
[linePos
++] = styler
[i
];
488 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
489 // End of line (or of line buffer) met, colourise it
490 lineBuffer
[linePos
] = '\0';
491 ColouriseBatchLine(lineBuffer
, linePos
, startLine
, i
, keywordlists
, styler
);
496 if (linePos
> 0) { // Last line does not have ending characters
497 lineBuffer
[linePos
] = '\0';
498 ColouriseBatchLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1,
499 keywordlists
, styler
);
503 static void ColouriseDiffLine(char *lineBuffer
, int endLine
, Accessor
&styler
) {
504 // It is needed to remember the current state to recognize starting
505 // comment lines before the first "diff " or "--- ". If a real
506 // difference starts then each line starting with ' ' is a whitespace
507 // otherwise it is considered a comment (Only in..., Binary file...)
508 if (0 == strncmp(lineBuffer
, "diff ", 5)) {
509 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
510 } else if (0 == strncmp(lineBuffer
, "Index: ", 7)) { // For subversion's diff
511 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
512 } else if (0 == strncmp(lineBuffer
, "---", 3) && lineBuffer
[3] != '-') {
513 // In a context diff, --- appears in both the header and the position markers
514 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+ 4) && !strchr(lineBuffer
, '/'))
515 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
516 else if (lineBuffer
[3] == '\r' || lineBuffer
[3] == '\n')
517 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
519 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
520 } else if (0 == strncmp(lineBuffer
, "+++ ", 4)) {
521 // I don't know of any diff where "+++ " is a position marker, but for
522 // consistency, do the same as with "--- " and "*** ".
523 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
524 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
526 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
527 } else if (0 == strncmp(lineBuffer
, "====", 4)) { // For p4's diff
528 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
529 } else if (0 == strncmp(lineBuffer
, "***", 3)) {
530 // In a context diff, *** appears in both the header and the position markers.
531 // Also ******** is a chunk header, but here it's treated as part of the
532 // position marker since there is no separate style for a chunk header.
533 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
534 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
535 else if (lineBuffer
[3] == '*')
536 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
538 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
539 } else if (0 == strncmp(lineBuffer
, "? ", 2)) { // For difflib
540 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
541 } else if (lineBuffer
[0] == '@') {
542 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
543 } else if (lineBuffer
[0] >= '0' && lineBuffer
[0] <= '9') {
544 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
545 } else if (lineBuffer
[0] == '-' || lineBuffer
[0] == '<') {
546 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
547 } else if (lineBuffer
[0] == '+' || lineBuffer
[0] == '>') {
548 styler
.ColourTo(endLine
, SCE_DIFF_ADDED
);
549 } else if (lineBuffer
[0] == '!') {
550 styler
.ColourTo(endLine
, SCE_DIFF_CHANGED
);
551 } else if (lineBuffer
[0] != ' ') {
552 styler
.ColourTo(endLine
, SCE_DIFF_COMMENT
);
554 styler
.ColourTo(endLine
, SCE_DIFF_DEFAULT
);
558 static void ColouriseDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
559 char lineBuffer
[1024];
560 styler
.StartAt(startPos
);
561 styler
.StartSegment(startPos
);
562 unsigned int linePos
= 0;
563 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
564 lineBuffer
[linePos
++] = styler
[i
];
565 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
566 // End of line (or of line buffer) met, colourise it
567 lineBuffer
[linePos
] = '\0';
568 ColouriseDiffLine(lineBuffer
, i
, styler
);
572 if (linePos
> 0) { // Last line does not have ending characters
573 ColouriseDiffLine(lineBuffer
, startPos
+ length
- 1, styler
);
577 static void FoldDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
578 int curLine
= styler
.GetLine(startPos
);
579 int curLineStart
= styler
.LineStart(curLine
);
580 int prevLevel
= curLine
> 0 ? styler
.LevelAt(curLine
- 1) : SC_FOLDLEVELBASE
;
584 int lineType
= styler
.StyleAt(curLineStart
);
585 if (lineType
== SCE_DIFF_COMMAND
)
586 nextLevel
= SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
;
587 else if (lineType
== SCE_DIFF_HEADER
)
588 nextLevel
= (SC_FOLDLEVELBASE
+ 1) | SC_FOLDLEVELHEADERFLAG
;
589 else if (lineType
== SCE_DIFF_POSITION
&& styler
[curLineStart
] != '-')
590 nextLevel
= (SC_FOLDLEVELBASE
+ 2) | SC_FOLDLEVELHEADERFLAG
;
591 else if (prevLevel
& SC_FOLDLEVELHEADERFLAG
)
592 nextLevel
= (prevLevel
& SC_FOLDLEVELNUMBERMASK
) + 1;
594 nextLevel
= prevLevel
;
596 if ((nextLevel
& SC_FOLDLEVELHEADERFLAG
) && (nextLevel
== prevLevel
))
597 styler
.SetLevel(curLine
-1, prevLevel
& ~SC_FOLDLEVELHEADERFLAG
);
599 styler
.SetLevel(curLine
, nextLevel
);
600 prevLevel
= nextLevel
;
602 curLineStart
= styler
.LineStart(++curLine
);
603 } while (static_cast<int>(startPos
) + length
> curLineStart
);
606 static void ColourisePoLine(
608 unsigned int lengthLine
,
609 unsigned int startLine
,
614 static unsigned int state
= SCE_PO_DEFAULT
;
615 unsigned int state_start
= SCE_PO_DEFAULT
;
617 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) // Skip initial spaces
619 if (i
< lengthLine
) {
620 if (lineBuffer
[i
] == '#') {
621 // check if the comment contains any flags ("#, ") and
622 // then whether the flags contain "fuzzy"
623 if (strstart(lineBuffer
, "#, ") && strstr(lineBuffer
, "fuzzy"))
624 styler
.ColourTo(endPos
, SCE_PO_FUZZY
);
626 styler
.ColourTo(endPos
, SCE_PO_COMMENT
);
628 if (lineBuffer
[0] == '"') {
629 // line continuation, use previous style
630 styler
.ColourTo(endPos
, state
);
632 // this implicitly also matches "msgid_plural"
633 } else if (strstart(lineBuffer
, "msgid")) {
634 state_start
= SCE_PO_MSGID
;
635 state
= SCE_PO_MSGID_TEXT
;
636 } else if (strstart(lineBuffer
, "msgstr")) {
637 state_start
= SCE_PO_MSGSTR
;
638 state
= SCE_PO_MSGSTR_TEXT
;
639 } else if (strstart(lineBuffer
, "msgctxt")) {
640 state_start
= SCE_PO_MSGCTXT
;
641 state
= SCE_PO_MSGCTXT_TEXT
;
643 if (state_start
!= SCE_PO_DEFAULT
) {
644 // find the next space
645 while ((i
< lengthLine
) && ! isspacechar(lineBuffer
[i
]))
647 styler
.ColourTo(startLine
+ i
- 1, state_start
);
648 styler
.ColourTo(startLine
+ i
, SCE_PO_DEFAULT
);
649 styler
.ColourTo(endPos
, state
);
653 styler
.ColourTo(endPos
, SCE_PO_DEFAULT
);
657 static void ColourisePoDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
658 char lineBuffer
[1024];
659 styler
.StartAt(startPos
);
660 styler
.StartSegment(startPos
);
661 unsigned int linePos
= 0;
662 unsigned int startLine
= startPos
;
663 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
664 lineBuffer
[linePos
++] = styler
[i
];
665 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
666 // End of line (or of line buffer) met, colourise it
667 lineBuffer
[linePos
] = '\0';
668 ColourisePoLine(lineBuffer
, linePos
, startLine
, i
, styler
);
673 if (linePos
> 0) { // Last line does not have ending characters
674 ColourisePoLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
678 static inline bool isassignchar(unsigned char ch
) {
679 return (ch
== '=') || (ch
== ':');
682 static void ColourisePropsLine(
684 unsigned int lengthLine
,
685 unsigned int startLine
,
688 bool allowInitialSpaces
) {
691 if (allowInitialSpaces
) {
692 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) // Skip initial spaces
695 if (isspacechar(lineBuffer
[i
])) // don't allow initial spaces
699 if (i
< lengthLine
) {
700 if (lineBuffer
[i
] == '#' || lineBuffer
[i
] == '!' || lineBuffer
[i
] == ';') {
701 styler
.ColourTo(endPos
, SCE_PROPS_COMMENT
);
702 } else if (lineBuffer
[i
] == '[') {
703 styler
.ColourTo(endPos
, SCE_PROPS_SECTION
);
704 } else if (lineBuffer
[i
] == '@') {
705 styler
.ColourTo(startLine
+ i
, SCE_PROPS_DEFVAL
);
706 if (isassignchar(lineBuffer
[i
++]))
707 styler
.ColourTo(startLine
+ i
, SCE_PROPS_ASSIGNMENT
);
708 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
710 // Search for the '=' character
711 while ((i
< lengthLine
) && !isassignchar(lineBuffer
[i
]))
713 if ((i
< lengthLine
) && isassignchar(lineBuffer
[i
])) {
714 styler
.ColourTo(startLine
+ i
- 1, SCE_PROPS_KEY
);
715 styler
.ColourTo(startLine
+ i
, SCE_PROPS_ASSIGNMENT
);
716 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
718 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
722 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
726 static void ColourisePropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
727 char lineBuffer
[1024];
728 styler
.StartAt(startPos
);
729 styler
.StartSegment(startPos
);
730 unsigned int linePos
= 0;
731 unsigned int startLine
= startPos
;
733 // property lexer.props.allow.initial.spaces
734 // For properties files, set to 0 to style all lines that start with whitespace in the default style.
735 // This is not suitable for SciTE .properties files which use indentation for flow control but
736 // can be used for RFC2822 text where indentation is used for continuation lines.
737 bool allowInitialSpaces
= styler
.GetPropertyInt("lexer.props.allow.initial.spaces", 1) != 0;
739 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
740 lineBuffer
[linePos
++] = styler
[i
];
741 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
742 // End of line (or of line buffer) met, colourise it
743 lineBuffer
[linePos
] = '\0';
744 ColourisePropsLine(lineBuffer
, linePos
, startLine
, i
, styler
, allowInitialSpaces
);
749 if (linePos
> 0) { // Last line does not have ending characters
750 ColourisePropsLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
, allowInitialSpaces
);
754 // adaption by ksc, using the "} else {" trick of 1.53
756 static void FoldPropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
757 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
759 unsigned int endPos
= startPos
+ length
;
760 int visibleChars
= 0;
761 int lineCurrent
= styler
.GetLine(startPos
);
763 char chNext
= styler
[startPos
];
764 int styleNext
= styler
.StyleAt(startPos
);
765 bool headerPoint
= false;
768 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
770 chNext
= styler
[i
+1];
772 int style
= styleNext
;
773 styleNext
= styler
.StyleAt(i
+ 1);
774 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
776 if (style
== SCE_PROPS_SECTION
) {
781 lev
= SC_FOLDLEVELBASE
;
783 if (lineCurrent
> 0) {
784 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
786 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
787 lev
= SC_FOLDLEVELBASE
+ 1;
789 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
794 lev
= SC_FOLDLEVELBASE
;
796 if (visibleChars
== 0 && foldCompact
)
797 lev
|= SC_FOLDLEVELWHITEFLAG
;
800 lev
|= SC_FOLDLEVELHEADERFLAG
;
802 if (lev
!= styler
.LevelAt(lineCurrent
)) {
803 styler
.SetLevel(lineCurrent
, lev
);
810 if (!isspacechar(ch
))
814 if (lineCurrent
> 0) {
815 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
816 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
817 lev
= SC_FOLDLEVELBASE
+ 1;
819 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
822 lev
= SC_FOLDLEVELBASE
;
824 int flagsNext
= styler
.LevelAt(lineCurrent
);
825 styler
.SetLevel(lineCurrent
, lev
| (flagsNext
& ~SC_FOLDLEVELNUMBERMASK
));
828 static void ColouriseMakeLine(
830 unsigned int lengthLine
,
831 unsigned int startLine
,
836 int lastNonSpace
= -1;
837 unsigned int state
= SCE_MAKE_DEFAULT
;
838 bool bSpecial
= false;
840 // check for a tab character in column 0 indicating a command
841 bool bCommand
= false;
842 if ((lengthLine
> 0) && (lineBuffer
[0] == '\t'))
845 // Skip initial spaces
846 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) {
849 if (lineBuffer
[i
] == '#') { // Comment
850 styler
.ColourTo(endPos
, SCE_MAKE_COMMENT
);
853 if (lineBuffer
[i
] == '!') { // Special directive
854 styler
.ColourTo(endPos
, SCE_MAKE_PREPROCESSOR
);
858 while (i
< lengthLine
) {
859 if (lineBuffer
[i
] == '$' && lineBuffer
[i
+ 1] == '(') {
860 styler
.ColourTo(startLine
+ i
- 1, state
);
861 state
= SCE_MAKE_IDENTIFIER
;
863 } else if (state
== SCE_MAKE_IDENTIFIER
&& lineBuffer
[i
] == ')') {
864 if (--varCount
== 0) {
865 styler
.ColourTo(startLine
+ i
, state
);
866 state
= SCE_MAKE_DEFAULT
;
870 // skip identifier and target styling if this is a command line
871 if (!bSpecial
&& !bCommand
) {
872 if (lineBuffer
[i
] == ':') {
873 if (((i
+ 1) < lengthLine
) && (lineBuffer
[i
+ 1] == '=')) {
874 // it's a ':=', so style as an identifier
875 if (lastNonSpace
>= 0)
876 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_IDENTIFIER
);
877 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
878 styler
.ColourTo(startLine
+ i
+ 1, SCE_MAKE_OPERATOR
);
880 // We should check that no colouring was made since the beginning of the line,
881 // to avoid colouring stuff like /OUT:file
882 if (lastNonSpace
>= 0)
883 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_TARGET
);
884 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
885 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
887 bSpecial
= true; // Only react to the first ':' of the line
888 state
= SCE_MAKE_DEFAULT
;
889 } else if (lineBuffer
[i
] == '=') {
890 if (lastNonSpace
>= 0)
891 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_IDENTIFIER
);
892 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
893 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
894 bSpecial
= true; // Only react to the first '=' of the line
895 state
= SCE_MAKE_DEFAULT
;
898 if (!isspacechar(lineBuffer
[i
])) {
903 if (state
== SCE_MAKE_IDENTIFIER
) {
904 styler
.ColourTo(endPos
, SCE_MAKE_IDEOL
); // Error, variable reference not ended
906 styler
.ColourTo(endPos
, SCE_MAKE_DEFAULT
);
910 static void ColouriseMakeDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
911 char lineBuffer
[1024];
912 styler
.StartAt(startPos
);
913 styler
.StartSegment(startPos
);
914 unsigned int linePos
= 0;
915 unsigned int startLine
= startPos
;
916 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
917 lineBuffer
[linePos
++] = styler
[i
];
918 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
919 // End of line (or of line buffer) met, colourise it
920 lineBuffer
[linePos
] = '\0';
921 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, i
, styler
);
926 if (linePos
> 0) { // Last line does not have ending characters
927 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
931 static int RecogniseErrorListLine(const char *lineBuffer
, unsigned int lengthLine
, int &startValue
) {
932 if (lineBuffer
[0] == '>') {
933 // Command or return status
935 } else if (lineBuffer
[0] == '<') {
937 return SCE_ERR_DIFF_DELETION
;
938 } else if (lineBuffer
[0] == '!') {
939 return SCE_ERR_DIFF_CHANGED
;
940 } else if (lineBuffer
[0] == '+') {
941 if (strstart(lineBuffer
, "+++ ")) {
942 return SCE_ERR_DIFF_MESSAGE
;
944 return SCE_ERR_DIFF_ADDITION
;
946 } else if (lineBuffer
[0] == '-') {
947 if (strstart(lineBuffer
, "--- ")) {
948 return SCE_ERR_DIFF_MESSAGE
;
950 return SCE_ERR_DIFF_DELETION
;
952 } else if (strstart(lineBuffer
, "cf90-")) {
953 // Absoft Pro Fortran 90/95 v8.2 error and/or warning message
955 } else if (strstart(lineBuffer
, "fortcom:")) {
956 // Intel Fortran Compiler v8.0 error/warning message
957 return SCE_ERR_IFORT
;
958 } else if (strstr(lineBuffer
, "File \"") && strstr(lineBuffer
, ", line ")) {
959 return SCE_ERR_PYTHON
;
960 } else if (strstr(lineBuffer
, " in ") && strstr(lineBuffer
, " on line ")) {
962 } else if ((strstart(lineBuffer
, "Error ") ||
963 strstart(lineBuffer
, "Warning ")) &&
964 strstr(lineBuffer
, " at (") &&
965 strstr(lineBuffer
, ") : ") &&
966 (strstr(lineBuffer
, " at (") < strstr(lineBuffer
, ") : "))) {
967 // Intel Fortran Compiler error/warning message
969 } else if (strstart(lineBuffer
, "Error ")) {
970 // Borland error message
971 return SCE_ERR_BORLAND
;
972 } else if (strstart(lineBuffer
, "Warning ")) {
973 // Borland warning message
974 return SCE_ERR_BORLAND
;
975 } else if (strstr(lineBuffer
, "at line ") &&
976 (strstr(lineBuffer
, "at line ") < (lineBuffer
+ lengthLine
)) &&
977 strstr(lineBuffer
, "file ") &&
978 (strstr(lineBuffer
, "file ") < (lineBuffer
+ lengthLine
))) {
979 // Lua 4 error message
981 } else if (strstr(lineBuffer
, " at ") &&
982 (strstr(lineBuffer
, " at ") < (lineBuffer
+ lengthLine
)) &&
983 strstr(lineBuffer
, " line ") &&
984 (strstr(lineBuffer
, " line ") < (lineBuffer
+ lengthLine
)) &&
985 (strstr(lineBuffer
, " at ") < (strstr(lineBuffer
, " line ")))) {
986 // perl error message
988 } else if ((memcmp(lineBuffer
, " at ", 6) == 0) &&
989 strstr(lineBuffer
, ":line ")) {
992 } else if (strstart(lineBuffer
, "Line ") &&
993 strstr(lineBuffer
, ", file ")) {
994 // Essential Lahey Fortran error message
996 } else if (strstart(lineBuffer
, "line ") &&
997 strstr(lineBuffer
, " column ")) {
998 // HTML tidy style: line 42 column 1
1000 } else if (strstart(lineBuffer
, "\tat ") &&
1001 strstr(lineBuffer
, "(") &&
1002 strstr(lineBuffer
, ".java:")) {
1003 // Java stack back trace
1004 return SCE_ERR_JAVA_STACK
;
1006 // Look for one of the following formats:
1007 // GCC: <filename>:<line>:<message>
1008 // Microsoft: <filename>(<line>) :<message>
1009 // Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal
1010 // Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal
1011 // Microsoft: <filename>(<line>,<column>)<message>
1012 // CTags: \t<message>
1013 // Lua 5 traceback: \t<filename>:<line>:<message>
1014 // Lua 5.1: <exe>: <filename>:<line>:<message>
1015 bool initialTab
= (lineBuffer
[0] == '\t');
1016 bool initialColonPart
= false;
1018 stGccStart
, stGccDigit
, stGcc
,
1019 stMsStart
, stMsDigit
, stMsBracket
, stMsVc
, stMsDigitComma
, stMsDotNet
,
1020 stCtagsStart
, stCtagsStartString
, stCtagsStringDollar
, stCtags
,
1022 } state
= stInitial
;
1023 for (unsigned int i
= 0; i
< lengthLine
; i
++) {
1024 char ch
= lineBuffer
[i
];
1026 if ((i
+ 1) < lengthLine
)
1027 chNext
= lineBuffer
[i
+ 1];
1028 if (state
== stInitial
) {
1030 // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)
1031 if ((chNext
!= '\\') && (chNext
!= '/') && (chNext
!= ' ')) {
1032 // This check is not completely accurate as may be on
1033 // GTK+ with a file name that includes ':'.
1035 } else if (chNext
== ' ') { // indicates a Lua 5.1 error message
1036 initialColonPart
= true;
1038 } else if ((ch
== '(') && Is1To9(chNext
) && (!initialTab
)) {
1040 // Check against '0' often removes phone numbers
1042 } else if ((ch
== '\t') && (!initialTab
)) {
1044 state
= stCtagsStart
;
1046 } else if (state
== stGccStart
) { // <filename>:
1047 state
= Is1To9(ch
) ? stGccDigit
: stUnrecognized
;
1048 } else if (state
== stGccDigit
) { // <filename>:<line>
1050 state
= stGcc
; // :9.*: is GCC
1053 } else if (!Is0To9(ch
)) {
1054 state
= stUnrecognized
;
1056 } else if (state
== stMsStart
) { // <filename>(
1057 state
= Is0To9(ch
) ? stMsDigit
: stUnrecognized
;
1058 } else if (state
== stMsDigit
) { // <filename>(<line>
1060 state
= stMsDigitComma
;
1061 } else if (ch
== ')') {
1062 state
= stMsBracket
;
1063 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
1064 state
= stUnrecognized
;
1066 } else if (state
== stMsBracket
) { // <filename>(<line>)
1067 if ((ch
== ' ') && (chNext
== ':')) {
1069 } else if ((ch
== ':' && chNext
== ' ') || (ch
== ' ')) {
1070 // Possibly Delphi.. don't test against chNext as it's one of the strings below.
1072 unsigned int j
, chPos
;
1076 numstep
= 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.
1078 numstep
= 2; // otherwise add 2.
1079 for (j
= i
+ numstep
; j
< lengthLine
&& IsAlphabetic(lineBuffer
[j
]) && chPos
< sizeof(word
) - 1; j
++)
1080 word
[chPos
++] = lineBuffer
[j
];
1082 if (!CompareCaseInsensitive(word
, "error") || !CompareCaseInsensitive(word
, "warning") ||
1083 !CompareCaseInsensitive(word
, "fatal") || !CompareCaseInsensitive(word
, "catastrophic") ||
1084 !CompareCaseInsensitive(word
, "note") || !CompareCaseInsensitive(word
, "remark")) {
1087 state
= stUnrecognized
;
1089 state
= stUnrecognized
;
1091 } else if (state
== stMsDigitComma
) { // <filename>(<line>,
1095 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
1096 state
= stUnrecognized
;
1098 } else if (state
== stCtagsStart
) {
1099 if ((lineBuffer
[i
- 1] == '\t') &&
1100 ((ch
== '/' && lineBuffer
[i
+ 1] == '^') || Is0To9(ch
))) {
1103 } else if ((ch
== '/') && (lineBuffer
[i
+ 1] == '^')) {
1104 state
= stCtagsStartString
;
1106 } else if ((state
== stCtagsStartString
) && ((lineBuffer
[i
] == '$') && (lineBuffer
[i
+ 1] == '/'))) {
1107 state
= stCtagsStringDollar
;
1111 if (state
== stGcc
) {
1112 return initialColonPart
? SCE_ERR_LUA
: SCE_ERR_GCC
;
1113 } else if ((state
== stMsVc
) || (state
== stMsDotNet
)) {
1115 } else if ((state
== stCtagsStringDollar
) || (state
== stCtags
)) {
1116 return SCE_ERR_CTAG
;
1118 return SCE_ERR_DEFAULT
;
1123 static void ColouriseErrorListLine(
1125 unsigned int lengthLine
,
1126 unsigned int endPos
,
1128 bool valueSeparate
) {
1129 int startValue
= -1;
1130 int style
= RecogniseErrorListLine(lineBuffer
, lengthLine
, startValue
);
1131 if (valueSeparate
&& (startValue
>= 0)) {
1132 styler
.ColourTo(endPos
- (lengthLine
- startValue
), style
);
1133 styler
.ColourTo(endPos
, SCE_ERR_VALUE
);
1135 styler
.ColourTo(endPos
, style
);
1139 static void ColouriseErrorListDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
1140 char lineBuffer
[10000];
1141 styler
.StartAt(startPos
);
1142 styler
.StartSegment(startPos
);
1143 unsigned int linePos
= 0;
1145 // property lexer.errorlist.value.separate
1146 // For lines in the output pane that are matches from Find in Files or GCC-style
1147 // diagnostics, style the path and line number separately from the rest of the
1148 // line with style 21 used for the rest of the line.
1149 // This allows matched text to be more easily distinguished from its location.
1150 bool valueSeparate
= styler
.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;
1151 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
1152 lineBuffer
[linePos
++] = styler
[i
];
1153 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
1154 // End of line (or of line buffer) met, colourise it
1155 lineBuffer
[linePos
] = '\0';
1156 ColouriseErrorListLine(lineBuffer
, linePos
, i
, styler
, valueSeparate
);
1160 if (linePos
> 0) { // Last line does not have ending characters
1161 ColouriseErrorListLine(lineBuffer
, linePos
, startPos
+ length
- 1, styler
, valueSeparate
);
1165 static bool latexIsSpecial(int ch
) {
1166 return (ch
== '#') || (ch
== '$') || (ch
== '%') || (ch
== '&') || (ch
== '_') ||
1167 (ch
== '{') || (ch
== '}') || (ch
== ' ');
1170 static bool latexIsBlank(int ch
) {
1171 return (ch
== ' ') || (ch
== '\t');
1174 static bool latexIsBlankAndNL(int ch
) {
1175 return (ch
== ' ') || (ch
== '\t') || (ch
== '\r') || (ch
== '\n');
1178 static bool latexIsLetter(int ch
) {
1179 return isascii(ch
) && isalpha(ch
);
1182 static bool latexIsTagValid(int &i
, int l
, Accessor
&styler
) {
1184 if (styler
.SafeGetCharAt(i
) == '{') {
1187 if (styler
.SafeGetCharAt(i
) == '}') {
1189 } else if (!latexIsLetter(styler
.SafeGetCharAt(i
)) &&
1190 styler
.SafeGetCharAt(i
)!='*') {
1194 } else if (!latexIsBlank(styler
.SafeGetCharAt(i
))) {
1202 static bool latexNextNotBlankIs(int i
, int l
, Accessor
&styler
, char needle
) {
1205 ch
= styler
.SafeGetCharAt(i
);
1206 if (!latexIsBlankAndNL(ch
) && ch
!= '*') {
1217 static bool latexLastWordIs(int start
, Accessor
&styler
, const char *needle
) {
1219 unsigned int l
= static_cast<unsigned int>(strlen(needle
));
1220 int ini
= start
-l
+1;
1223 while (i
< l
&& i
< 32) {
1224 s
[i
] = styler
.SafeGetCharAt(ini
+ i
);
1229 return (strcmp(s
, needle
) == 0);
1232 static void ColouriseLatexDoc(unsigned int startPos
, int length
, int initStyle
,
1233 WordList
*[], Accessor
&styler
) {
1235 styler
.StartAt(startPos
);
1237 int state
= initStyle
;
1238 char chNext
= styler
.SafeGetCharAt(startPos
);
1239 styler
.StartSegment(startPos
);
1240 int lengthDoc
= startPos
+ length
;
1241 char chVerbatimDelim
= '\0';
1243 for (int i
= startPos
; i
< lengthDoc
; i
++) {
1245 chNext
= styler
.SafeGetCharAt(i
+ 1);
1247 if (styler
.IsLeadByte(ch
)) {
1249 chNext
= styler
.SafeGetCharAt(i
+ 1);
1254 case SCE_L_DEFAULT
:
1257 styler
.ColourTo(i
- 1, state
);
1258 if (latexIsSpecial(chNext
)) {
1259 state
= SCE_L_SPECIAL
;
1261 if (latexIsLetter(chNext
)) {
1262 state
= SCE_L_COMMAND
;
1264 if (chNext
== '(' || chNext
== '[') {
1265 styler
.ColourTo(i
-1, state
);
1266 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1269 state
= SCE_L_MATH2
;
1271 chNext
= styler
.SafeGetCharAt(i
+1);
1273 state
= SCE_L_SHORTCMD
;
1279 styler
.ColourTo(i
- 1, state
);
1281 if (chNext
== '$') {
1282 state
= SCE_L_MATH2
;
1284 chNext
= styler
.SafeGetCharAt(i
+ 1);
1288 styler
.ColourTo(i
- 1, state
);
1289 state
= SCE_L_COMMENT
;
1294 styler
.ColourTo(i
-1, state
);
1295 state
= SCE_L_DEFAULT
;
1298 case SCE_L_SHORTCMD
:
1299 styler
.ColourTo(i
, state
);
1300 state
= SCE_L_DEFAULT
;
1302 case SCE_L_COMMAND
:
1303 if (!latexIsLetter(chNext
)) {
1304 styler
.ColourTo(i
, state
);
1305 state
= SCE_L_DEFAULT
;
1306 if (latexNextNotBlankIs(i
+1, lengthDoc
, styler
, '[' )) {
1307 state
= SCE_L_CMDOPT
;
1308 } else if (latexLastWordIs(i
, styler
, "\\begin")) {
1310 } else if (latexLastWordIs(i
, styler
, "\\end")) {
1312 } else if (latexLastWordIs(i
, styler
, "\\verb") &&
1313 chNext
!= '*' && chNext
!= ' ') {
1314 chVerbatimDelim
= chNext
;
1315 state
= SCE_L_VERBATIM
;
1321 styler
.ColourTo(i
, state
);
1322 state
= SCE_L_DEFAULT
;
1326 if (latexIsTagValid(i
, lengthDoc
, styler
)) {
1327 styler
.ColourTo(i
, state
);
1328 state
= SCE_L_DEFAULT
;
1329 if (latexLastWordIs(i
, styler
, "{verbatim}")) {
1330 state
= SCE_L_VERBATIM
;
1331 } else if (latexLastWordIs(i
, styler
, "{comment}")) {
1332 state
= SCE_L_COMMENT2
;
1333 } else if (latexLastWordIs(i
, styler
, "{math}")) {
1335 } else if (latexLastWordIs(i
, styler
, "{displaymath}")) {
1336 state
= SCE_L_MATH2
;
1337 } else if (latexLastWordIs(i
, styler
, "{equation}")) {
1338 state
= SCE_L_MATH2
;
1341 state
= SCE_L_ERROR
;
1342 styler
.ColourTo(i
, state
);
1343 state
= SCE_L_DEFAULT
;
1345 chNext
= styler
.SafeGetCharAt(i
+1);
1348 if (latexIsTagValid(i
, lengthDoc
, styler
)) {
1349 styler
.ColourTo(i
, state
);
1350 state
= SCE_L_DEFAULT
;
1352 state
= SCE_L_ERROR
;
1354 chNext
= styler
.SafeGetCharAt(i
+1);
1358 styler
.ColourTo(i
, state
);
1359 state
= SCE_L_DEFAULT
;
1360 } else if (ch
== '\\' && chNext
== ')') {
1361 styler
.ColourTo(i
-1, state
);
1362 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1364 chNext
= styler
.SafeGetCharAt(i
+1);
1365 state
= SCE_L_DEFAULT
;
1366 } else if (ch
== '\\') {
1368 if (latexLastWordIs(match
, styler
, "\\end")) {
1370 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1371 if (latexLastWordIs(match
, styler
, "{math}")) {
1372 styler
.ColourTo(i
-1, state
);
1373 state
= SCE_L_COMMAND
;
1382 if (chNext
== '$') {
1384 chNext
= styler
.SafeGetCharAt(i
+ 1);
1385 styler
.ColourTo(i
, state
);
1386 state
= SCE_L_DEFAULT
;
1388 styler
.ColourTo(i
, SCE_L_ERROR
);
1389 state
= SCE_L_DEFAULT
;
1391 } else if (ch
== '\\' && chNext
== ']') {
1392 styler
.ColourTo(i
-1, state
);
1393 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1395 chNext
= styler
.SafeGetCharAt(i
+1);
1396 state
= SCE_L_DEFAULT
;
1397 } else if (ch
== '\\') {
1399 if (latexLastWordIs(match
, styler
, "\\end")) {
1401 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1402 if (latexLastWordIs(match
, styler
, "{displaymath}")) {
1403 styler
.ColourTo(i
-1, state
);
1404 state
= SCE_L_COMMAND
;
1405 } else if (latexLastWordIs(match
, styler
, "{equation}")) {
1406 styler
.ColourTo(i
-1, state
);
1407 state
= SCE_L_COMMAND
;
1413 case SCE_L_COMMENT
:
1414 if (ch
== '\r' || ch
== '\n') {
1415 styler
.ColourTo(i
- 1, state
);
1416 state
= SCE_L_DEFAULT
;
1419 case SCE_L_COMMENT2
:
1422 if (latexLastWordIs(match
, styler
, "\\end")) {
1424 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1425 if (latexLastWordIs(match
, styler
, "{comment}")) {
1426 styler
.ColourTo(i
-1, state
);
1427 state
= SCE_L_COMMAND
;
1433 case SCE_L_VERBATIM
:
1436 if (latexLastWordIs(match
, styler
, "\\end")) {
1438 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1439 if (latexLastWordIs(match
, styler
, "{verbatim}")) {
1440 styler
.ColourTo(i
-1, state
);
1441 state
= SCE_L_COMMAND
;
1445 } else if (chNext
== chVerbatimDelim
) {
1446 styler
.ColourTo(i
+1, state
);
1447 state
= SCE_L_DEFAULT
;
1448 chVerbatimDelim
= '\0';
1449 } else if (chVerbatimDelim
!= '\0' && (ch
== '\n' || ch
== '\r')) {
1450 styler
.ColourTo(i
, SCE_L_ERROR
);
1451 state
= SCE_L_DEFAULT
;
1452 chVerbatimDelim
= '\0';
1457 styler
.ColourTo(lengthDoc
-1, state
);
1460 static const char *const batchWordListDesc
[] = {
1461 "Internal Commands",
1462 "External Commands",
1466 static const char *const emptyWordListDesc
[] = {
1470 static void ColouriseNullDoc(unsigned int startPos
, int length
, int, WordList
*[],
1472 // Null language means all style bytes are 0 so just mark the end - no need to fill in.
1474 styler
.StartAt(startPos
+ length
- 1);
1475 styler
.StartSegment(startPos
+ length
- 1);
1476 styler
.ColourTo(startPos
+ length
- 1, 0);
1480 LexerModule
lmBatch(SCLEX_BATCH
, ColouriseBatchDoc
, "batch", 0, batchWordListDesc
);
1481 LexerModule
lmDiff(SCLEX_DIFF
, ColouriseDiffDoc
, "diff", FoldDiffDoc
, emptyWordListDesc
);
1482 LexerModule
lmPo(SCLEX_PO
, ColourisePoDoc
, "po", 0, emptyWordListDesc
);
1483 LexerModule
lmProps(SCLEX_PROPERTIES
, ColourisePropsDoc
, "props", FoldPropsDoc
, emptyWordListDesc
);
1484 LexerModule
lmMake(SCLEX_MAKEFILE
, ColouriseMakeDoc
, "makefile", 0, emptyWordListDesc
);
1485 LexerModule
lmErrorList(SCLEX_ERRORLIST
, ColouriseErrorListDoc
, "errorlist", 0, emptyWordListDesc
);
1486 LexerModule
lmLatex(SCLEX_LATEX
, ColouriseLatexDoc
, "latex", 0, emptyWordListDesc
);
1487 LexerModule
lmNull(SCLEX_NULL
, ColouriseNullDoc
, "null");