]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/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.
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 #define DIFF_BUFFER_START_SIZE 16
504 // Note that ColouriseDiffLine analyzes only the first DIFF_BUFFER_START_SIZE
505 // characters of each line to classify the line.
507 static void ColouriseDiffLine(char *lineBuffer
, int endLine
, Accessor
&styler
) {
508 // It is needed to remember the current state to recognize starting
509 // comment lines before the first "diff " or "--- ". If a real
510 // difference starts then each line starting with ' ' is a whitespace
511 // otherwise it is considered a comment (Only in..., Binary file...)
512 if (0 == strncmp(lineBuffer
, "diff ", 5)) {
513 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
514 } else if (0 == strncmp(lineBuffer
, "Index: ", 7)) { // For subversion's diff
515 styler
.ColourTo(endLine
, SCE_DIFF_COMMAND
);
516 } else if (0 == strncmp(lineBuffer
, "---", 3) && lineBuffer
[3] != '-') {
517 // In a context diff, --- appears in both the header and the position markers
518 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+ 4) && !strchr(lineBuffer
, '/'))
519 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
520 else if (lineBuffer
[3] == '\r' || lineBuffer
[3] == '\n')
521 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
523 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
524 } else if (0 == strncmp(lineBuffer
, "+++ ", 4)) {
525 // I don't know of any diff where "+++ " is a position marker, but for
526 // consistency, do the same as with "--- " and "*** ".
527 if (atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
528 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
530 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
531 } else if (0 == strncmp(lineBuffer
, "====", 4)) { // For p4's diff
532 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
533 } else if (0 == strncmp(lineBuffer
, "***", 3)) {
534 // In a context diff, *** appears in both the header and the position markers.
535 // Also ******** is a chunk header, but here it's treated as part of the
536 // position marker since there is no separate style for a chunk header.
537 if (lineBuffer
[3] == ' ' && atoi(lineBuffer
+4) && !strchr(lineBuffer
, '/'))
538 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
539 else if (lineBuffer
[3] == '*')
540 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
542 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
543 } else if (0 == strncmp(lineBuffer
, "? ", 2)) { // For difflib
544 styler
.ColourTo(endLine
, SCE_DIFF_HEADER
);
545 } else if (lineBuffer
[0] == '@') {
546 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
547 } else if (lineBuffer
[0] >= '0' && lineBuffer
[0] <= '9') {
548 styler
.ColourTo(endLine
, SCE_DIFF_POSITION
);
549 } else if (lineBuffer
[0] == '-' || lineBuffer
[0] == '<') {
550 styler
.ColourTo(endLine
, SCE_DIFF_DELETED
);
551 } else if (lineBuffer
[0] == '+' || lineBuffer
[0] == '>') {
552 styler
.ColourTo(endLine
, SCE_DIFF_ADDED
);
553 } else if (lineBuffer
[0] == '!') {
554 styler
.ColourTo(endLine
, SCE_DIFF_CHANGED
);
555 } else if (lineBuffer
[0] != ' ') {
556 styler
.ColourTo(endLine
, SCE_DIFF_COMMENT
);
558 styler
.ColourTo(endLine
, SCE_DIFF_DEFAULT
);
562 static void ColouriseDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
563 char lineBuffer
[DIFF_BUFFER_START_SIZE
];
564 styler
.StartAt(startPos
);
565 styler
.StartSegment(startPos
);
566 unsigned int linePos
= 0;
567 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
568 if (AtEOL(styler
, i
)) {
569 if (linePos
< DIFF_BUFFER_START_SIZE
) {
570 lineBuffer
[linePos
] = 0;
572 ColouriseDiffLine(lineBuffer
, i
, styler
);
574 } else if (linePos
< DIFF_BUFFER_START_SIZE
- 1) {
575 lineBuffer
[linePos
++] = styler
[i
];
576 } else if (linePos
== DIFF_BUFFER_START_SIZE
- 1) {
577 lineBuffer
[linePos
++] = 0;
580 if (linePos
> 0) { // Last line does not have ending characters
581 if (linePos
< DIFF_BUFFER_START_SIZE
) {
582 lineBuffer
[linePos
] = 0;
584 ColouriseDiffLine(lineBuffer
, startPos
+ length
- 1, styler
);
588 static void FoldDiffDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
589 int curLine
= styler
.GetLine(startPos
);
590 int curLineStart
= styler
.LineStart(curLine
);
591 int prevLevel
= curLine
> 0 ? styler
.LevelAt(curLine
- 1) : SC_FOLDLEVELBASE
;
595 int lineType
= styler
.StyleAt(curLineStart
);
596 if (lineType
== SCE_DIFF_COMMAND
)
597 nextLevel
= SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
;
598 else if (lineType
== SCE_DIFF_HEADER
)
599 nextLevel
= (SC_FOLDLEVELBASE
+ 1) | SC_FOLDLEVELHEADERFLAG
;
600 else if (lineType
== SCE_DIFF_POSITION
&& styler
[curLineStart
] != '-')
601 nextLevel
= (SC_FOLDLEVELBASE
+ 2) | SC_FOLDLEVELHEADERFLAG
;
602 else if (prevLevel
& SC_FOLDLEVELHEADERFLAG
)
603 nextLevel
= (prevLevel
& SC_FOLDLEVELNUMBERMASK
) + 1;
605 nextLevel
= prevLevel
;
607 if ((nextLevel
& SC_FOLDLEVELHEADERFLAG
) && (nextLevel
== prevLevel
))
608 styler
.SetLevel(curLine
-1, prevLevel
& ~SC_FOLDLEVELHEADERFLAG
);
610 styler
.SetLevel(curLine
, nextLevel
);
611 prevLevel
= nextLevel
;
613 curLineStart
= styler
.LineStart(++curLine
);
614 } while (static_cast<int>(startPos
) + length
> curLineStart
);
617 static void ColourisePoLine(
619 unsigned int lengthLine
,
620 unsigned int startLine
,
625 static unsigned int state
= SCE_PO_DEFAULT
;
626 unsigned int state_start
= SCE_PO_DEFAULT
;
628 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) // Skip initial spaces
630 if (i
< lengthLine
) {
631 if (lineBuffer
[i
] == '#') {
632 // check if the comment contains any flags ("#, ") and
633 // then whether the flags contain "fuzzy"
634 if (strstart(lineBuffer
, "#, ") && strstr(lineBuffer
, "fuzzy"))
635 styler
.ColourTo(endPos
, SCE_PO_FUZZY
);
637 styler
.ColourTo(endPos
, SCE_PO_COMMENT
);
639 if (lineBuffer
[0] == '"') {
640 // line continuation, use previous style
641 styler
.ColourTo(endPos
, state
);
643 // this implicitly also matches "msgid_plural"
644 } else if (strstart(lineBuffer
, "msgid")) {
645 state_start
= SCE_PO_MSGID
;
646 state
= SCE_PO_MSGID_TEXT
;
647 } else if (strstart(lineBuffer
, "msgstr")) {
648 state_start
= SCE_PO_MSGSTR
;
649 state
= SCE_PO_MSGSTR_TEXT
;
650 } else if (strstart(lineBuffer
, "msgctxt")) {
651 state_start
= SCE_PO_MSGCTXT
;
652 state
= SCE_PO_MSGCTXT_TEXT
;
654 if (state_start
!= SCE_PO_DEFAULT
) {
655 // find the next space
656 while ((i
< lengthLine
) && ! isspacechar(lineBuffer
[i
]))
658 styler
.ColourTo(startLine
+ i
- 1, state_start
);
659 styler
.ColourTo(startLine
+ i
, SCE_PO_DEFAULT
);
660 styler
.ColourTo(endPos
, state
);
664 styler
.ColourTo(endPos
, SCE_PO_DEFAULT
);
668 static void ColourisePoDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
669 char lineBuffer
[1024];
670 styler
.StartAt(startPos
);
671 styler
.StartSegment(startPos
);
672 unsigned int linePos
= 0;
673 unsigned int startLine
= startPos
;
674 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
675 lineBuffer
[linePos
++] = styler
[i
];
676 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
677 // End of line (or of line buffer) met, colourise it
678 lineBuffer
[linePos
] = '\0';
679 ColourisePoLine(lineBuffer
, linePos
, startLine
, i
, styler
);
684 if (linePos
> 0) { // Last line does not have ending characters
685 ColourisePoLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
689 static inline bool isassignchar(unsigned char ch
) {
690 return (ch
== '=') || (ch
== ':');
693 static void ColourisePropsLine(
695 unsigned int lengthLine
,
696 unsigned int startLine
,
699 bool allowInitialSpaces
) {
702 if (allowInitialSpaces
) {
703 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) // Skip initial spaces
706 if (isspacechar(lineBuffer
[i
])) // don't allow initial spaces
710 if (i
< lengthLine
) {
711 if (lineBuffer
[i
] == '#' || lineBuffer
[i
] == '!' || lineBuffer
[i
] == ';') {
712 styler
.ColourTo(endPos
, SCE_PROPS_COMMENT
);
713 } else if (lineBuffer
[i
] == '[') {
714 styler
.ColourTo(endPos
, SCE_PROPS_SECTION
);
715 } else if (lineBuffer
[i
] == '@') {
716 styler
.ColourTo(startLine
+ i
, SCE_PROPS_DEFVAL
);
717 if (isassignchar(lineBuffer
[i
++]))
718 styler
.ColourTo(startLine
+ i
, SCE_PROPS_ASSIGNMENT
);
719 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
721 // Search for the '=' character
722 while ((i
< lengthLine
) && !isassignchar(lineBuffer
[i
]))
724 if ((i
< lengthLine
) && isassignchar(lineBuffer
[i
])) {
725 styler
.ColourTo(startLine
+ i
- 1, SCE_PROPS_KEY
);
726 styler
.ColourTo(startLine
+ i
, SCE_PROPS_ASSIGNMENT
);
727 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
729 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
733 styler
.ColourTo(endPos
, SCE_PROPS_DEFAULT
);
737 static void ColourisePropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
738 char lineBuffer
[1024];
739 styler
.StartAt(startPos
);
740 styler
.StartSegment(startPos
);
741 unsigned int linePos
= 0;
742 unsigned int startLine
= startPos
;
744 // property lexer.props.allow.initial.spaces
745 // For properties files, set to 0 to style all lines that start with whitespace in the default style.
746 // This is not suitable for SciTE .properties files which use indentation for flow control but
747 // can be used for RFC2822 text where indentation is used for continuation lines.
748 bool allowInitialSpaces
= styler
.GetPropertyInt("lexer.props.allow.initial.spaces", 1) != 0;
750 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
751 lineBuffer
[linePos
++] = styler
[i
];
752 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
753 // End of line (or of line buffer) met, colourise it
754 lineBuffer
[linePos
] = '\0';
755 ColourisePropsLine(lineBuffer
, linePos
, startLine
, i
, styler
, allowInitialSpaces
);
760 if (linePos
> 0) { // Last line does not have ending characters
761 ColourisePropsLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
, allowInitialSpaces
);
765 // adaption by ksc, using the "} else {" trick of 1.53
767 static void FoldPropsDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
768 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
770 unsigned int endPos
= startPos
+ length
;
771 int visibleChars
= 0;
772 int lineCurrent
= styler
.GetLine(startPos
);
774 char chNext
= styler
[startPos
];
775 int styleNext
= styler
.StyleAt(startPos
);
776 bool headerPoint
= false;
779 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
781 chNext
= styler
[i
+1];
783 int style
= styleNext
;
784 styleNext
= styler
.StyleAt(i
+ 1);
785 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
787 if (style
== SCE_PROPS_SECTION
) {
792 lev
= SC_FOLDLEVELBASE
;
794 if (lineCurrent
> 0) {
795 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
797 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
798 lev
= SC_FOLDLEVELBASE
+ 1;
800 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
805 lev
= SC_FOLDLEVELBASE
;
807 if (visibleChars
== 0 && foldCompact
)
808 lev
|= SC_FOLDLEVELWHITEFLAG
;
811 lev
|= SC_FOLDLEVELHEADERFLAG
;
813 if (lev
!= styler
.LevelAt(lineCurrent
)) {
814 styler
.SetLevel(lineCurrent
, lev
);
821 if (!isspacechar(ch
))
825 if (lineCurrent
> 0) {
826 int levelPrevious
= styler
.LevelAt(lineCurrent
- 1);
827 if (levelPrevious
& SC_FOLDLEVELHEADERFLAG
) {
828 lev
= SC_FOLDLEVELBASE
+ 1;
830 lev
= levelPrevious
& SC_FOLDLEVELNUMBERMASK
;
833 lev
= SC_FOLDLEVELBASE
;
835 int flagsNext
= styler
.LevelAt(lineCurrent
);
836 styler
.SetLevel(lineCurrent
, lev
| (flagsNext
& ~SC_FOLDLEVELNUMBERMASK
));
839 static void ColouriseMakeLine(
841 unsigned int lengthLine
,
842 unsigned int startLine
,
847 int lastNonSpace
= -1;
848 unsigned int state
= SCE_MAKE_DEFAULT
;
849 bool bSpecial
= false;
851 // check for a tab character in column 0 indicating a command
852 bool bCommand
= false;
853 if ((lengthLine
> 0) && (lineBuffer
[0] == '\t'))
856 // Skip initial spaces
857 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
])) {
860 if (lineBuffer
[i
] == '#') { // Comment
861 styler
.ColourTo(endPos
, SCE_MAKE_COMMENT
);
864 if (lineBuffer
[i
] == '!') { // Special directive
865 styler
.ColourTo(endPos
, SCE_MAKE_PREPROCESSOR
);
869 while (i
< lengthLine
) {
870 if (lineBuffer
[i
] == '$' && lineBuffer
[i
+ 1] == '(') {
871 styler
.ColourTo(startLine
+ i
- 1, state
);
872 state
= SCE_MAKE_IDENTIFIER
;
874 } else if (state
== SCE_MAKE_IDENTIFIER
&& lineBuffer
[i
] == ')') {
875 if (--varCount
== 0) {
876 styler
.ColourTo(startLine
+ i
, state
);
877 state
= SCE_MAKE_DEFAULT
;
881 // skip identifier and target styling if this is a command line
882 if (!bSpecial
&& !bCommand
) {
883 if (lineBuffer
[i
] == ':') {
884 if (((i
+ 1) < lengthLine
) && (lineBuffer
[i
+ 1] == '=')) {
885 // it's a ':=', so style as an identifier
886 if (lastNonSpace
>= 0)
887 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_IDENTIFIER
);
888 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
889 styler
.ColourTo(startLine
+ i
+ 1, SCE_MAKE_OPERATOR
);
891 // We should check that no colouring was made since the beginning of the line,
892 // to avoid colouring stuff like /OUT:file
893 if (lastNonSpace
>= 0)
894 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_TARGET
);
895 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
896 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
898 bSpecial
= true; // Only react to the first ':' of the line
899 state
= SCE_MAKE_DEFAULT
;
900 } else if (lineBuffer
[i
] == '=') {
901 if (lastNonSpace
>= 0)
902 styler
.ColourTo(startLine
+ lastNonSpace
, SCE_MAKE_IDENTIFIER
);
903 styler
.ColourTo(startLine
+ i
- 1, SCE_MAKE_DEFAULT
);
904 styler
.ColourTo(startLine
+ i
, SCE_MAKE_OPERATOR
);
905 bSpecial
= true; // Only react to the first '=' of the line
906 state
= SCE_MAKE_DEFAULT
;
909 if (!isspacechar(lineBuffer
[i
])) {
914 if (state
== SCE_MAKE_IDENTIFIER
) {
915 styler
.ColourTo(endPos
, SCE_MAKE_IDEOL
); // Error, variable reference not ended
917 styler
.ColourTo(endPos
, SCE_MAKE_DEFAULT
);
921 static void ColouriseMakeDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
922 char lineBuffer
[1024];
923 styler
.StartAt(startPos
);
924 styler
.StartSegment(startPos
);
925 unsigned int linePos
= 0;
926 unsigned int startLine
= startPos
;
927 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
928 lineBuffer
[linePos
++] = styler
[i
];
929 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
930 // End of line (or of line buffer) met, colourise it
931 lineBuffer
[linePos
] = '\0';
932 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, i
, styler
);
937 if (linePos
> 0) { // Last line does not have ending characters
938 ColouriseMakeLine(lineBuffer
, linePos
, startLine
, startPos
+ length
- 1, styler
);
942 static int RecogniseErrorListLine(const char *lineBuffer
, unsigned int lengthLine
, int &startValue
) {
943 if (lineBuffer
[0] == '>') {
944 // Command or return status
946 } else if (lineBuffer
[0] == '<') {
948 return SCE_ERR_DIFF_DELETION
;
949 } else if (lineBuffer
[0] == '!') {
950 return SCE_ERR_DIFF_CHANGED
;
951 } else if (lineBuffer
[0] == '+') {
952 if (strstart(lineBuffer
, "+++ ")) {
953 return SCE_ERR_DIFF_MESSAGE
;
955 return SCE_ERR_DIFF_ADDITION
;
957 } else if (lineBuffer
[0] == '-') {
958 if (strstart(lineBuffer
, "--- ")) {
959 return SCE_ERR_DIFF_MESSAGE
;
961 return SCE_ERR_DIFF_DELETION
;
963 } else if (strstart(lineBuffer
, "cf90-")) {
964 // Absoft Pro Fortran 90/95 v8.2 error and/or warning message
966 } else if (strstart(lineBuffer
, "fortcom:")) {
967 // Intel Fortran Compiler v8.0 error/warning message
968 return SCE_ERR_IFORT
;
969 } else if (strstr(lineBuffer
, "File \"") && strstr(lineBuffer
, ", line ")) {
970 return SCE_ERR_PYTHON
;
971 } else if (strstr(lineBuffer
, " in ") && strstr(lineBuffer
, " on line ")) {
973 } else if ((strstart(lineBuffer
, "Error ") ||
974 strstart(lineBuffer
, "Warning ")) &&
975 strstr(lineBuffer
, " at (") &&
976 strstr(lineBuffer
, ") : ") &&
977 (strstr(lineBuffer
, " at (") < strstr(lineBuffer
, ") : "))) {
978 // Intel Fortran Compiler error/warning message
980 } else if (strstart(lineBuffer
, "Error ")) {
981 // Borland error message
982 return SCE_ERR_BORLAND
;
983 } else if (strstart(lineBuffer
, "Warning ")) {
984 // Borland warning message
985 return SCE_ERR_BORLAND
;
986 } else if (strstr(lineBuffer
, "at line ") &&
987 (strstr(lineBuffer
, "at line ") < (lineBuffer
+ lengthLine
)) &&
988 strstr(lineBuffer
, "file ") &&
989 (strstr(lineBuffer
, "file ") < (lineBuffer
+ lengthLine
))) {
990 // Lua 4 error message
992 } else if (strstr(lineBuffer
, " at ") &&
993 (strstr(lineBuffer
, " at ") < (lineBuffer
+ lengthLine
)) &&
994 strstr(lineBuffer
, " line ") &&
995 (strstr(lineBuffer
, " line ") < (lineBuffer
+ lengthLine
)) &&
996 (strstr(lineBuffer
, " at ") < (strstr(lineBuffer
, " line ")))) {
997 // perl error message
999 } else if ((memcmp(lineBuffer
, " at ", 6) == 0) &&
1000 strstr(lineBuffer
, ":line ")) {
1003 } else if (strstart(lineBuffer
, "Line ") &&
1004 strstr(lineBuffer
, ", file ")) {
1005 // Essential Lahey Fortran error message
1007 } else if (strstart(lineBuffer
, "line ") &&
1008 strstr(lineBuffer
, " column ")) {
1009 // HTML tidy style: line 42 column 1
1010 return SCE_ERR_TIDY
;
1011 } else if (strstart(lineBuffer
, "\tat ") &&
1012 strstr(lineBuffer
, "(") &&
1013 strstr(lineBuffer
, ".java:")) {
1014 // Java stack back trace
1015 return SCE_ERR_JAVA_STACK
;
1017 // Look for one of the following formats:
1018 // GCC: <filename>:<line>:<message>
1019 // Microsoft: <filename>(<line>) :<message>
1020 // Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal
1021 // Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal
1022 // Microsoft: <filename>(<line>,<column>)<message>
1023 // CTags: \t<message>
1024 // Lua 5 traceback: \t<filename>:<line>:<message>
1025 // Lua 5.1: <exe>: <filename>:<line>:<message>
1026 bool initialTab
= (lineBuffer
[0] == '\t');
1027 bool initialColonPart
= false;
1029 stGccStart
, stGccDigit
, stGccColumn
, stGcc
,
1030 stMsStart
, stMsDigit
, stMsBracket
, stMsVc
, stMsDigitComma
, stMsDotNet
,
1031 stCtagsStart
, stCtagsStartString
, stCtagsStringDollar
, stCtags
,
1033 } state
= stInitial
;
1034 for (unsigned int i
= 0; i
< lengthLine
; i
++) {
1035 char ch
= lineBuffer
[i
];
1037 if ((i
+ 1) < lengthLine
)
1038 chNext
= lineBuffer
[i
+ 1];
1039 if (state
== stInitial
) {
1041 // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)
1042 if ((chNext
!= '\\') && (chNext
!= '/') && (chNext
!= ' ')) {
1043 // This check is not completely accurate as may be on
1044 // GTK+ with a file name that includes ':'.
1046 } else if (chNext
== ' ') { // indicates a Lua 5.1 error message
1047 initialColonPart
= true;
1049 } else if ((ch
== '(') && Is1To9(chNext
) && (!initialTab
)) {
1051 // Check against '0' often removes phone numbers
1053 } else if ((ch
== '\t') && (!initialTab
)) {
1055 state
= stCtagsStart
;
1057 } else if (state
== stGccStart
) { // <filename>:
1058 state
= Is1To9(ch
) ? stGccDigit
: stUnrecognized
;
1059 } else if (state
== stGccDigit
) { // <filename>:<line>
1061 state
= stGccColumn
; // :9.*: is GCC
1063 } else if (!Is0To9(ch
)) {
1064 state
= stUnrecognized
;
1066 } else if (state
== stGccColumn
) { // <filename>:<line>:<column>
1073 } else if (state
== stMsStart
) { // <filename>(
1074 state
= Is0To9(ch
) ? stMsDigit
: stUnrecognized
;
1075 } else if (state
== stMsDigit
) { // <filename>(<line>
1077 state
= stMsDigitComma
;
1078 } else if (ch
== ')') {
1079 state
= stMsBracket
;
1080 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
1081 state
= stUnrecognized
;
1083 } else if (state
== stMsBracket
) { // <filename>(<line>)
1084 if ((ch
== ' ') && (chNext
== ':')) {
1086 } else if ((ch
== ':' && chNext
== ' ') || (ch
== ' ')) {
1087 // Possibly Delphi.. don't test against chNext as it's one of the strings below.
1089 unsigned int j
, chPos
;
1093 numstep
= 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.
1095 numstep
= 2; // otherwise add 2.
1096 for (j
= i
+ numstep
; j
< lengthLine
&& IsAlphabetic(lineBuffer
[j
]) && chPos
< sizeof(word
) - 1; j
++)
1097 word
[chPos
++] = lineBuffer
[j
];
1099 if (!CompareCaseInsensitive(word
, "error") || !CompareCaseInsensitive(word
, "warning") ||
1100 !CompareCaseInsensitive(word
, "fatal") || !CompareCaseInsensitive(word
, "catastrophic") ||
1101 !CompareCaseInsensitive(word
, "note") || !CompareCaseInsensitive(word
, "remark")) {
1104 state
= stUnrecognized
;
1106 state
= stUnrecognized
;
1108 } else if (state
== stMsDigitComma
) { // <filename>(<line>,
1112 } else if ((ch
!= ' ') && !Is0To9(ch
)) {
1113 state
= stUnrecognized
;
1115 } else if (state
== stCtagsStart
) {
1116 if ((lineBuffer
[i
- 1] == '\t') &&
1117 ((ch
== '/' && lineBuffer
[i
+ 1] == '^') || Is0To9(ch
))) {
1120 } else if ((ch
== '/') && (lineBuffer
[i
+ 1] == '^')) {
1121 state
= stCtagsStartString
;
1123 } else if ((state
== stCtagsStartString
) && ((lineBuffer
[i
] == '$') && (lineBuffer
[i
+ 1] == '/'))) {
1124 state
= stCtagsStringDollar
;
1128 if (state
== stGcc
) {
1129 return initialColonPart
? SCE_ERR_LUA
: SCE_ERR_GCC
;
1130 } else if ((state
== stMsVc
) || (state
== stMsDotNet
)) {
1132 } else if ((state
== stCtagsStringDollar
) || (state
== stCtags
)) {
1133 return SCE_ERR_CTAG
;
1135 return SCE_ERR_DEFAULT
;
1140 static void ColouriseErrorListLine(
1142 unsigned int lengthLine
,
1143 unsigned int endPos
,
1145 bool valueSeparate
) {
1146 int startValue
= -1;
1147 int style
= RecogniseErrorListLine(lineBuffer
, lengthLine
, startValue
);
1148 if (valueSeparate
&& (startValue
>= 0)) {
1149 styler
.ColourTo(endPos
- (lengthLine
- startValue
), style
);
1150 styler
.ColourTo(endPos
, SCE_ERR_VALUE
);
1152 styler
.ColourTo(endPos
, style
);
1156 static void ColouriseErrorListDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
1157 char lineBuffer
[10000];
1158 styler
.StartAt(startPos
);
1159 styler
.StartSegment(startPos
);
1160 unsigned int linePos
= 0;
1162 // property lexer.errorlist.value.separate
1163 // For lines in the output pane that are matches from Find in Files or GCC-style
1164 // diagnostics, style the path and line number separately from the rest of the
1165 // line with style 21 used for the rest of the line.
1166 // This allows matched text to be more easily distinguished from its location.
1167 bool valueSeparate
= styler
.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;
1168 for (unsigned int i
= startPos
; i
< startPos
+ length
; i
++) {
1169 lineBuffer
[linePos
++] = styler
[i
];
1170 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
1171 // End of line (or of line buffer) met, colourise it
1172 lineBuffer
[linePos
] = '\0';
1173 ColouriseErrorListLine(lineBuffer
, linePos
, i
, styler
, valueSeparate
);
1177 if (linePos
> 0) { // Last line does not have ending characters
1178 ColouriseErrorListLine(lineBuffer
, linePos
, startPos
+ length
- 1, styler
, valueSeparate
);
1182 static bool latexIsSpecial(int ch
) {
1183 return (ch
== '#') || (ch
== '$') || (ch
== '%') || (ch
== '&') || (ch
== '_') ||
1184 (ch
== '{') || (ch
== '}') || (ch
== ' ');
1187 static bool latexIsBlank(int ch
) {
1188 return (ch
== ' ') || (ch
== '\t');
1191 static bool latexIsBlankAndNL(int ch
) {
1192 return (ch
== ' ') || (ch
== '\t') || (ch
== '\r') || (ch
== '\n');
1195 static bool latexIsLetter(int ch
) {
1196 return isascii(ch
) && isalpha(ch
);
1199 static bool latexIsTagValid(int &i
, int l
, Accessor
&styler
) {
1201 if (styler
.SafeGetCharAt(i
) == '{') {
1204 if (styler
.SafeGetCharAt(i
) == '}') {
1206 } else if (!latexIsLetter(styler
.SafeGetCharAt(i
)) &&
1207 styler
.SafeGetCharAt(i
)!='*') {
1211 } else if (!latexIsBlank(styler
.SafeGetCharAt(i
))) {
1219 static bool latexNextNotBlankIs(int i
, int l
, Accessor
&styler
, char needle
) {
1222 ch
= styler
.SafeGetCharAt(i
);
1223 if (!latexIsBlankAndNL(ch
) && ch
!= '*') {
1234 static bool latexLastWordIs(int start
, Accessor
&styler
, const char *needle
) {
1236 unsigned int l
= static_cast<unsigned int>(strlen(needle
));
1237 int ini
= start
-l
+1;
1240 while (i
< l
&& i
< 32) {
1241 s
[i
] = styler
.SafeGetCharAt(ini
+ i
);
1246 return (strcmp(s
, needle
) == 0);
1249 static void ColouriseLatexDoc(unsigned int startPos
, int length
, int initStyle
,
1250 WordList
*[], Accessor
&styler
) {
1252 styler
.StartAt(startPos
);
1254 int state
= initStyle
;
1255 char chNext
= styler
.SafeGetCharAt(startPos
);
1256 styler
.StartSegment(startPos
);
1257 int lengthDoc
= startPos
+ length
;
1258 char chVerbatimDelim
= '\0';
1260 for (int i
= startPos
; i
< lengthDoc
; i
++) {
1262 chNext
= styler
.SafeGetCharAt(i
+ 1);
1264 if (styler
.IsLeadByte(ch
)) {
1266 chNext
= styler
.SafeGetCharAt(i
+ 1);
1271 case SCE_L_DEFAULT
:
1274 styler
.ColourTo(i
- 1, state
);
1275 if (latexIsSpecial(chNext
)) {
1276 state
= SCE_L_SPECIAL
;
1278 if (latexIsLetter(chNext
)) {
1279 state
= SCE_L_COMMAND
;
1281 if (chNext
== '(' || chNext
== '[') {
1282 styler
.ColourTo(i
-1, state
);
1283 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1286 state
= SCE_L_MATH2
;
1288 chNext
= styler
.SafeGetCharAt(i
+1);
1290 state
= SCE_L_SHORTCMD
;
1296 styler
.ColourTo(i
- 1, state
);
1298 if (chNext
== '$') {
1299 state
= SCE_L_MATH2
;
1301 chNext
= styler
.SafeGetCharAt(i
+ 1);
1305 styler
.ColourTo(i
- 1, state
);
1306 state
= SCE_L_COMMENT
;
1311 styler
.ColourTo(i
-1, state
);
1312 state
= SCE_L_DEFAULT
;
1315 case SCE_L_SHORTCMD
:
1316 styler
.ColourTo(i
, state
);
1317 state
= SCE_L_DEFAULT
;
1319 case SCE_L_COMMAND
:
1320 if (!latexIsLetter(chNext
)) {
1321 styler
.ColourTo(i
, state
);
1322 state
= SCE_L_DEFAULT
;
1323 if (latexNextNotBlankIs(i
+1, lengthDoc
, styler
, '[' )) {
1324 state
= SCE_L_CMDOPT
;
1325 } else if (latexLastWordIs(i
, styler
, "\\begin")) {
1327 } else if (latexLastWordIs(i
, styler
, "\\end")) {
1329 } else if (latexLastWordIs(i
, styler
, "\\verb") &&
1330 chNext
!= '*' && chNext
!= ' ') {
1331 chVerbatimDelim
= chNext
;
1332 state
= SCE_L_VERBATIM
;
1338 styler
.ColourTo(i
, state
);
1339 state
= SCE_L_DEFAULT
;
1343 if (latexIsTagValid(i
, lengthDoc
, styler
)) {
1344 styler
.ColourTo(i
, state
);
1345 state
= SCE_L_DEFAULT
;
1346 if (latexLastWordIs(i
, styler
, "{verbatim}")) {
1347 state
= SCE_L_VERBATIM
;
1348 } else if (latexLastWordIs(i
, styler
, "{comment}")) {
1349 state
= SCE_L_COMMENT2
;
1350 } else if (latexLastWordIs(i
, styler
, "{math}")) {
1352 } else if (latexLastWordIs(i
, styler
, "{displaymath}")) {
1353 state
= SCE_L_MATH2
;
1354 } else if (latexLastWordIs(i
, styler
, "{equation}")) {
1355 state
= SCE_L_MATH2
;
1358 state
= SCE_L_ERROR
;
1359 styler
.ColourTo(i
, state
);
1360 state
= SCE_L_DEFAULT
;
1362 chNext
= styler
.SafeGetCharAt(i
+1);
1365 if (latexIsTagValid(i
, lengthDoc
, styler
)) {
1366 styler
.ColourTo(i
, state
);
1367 state
= SCE_L_DEFAULT
;
1369 state
= SCE_L_ERROR
;
1371 chNext
= styler
.SafeGetCharAt(i
+1);
1375 styler
.ColourTo(i
, state
);
1376 state
= SCE_L_DEFAULT
;
1377 } else if (ch
== '\\' && chNext
== ')') {
1378 styler
.ColourTo(i
-1, state
);
1379 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1381 chNext
= styler
.SafeGetCharAt(i
+1);
1382 state
= SCE_L_DEFAULT
;
1383 } else if (ch
== '\\') {
1385 if (latexLastWordIs(match
, styler
, "\\end")) {
1387 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1388 if (latexLastWordIs(match
, styler
, "{math}")) {
1389 styler
.ColourTo(i
-1, state
);
1390 state
= SCE_L_COMMAND
;
1399 if (chNext
== '$') {
1401 chNext
= styler
.SafeGetCharAt(i
+ 1);
1402 styler
.ColourTo(i
, state
);
1403 state
= SCE_L_DEFAULT
;
1405 styler
.ColourTo(i
, SCE_L_ERROR
);
1406 state
= SCE_L_DEFAULT
;
1408 } else if (ch
== '\\' && chNext
== ']') {
1409 styler
.ColourTo(i
-1, state
);
1410 styler
.ColourTo(i
+1, SCE_L_SHORTCMD
);
1412 chNext
= styler
.SafeGetCharAt(i
+1);
1413 state
= SCE_L_DEFAULT
;
1414 } else if (ch
== '\\') {
1416 if (latexLastWordIs(match
, styler
, "\\end")) {
1418 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1419 if (latexLastWordIs(match
, styler
, "{displaymath}")) {
1420 styler
.ColourTo(i
-1, state
);
1421 state
= SCE_L_COMMAND
;
1422 } else if (latexLastWordIs(match
, styler
, "{equation}")) {
1423 styler
.ColourTo(i
-1, state
);
1424 state
= SCE_L_COMMAND
;
1430 case SCE_L_COMMENT
:
1431 if (ch
== '\r' || ch
== '\n') {
1432 styler
.ColourTo(i
- 1, state
);
1433 state
= SCE_L_DEFAULT
;
1436 case SCE_L_COMMENT2
:
1439 if (latexLastWordIs(match
, styler
, "\\end")) {
1441 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1442 if (latexLastWordIs(match
, styler
, "{comment}")) {
1443 styler
.ColourTo(i
-1, state
);
1444 state
= SCE_L_COMMAND
;
1450 case SCE_L_VERBATIM
:
1453 if (latexLastWordIs(match
, styler
, "\\end")) {
1455 if (latexIsTagValid(match
, lengthDoc
, styler
)) {
1456 if (latexLastWordIs(match
, styler
, "{verbatim}")) {
1457 styler
.ColourTo(i
-1, state
);
1458 state
= SCE_L_COMMAND
;
1462 } else if (chNext
== chVerbatimDelim
) {
1463 styler
.ColourTo(i
+1, state
);
1464 state
= SCE_L_DEFAULT
;
1465 chVerbatimDelim
= '\0';
1466 } else if (chVerbatimDelim
!= '\0' && (ch
== '\n' || ch
== '\r')) {
1467 styler
.ColourTo(i
, SCE_L_ERROR
);
1468 state
= SCE_L_DEFAULT
;
1469 chVerbatimDelim
= '\0';
1474 styler
.ColourTo(lengthDoc
-1, state
);
1477 static const char *const batchWordListDesc
[] = {
1478 "Internal Commands",
1479 "External Commands",
1483 static const char *const emptyWordListDesc
[] = {
1487 static void ColouriseNullDoc(unsigned int startPos
, int length
, int, WordList
*[],
1489 // Null language means all style bytes are 0 so just mark the end - no need to fill in.
1491 styler
.StartAt(startPos
+ length
- 1);
1492 styler
.StartSegment(startPos
+ length
- 1);
1493 styler
.ColourTo(startPos
+ length
- 1, 0);
1497 LexerModule
lmBatch(SCLEX_BATCH
, ColouriseBatchDoc
, "batch", 0, batchWordListDesc
);
1498 LexerModule
lmDiff(SCLEX_DIFF
, ColouriseDiffDoc
, "diff", FoldDiffDoc
, emptyWordListDesc
);
1499 LexerModule
lmPo(SCLEX_PO
, ColourisePoDoc
, "po", 0, emptyWordListDesc
);
1500 LexerModule
lmProps(SCLEX_PROPERTIES
, ColourisePropsDoc
, "props", FoldPropsDoc
, emptyWordListDesc
);
1501 LexerModule
lmMake(SCLEX_MAKEFILE
, ColouriseMakeDoc
, "makefile", 0, emptyWordListDesc
);
1502 LexerModule
lmErrorList(SCLEX_ERRORLIST
, ColouriseErrorListDoc
, "errorlist", 0, emptyWordListDesc
);
1503 LexerModule
lmLatex(SCLEX_LATEX
, ColouriseLatexDoc
, "latex", 0, emptyWordListDesc
);
1504 LexerModule
lmNull(SCLEX_NULL
, ColouriseNullDoc
, "null");