]>
Commit | Line | Data |
---|---|---|
1 | // Scintilla source code edit control | |
2 | /** @file LexOthers.cxx | |
3 | ** Lexers for batch files, diff results, properties files, make files and error lists. | |
4 | ** Also lexer for LaTeX documents. | |
5 | **/ | |
6 | // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> | |
7 | // The License.txt file describes the conditions under which this software may be distributed. | |
8 | ||
9 | #include <stdlib.h> | |
10 | #include <string.h> | |
11 | #include <stdio.h> | |
12 | #include <stdarg.h> | |
13 | #include <assert.h> | |
14 | #include <ctype.h> | |
15 | ||
16 | #include "ILexer.h" | |
17 | #include "Scintilla.h" | |
18 | #include "SciLexer.h" | |
19 | ||
20 | #include "WordList.h" | |
21 | #include "LexAccessor.h" | |
22 | #include "Accessor.h" | |
23 | #include "StyleContext.h" | |
24 | #include "CharacterSet.h" | |
25 | #include "LexerModule.h" | |
26 | ||
27 | #ifdef SCI_NAMESPACE | |
28 | using namespace Scintilla; | |
29 | #endif | |
30 | ||
31 | static bool strstart(const char *haystack, const char *needle) { | |
32 | return strncmp(haystack, needle, strlen(needle)) == 0; | |
33 | } | |
34 | ||
35 | static bool Is0To9(char ch) { | |
36 | return (ch >= '0') && (ch <= '9'); | |
37 | } | |
38 | ||
39 | static bool Is1To9(char ch) { | |
40 | return (ch >= '1') && (ch <= '9'); | |
41 | } | |
42 | ||
43 | static bool IsAlphabetic(int ch) { | |
44 | return isascii(ch) && isalpha(ch); | |
45 | } | |
46 | ||
47 | static inline bool AtEOL(Accessor &styler, unsigned int i) { | |
48 | return (styler[i] == '\n') || | |
49 | ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); | |
50 | } | |
51 | ||
52 | // Tests for BATCH Operators | |
53 | static bool IsBOperator(char ch) { | |
54 | return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || | |
55 | (ch == '|') || (ch == '?') || (ch == '*'); | |
56 | } | |
57 | ||
58 | // Tests for BATCH Separators | |
59 | static bool IsBSeparator(char ch) { | |
60 | return (ch == '\\') || (ch == '.') || (ch == ';') || | |
61 | (ch == '\"') || (ch == '\'') || (ch == '/'); | |
62 | } | |
63 | ||
64 | static void ColouriseBatchLine( | |
65 | char *lineBuffer, | |
66 | unsigned int lengthLine, | |
67 | unsigned int startLine, | |
68 | unsigned int endPos, | |
69 | WordList *keywordlists[], | |
70 | Accessor &styler) { | |
71 | ||
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) | |
79 | ||
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 | |
90 | ||
91 | // Skip initial spaces | |
92 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
93 | offset++; | |
94 | } | |
95 | // Colorize Default Text | |
96 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
97 | // Set External Command / Program Location | |
98 | cmdLoc = offset; | |
99 | ||
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); | |
105 | } else { | |
106 | // Colorize Real Label | |
107 | styler.ColourTo(endPos, SCE_BAT_LABEL); | |
108 | } | |
109 | return; | |
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); | |
118 | return; | |
119 | } | |
120 | ||
121 | // Check for Hide Command (@ECHO OFF/ON) | |
122 | if (lineBuffer[offset] == '@') { | |
123 | styler.ColourTo(startLine + offset, SCE_BAT_HIDE); | |
124 | offset++; | |
125 | } | |
126 | // Skip next spaces | |
127 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
128 | offset++; | |
129 | } | |
130 | ||
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); | |
136 | } | |
137 | // Copy word from Line Buffer into Word Buffer | |
138 | wbl = 0; | |
139 | for (; offset < lengthLine && wbl < 80 && | |
140 | !isspacechar(lineBuffer[offset]); wbl++, offset++) { | |
141 | wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset])); | |
142 | } | |
143 | wordBuffer[wbl] = '\0'; | |
144 | wbo = 0; | |
145 | ||
146 | // Check for Comment - return if found | |
147 | if (CompareCaseInsensitive(wordBuffer, "rem") == 0) { | |
148 | styler.ColourTo(endPos, SCE_BAT_COMMENT); | |
149 | return; | |
150 | } | |
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 | |
159 | offset -= (wbl - 1); | |
160 | // Colorize External Command / Program | |
161 | if (!keywords2) { | |
162 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
163 | } else if (keywords2.InList(wordBuffer)) { | |
164 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
165 | } else { | |
166 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
167 | } | |
168 | // Reset External Command / Program Location | |
169 | cmdLoc = offset; | |
170 | } else { | |
171 | // Reset Offset to re-process remainder of word | |
172 | offset -= (wbl - 1); | |
173 | // Colorize Default Text | |
174 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
175 | } | |
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; | |
185 | } | |
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 | |
190 | cmdLoc = offset; | |
191 | // Skip next spaces | |
192 | while ((cmdLoc < lengthLine) && | |
193 | (isspacechar(lineBuffer[cmdLoc]))) { | |
194 | cmdLoc++; | |
195 | } | |
196 | // Skip comparison | |
197 | while ((cmdLoc < lengthLine) && | |
198 | (!isspacechar(lineBuffer[cmdLoc]))) { | |
199 | cmdLoc++; | |
200 | } | |
201 | // Skip next spaces | |
202 | while ((cmdLoc < lengthLine) && | |
203 | (isspacechar(lineBuffer[cmdLoc]))) { | |
204 | cmdLoc++; | |
205 | } | |
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 | |
212 | cmdLoc = offset; | |
213 | // Skip next spaces | |
214 | while ((cmdLoc < lengthLine) && | |
215 | (isspacechar(lineBuffer[cmdLoc]))) { | |
216 | cmdLoc++; | |
217 | } | |
218 | } | |
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++) { | |
232 | wbo = 0; | |
233 | // Copy Keyword Length from Word Buffer into Special Keyword Buffer | |
234 | for (; wbo < keywordLength; wbo++) { | |
235 | sKeywordBuffer[wbo] = static_cast<char>(wordBuffer[wbo]); | |
236 | } | |
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; | |
246 | } | |
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); | |
251 | } | |
252 | } | |
253 | // Check for External Command / Program or Default Text | |
254 | if (!sKeywordFound) { | |
255 | wbo = 0; | |
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]))) { | |
264 | wbo++; | |
265 | } | |
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; | |
273 | } | |
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 | |
277 | cmdLoc = offset; | |
278 | // Skip next spaces | |
279 | while ((cmdLoc < lengthLine) && | |
280 | (isspacechar(lineBuffer[cmdLoc]))) { | |
281 | cmdLoc++; | |
282 | } | |
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]))) { | |
288 | cmdLoc++; | |
289 | } | |
290 | // Skip next spaces | |
291 | while ((cmdLoc < lengthLine) && | |
292 | (isspacechar(lineBuffer[cmdLoc]))) { | |
293 | cmdLoc++; | |
294 | } | |
295 | } | |
296 | } | |
297 | // Colorize External Command / Program | |
298 | if (!keywords2) { | |
299 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
300 | } else if (keywords2.InList(wordBuffer)) { | |
301 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
302 | } else { | |
303 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
304 | } | |
305 | // No need to Reset Offset | |
306 | // Check for Default Text | |
307 | } else { | |
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]))) { | |
314 | wbo++; | |
315 | } | |
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); | |
320 | } | |
321 | } | |
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); | |
326 | wbo++; | |
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]))) { | |
332 | wbo++; | |
333 | } | |
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); | |
340 | } | |
341 | // Colorize Argument | |
342 | styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER); | |
343 | // Reset Offset to re-process remainder of word | |
344 | offset -= (wbl - 2); | |
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); | |
351 | } | |
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] == '%')) { | |
359 | wbo++; | |
360 | // Check for External Command / Program | |
361 | if (cmdLoc == offset - wbl) { | |
362 | cmdLoc = offset - (wbl - wbo); | |
363 | } | |
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) | |
369 | } else if ( | |
370 | (wbl > 2) && | |
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); | |
378 | } | |
379 | // Colorize Local Variable | |
380 | styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER); | |
381 | // Reset Offset to re-process remainder of word | |
382 | offset -= (wbl - 3); | |
383 | } | |
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); | |
388 | wbo++; | |
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]))) { | |
394 | wbo++; | |
395 | } | |
396 | if (wordBuffer[wbo] == '!') { | |
397 | wbo++; | |
398 | // Check for External Command / Program | |
399 | if (cmdLoc == offset - wbl) { | |
400 | cmdLoc = offset - (wbl - wbo); | |
401 | } | |
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); | |
406 | } | |
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 | |
414 | cmdLoc = offset; | |
415 | // Skip next spaces | |
416 | while ((cmdLoc < lengthLine) && | |
417 | (isspacechar(lineBuffer[cmdLoc]))) { | |
418 | cmdLoc++; | |
419 | } | |
420 | // Colorize Comparison Operator | |
421 | styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR); | |
422 | // Reset Offset to re-process remainder of word | |
423 | offset -= (wbl - 2); | |
424 | // Check for Pipe Operator | |
425 | } else if (wordBuffer[0] == '|') { | |
426 | // Reset External Command / Program Location | |
427 | cmdLoc = offset - wbl + 1; | |
428 | // Skip next spaces | |
429 | while ((cmdLoc < lengthLine) && | |
430 | (isspacechar(lineBuffer[cmdLoc]))) { | |
431 | cmdLoc++; | |
432 | } | |
433 | // Colorize Pipe Operator | |
434 | styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); | |
435 | // Reset Offset to re-process remainder of word | |
436 | offset -= (wbl - 1); | |
437 | // Check for Other Operator | |
438 | } else { | |
439 | // Check for > Operator | |
440 | if (wordBuffer[0] == '>') { | |
441 | // Turn Keyword and External Command / Program checking back on | |
442 | continueProcessing = true; | |
443 | } | |
444 | // Colorize Other Operator | |
445 | styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); | |
446 | // Reset Offset to re-process remainder of word | |
447 | offset -= (wbl - 1); | |
448 | } | |
449 | // Check for Default Text | |
450 | } else { | |
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]))) { | |
457 | wbo++; | |
458 | } | |
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); | |
463 | } | |
464 | // Skip next spaces - nothing happens if Offset was Reset | |
465 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
466 | offset++; | |
467 | } | |
468 | } | |
469 | // Colorize Default Text for remainder of line - currently not lexed | |
470 | styler.ColourTo(endPos, SCE_BAT_DEFAULT); | |
471 | } | |
472 | ||
473 | static void ColouriseBatchDoc( | |
474 | unsigned int startPos, | |
475 | int length, | |
476 | int /*initStyle*/, | |
477 | WordList *keywordlists[], | |
478 | Accessor &styler) { | |
479 | ||
480 | char lineBuffer[1024]; | |
481 | ||
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); | |
492 | linePos = 0; | |
493 | startLine = i + 1; | |
494 | } | |
495 | } | |
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); | |
500 | } | |
501 | } | |
502 | ||
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. | |
506 | ||
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); | |
522 | else | |
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); | |
529 | else | |
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); | |
541 | else | |
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); | |
557 | } else { | |
558 | styler.ColourTo(endLine, SCE_DIFF_DEFAULT); | |
559 | } | |
560 | } | |
561 | ||
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; | |
571 | } | |
572 | ColouriseDiffLine(lineBuffer, i, styler); | |
573 | linePos = 0; | |
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; | |
578 | } | |
579 | } | |
580 | if (linePos > 0) { // Last line does not have ending characters | |
581 | if (linePos < DIFF_BUFFER_START_SIZE) { | |
582 | lineBuffer[linePos] = 0; | |
583 | } | |
584 | ColouriseDiffLine(lineBuffer, startPos + length - 1, styler); | |
585 | } | |
586 | } | |
587 | ||
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; | |
592 | int nextLevel; | |
593 | ||
594 | do { | |
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; | |
604 | else | |
605 | nextLevel = prevLevel; | |
606 | ||
607 | if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel)) | |
608 | styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG); | |
609 | ||
610 | styler.SetLevel(curLine, nextLevel); | |
611 | prevLevel = nextLevel; | |
612 | ||
613 | curLineStart = styler.LineStart(++curLine); | |
614 | } while (static_cast<int>(startPos) + length > curLineStart); | |
615 | } | |
616 | ||
617 | static void ColourisePoLine( | |
618 | char *lineBuffer, | |
619 | unsigned int lengthLine, | |
620 | unsigned int startLine, | |
621 | unsigned int endPos, | |
622 | Accessor &styler) { | |
623 | ||
624 | unsigned int i = 0; | |
625 | static unsigned int state = SCE_PO_DEFAULT; | |
626 | unsigned int state_start = SCE_PO_DEFAULT; | |
627 | ||
628 | while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces | |
629 | i++; | |
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); | |
636 | else | |
637 | styler.ColourTo(endPos, SCE_PO_COMMENT); | |
638 | } else { | |
639 | if (lineBuffer[0] == '"') { | |
640 | // line continuation, use previous style | |
641 | styler.ColourTo(endPos, state); | |
642 | return; | |
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; | |
653 | } | |
654 | if (state_start != SCE_PO_DEFAULT) { | |
655 | // find the next space | |
656 | while ((i < lengthLine) && ! isspacechar(lineBuffer[i])) | |
657 | i++; | |
658 | styler.ColourTo(startLine + i - 1, state_start); | |
659 | styler.ColourTo(startLine + i, SCE_PO_DEFAULT); | |
660 | styler.ColourTo(endPos, state); | |
661 | } | |
662 | } | |
663 | } else { | |
664 | styler.ColourTo(endPos, SCE_PO_DEFAULT); | |
665 | } | |
666 | } | |
667 | ||
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); | |
680 | linePos = 0; | |
681 | startLine = i + 1; | |
682 | } | |
683 | } | |
684 | if (linePos > 0) { // Last line does not have ending characters | |
685 | ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); | |
686 | } | |
687 | } | |
688 | ||
689 | static inline bool isassignchar(unsigned char ch) { | |
690 | return (ch == '=') || (ch == ':'); | |
691 | } | |
692 | ||
693 | static void ColourisePropsLine( | |
694 | char *lineBuffer, | |
695 | unsigned int lengthLine, | |
696 | unsigned int startLine, | |
697 | unsigned int endPos, | |
698 | Accessor &styler, | |
699 | bool allowInitialSpaces) { | |
700 | ||
701 | unsigned int i = 0; | |
702 | if (allowInitialSpaces) { | |
703 | while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces | |
704 | i++; | |
705 | } else { | |
706 | if (isspacechar(lineBuffer[i])) // don't allow initial spaces | |
707 | i = lengthLine; | |
708 | } | |
709 | ||
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); | |
720 | } else { | |
721 | // Search for the '=' character | |
722 | while ((i < lengthLine) && !isassignchar(lineBuffer[i])) | |
723 | 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); | |
728 | } else { | |
729 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); | |
730 | } | |
731 | } | |
732 | } else { | |
733 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); | |
734 | } | |
735 | } | |
736 | ||
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; | |
743 | ||
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; | |
749 | ||
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); | |
756 | linePos = 0; | |
757 | startLine = i + 1; | |
758 | } | |
759 | } | |
760 | if (linePos > 0) { // Last line does not have ending characters | |
761 | ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler, allowInitialSpaces); | |
762 | } | |
763 | } | |
764 | ||
765 | // adaption by ksc, using the "} else {" trick of 1.53 | |
766 | // 030721 | |
767 | static void FoldPropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
768 | bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; | |
769 | ||
770 | unsigned int endPos = startPos + length; | |
771 | int visibleChars = 0; | |
772 | int lineCurrent = styler.GetLine(startPos); | |
773 | ||
774 | char chNext = styler[startPos]; | |
775 | int styleNext = styler.StyleAt(startPos); | |
776 | bool headerPoint = false; | |
777 | int lev; | |
778 | ||
779 | for (unsigned int i = startPos; i < endPos; i++) { | |
780 | char ch = chNext; | |
781 | chNext = styler[i+1]; | |
782 | ||
783 | int style = styleNext; | |
784 | styleNext = styler.StyleAt(i + 1); | |
785 | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); | |
786 | ||
787 | if (style == SCE_PROPS_SECTION) { | |
788 | headerPoint = true; | |
789 | } | |
790 | ||
791 | if (atEOL) { | |
792 | lev = SC_FOLDLEVELBASE; | |
793 | ||
794 | if (lineCurrent > 0) { | |
795 | int levelPrevious = styler.LevelAt(lineCurrent - 1); | |
796 | ||
797 | if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { | |
798 | lev = SC_FOLDLEVELBASE + 1; | |
799 | } else { | |
800 | lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; | |
801 | } | |
802 | } | |
803 | ||
804 | if (headerPoint) { | |
805 | lev = SC_FOLDLEVELBASE; | |
806 | } | |
807 | if (visibleChars == 0 && foldCompact) | |
808 | lev |= SC_FOLDLEVELWHITEFLAG; | |
809 | ||
810 | if (headerPoint) { | |
811 | lev |= SC_FOLDLEVELHEADERFLAG; | |
812 | } | |
813 | if (lev != styler.LevelAt(lineCurrent)) { | |
814 | styler.SetLevel(lineCurrent, lev); | |
815 | } | |
816 | ||
817 | lineCurrent++; | |
818 | visibleChars = 0; | |
819 | headerPoint = false; | |
820 | } | |
821 | if (!isspacechar(ch)) | |
822 | visibleChars++; | |
823 | } | |
824 | ||
825 | if (lineCurrent > 0) { | |
826 | int levelPrevious = styler.LevelAt(lineCurrent - 1); | |
827 | if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { | |
828 | lev = SC_FOLDLEVELBASE + 1; | |
829 | } else { | |
830 | lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; | |
831 | } | |
832 | } else { | |
833 | lev = SC_FOLDLEVELBASE; | |
834 | } | |
835 | int flagsNext = styler.LevelAt(lineCurrent); | |
836 | styler.SetLevel(lineCurrent, lev | (flagsNext & ~SC_FOLDLEVELNUMBERMASK)); | |
837 | } | |
838 | ||
839 | static void ColouriseMakeLine( | |
840 | char *lineBuffer, | |
841 | unsigned int lengthLine, | |
842 | unsigned int startLine, | |
843 | unsigned int endPos, | |
844 | Accessor &styler) { | |
845 | ||
846 | unsigned int i = 0; | |
847 | int lastNonSpace = -1; | |
848 | unsigned int state = SCE_MAKE_DEFAULT; | |
849 | bool bSpecial = false; | |
850 | ||
851 | // check for a tab character in column 0 indicating a command | |
852 | bool bCommand = false; | |
853 | if ((lengthLine > 0) && (lineBuffer[0] == '\t')) | |
854 | bCommand = true; | |
855 | ||
856 | // Skip initial spaces | |
857 | while ((i < lengthLine) && isspacechar(lineBuffer[i])) { | |
858 | i++; | |
859 | } | |
860 | if (lineBuffer[i] == '#') { // Comment | |
861 | styler.ColourTo(endPos, SCE_MAKE_COMMENT); | |
862 | return; | |
863 | } | |
864 | if (lineBuffer[i] == '!') { // Special directive | |
865 | styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR); | |
866 | return; | |
867 | } | |
868 | int varCount = 0; | |
869 | while (i < lengthLine) { | |
870 | if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') { | |
871 | styler.ColourTo(startLine + i - 1, state); | |
872 | state = SCE_MAKE_IDENTIFIER; | |
873 | varCount++; | |
874 | } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') { | |
875 | if (--varCount == 0) { | |
876 | styler.ColourTo(startLine + i, state); | |
877 | state = SCE_MAKE_DEFAULT; | |
878 | } | |
879 | } | |
880 | ||
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); | |
890 | } else { | |
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); | |
897 | } | |
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; | |
907 | } | |
908 | } | |
909 | if (!isspacechar(lineBuffer[i])) { | |
910 | lastNonSpace = i; | |
911 | } | |
912 | i++; | |
913 | } | |
914 | if (state == SCE_MAKE_IDENTIFIER) { | |
915 | styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended | |
916 | } else { | |
917 | styler.ColourTo(endPos, SCE_MAKE_DEFAULT); | |
918 | } | |
919 | } | |
920 | ||
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); | |
933 | linePos = 0; | |
934 | startLine = i + 1; | |
935 | } | |
936 | } | |
937 | if (linePos > 0) { // Last line does not have ending characters | |
938 | ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); | |
939 | } | |
940 | } | |
941 | ||
942 | static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine, int &startValue) { | |
943 | if (lineBuffer[0] == '>') { | |
944 | // Command or return status | |
945 | return SCE_ERR_CMD; | |
946 | } else if (lineBuffer[0] == '<') { | |
947 | // Diff removal. | |
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; | |
954 | } else { | |
955 | return SCE_ERR_DIFF_ADDITION; | |
956 | } | |
957 | } else if (lineBuffer[0] == '-') { | |
958 | if (strstart(lineBuffer, "--- ")) { | |
959 | return SCE_ERR_DIFF_MESSAGE; | |
960 | } else { | |
961 | return SCE_ERR_DIFF_DELETION; | |
962 | } | |
963 | } else if (strstart(lineBuffer, "cf90-")) { | |
964 | // Absoft Pro Fortran 90/95 v8.2 error and/or warning message | |
965 | return SCE_ERR_ABSF; | |
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 ")) { | |
972 | return SCE_ERR_PHP; | |
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 | |
979 | return SCE_ERR_IFC; | |
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 | |
991 | return SCE_ERR_LUA; | |
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 | |
998 | return SCE_ERR_PERL; | |
999 | } else if ((memcmp(lineBuffer, " at ", 6) == 0) && | |
1000 | strstr(lineBuffer, ":line ")) { | |
1001 | // A .NET traceback | |
1002 | return SCE_ERR_NET; | |
1003 | } else if (strstart(lineBuffer, "Line ") && | |
1004 | strstr(lineBuffer, ", file ")) { | |
1005 | // Essential Lahey Fortran error message | |
1006 | return SCE_ERR_ELF; | |
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; | |
1016 | } else { | |
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; | |
1028 | enum { stInitial, | |
1029 | stGccStart, stGccDigit, stGccColumn, stGcc, | |
1030 | stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet, | |
1031 | stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags, | |
1032 | stUnrecognized | |
1033 | } state = stInitial; | |
1034 | for (unsigned int i = 0; i < lengthLine; i++) { | |
1035 | char ch = lineBuffer[i]; | |
1036 | char chNext = ' '; | |
1037 | if ((i + 1) < lengthLine) | |
1038 | chNext = lineBuffer[i + 1]; | |
1039 | if (state == stInitial) { | |
1040 | if (ch == ':') { | |
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 ':'. | |
1045 | state = stGccStart; | |
1046 | } else if (chNext == ' ') { // indicates a Lua 5.1 error message | |
1047 | initialColonPart = true; | |
1048 | } | |
1049 | } else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) { | |
1050 | // May be Microsoft | |
1051 | // Check against '0' often removes phone numbers | |
1052 | state = stMsStart; | |
1053 | } else if ((ch == '\t') && (!initialTab)) { | |
1054 | // May be CTags | |
1055 | state = stCtagsStart; | |
1056 | } | |
1057 | } else if (state == stGccStart) { // <filename>: | |
1058 | state = Is1To9(ch) ? stGccDigit : stUnrecognized; | |
1059 | } else if (state == stGccDigit) { // <filename>:<line> | |
1060 | if (ch == ':') { | |
1061 | state = stGccColumn; // :9.*: is GCC | |
1062 | startValue = i + 1; | |
1063 | } else if (!Is0To9(ch)) { | |
1064 | state = stUnrecognized; | |
1065 | } | |
1066 | } else if (state == stGccColumn) { // <filename>:<line>:<column> | |
1067 | if (!Is0To9(ch)) { | |
1068 | state = stGcc; | |
1069 | if (ch == ':') | |
1070 | startValue = i + 1; | |
1071 | break; | |
1072 | } | |
1073 | } else if (state == stMsStart) { // <filename>( | |
1074 | state = Is0To9(ch) ? stMsDigit : stUnrecognized; | |
1075 | } else if (state == stMsDigit) { // <filename>(<line> | |
1076 | if (ch == ',') { | |
1077 | state = stMsDigitComma; | |
1078 | } else if (ch == ')') { | |
1079 | state = stMsBracket; | |
1080 | } else if ((ch != ' ') && !Is0To9(ch)) { | |
1081 | state = stUnrecognized; | |
1082 | } | |
1083 | } else if (state == stMsBracket) { // <filename>(<line>) | |
1084 | if ((ch == ' ') && (chNext == ':')) { | |
1085 | state = stMsVc; | |
1086 | } else if ((ch == ':' && chNext == ' ') || (ch == ' ')) { | |
1087 | // Possibly Delphi.. don't test against chNext as it's one of the strings below. | |
1088 | char word[512]; | |
1089 | unsigned int j, chPos; | |
1090 | unsigned numstep; | |
1091 | chPos = 0; | |
1092 | if (ch == ' ') | |
1093 | numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i. | |
1094 | else | |
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]; | |
1098 | word[chPos] = 0; | |
1099 | if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") || | |
1100 | !CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") || | |
1101 | !CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) { | |
1102 | state = stMsVc; | |
1103 | } else | |
1104 | state = stUnrecognized; | |
1105 | } else { | |
1106 | state = stUnrecognized; | |
1107 | } | |
1108 | } else if (state == stMsDigitComma) { // <filename>(<line>, | |
1109 | if (ch == ')') { | |
1110 | state = stMsDotNet; | |
1111 | break; | |
1112 | } else if ((ch != ' ') && !Is0To9(ch)) { | |
1113 | state = stUnrecognized; | |
1114 | } | |
1115 | } else if (state == stCtagsStart) { | |
1116 | if ((lineBuffer[i - 1] == '\t') && | |
1117 | ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) { | |
1118 | state = stCtags; | |
1119 | break; | |
1120 | } else if ((ch == '/') && (lineBuffer[i + 1] == '^')) { | |
1121 | state = stCtagsStartString; | |
1122 | } | |
1123 | } else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) { | |
1124 | state = stCtagsStringDollar; | |
1125 | break; | |
1126 | } | |
1127 | } | |
1128 | if (state == stGcc) { | |
1129 | return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC; | |
1130 | } else if ((state == stMsVc) || (state == stMsDotNet)) { | |
1131 | return SCE_ERR_MS; | |
1132 | } else if ((state == stCtagsStringDollar) || (state == stCtags)) { | |
1133 | return SCE_ERR_CTAG; | |
1134 | } else { | |
1135 | return SCE_ERR_DEFAULT; | |
1136 | } | |
1137 | } | |
1138 | } | |
1139 | ||
1140 | static void ColouriseErrorListLine( | |
1141 | char *lineBuffer, | |
1142 | unsigned int lengthLine, | |
1143 | unsigned int endPos, | |
1144 | Accessor &styler, | |
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); | |
1151 | } else { | |
1152 | styler.ColourTo(endPos, style); | |
1153 | } | |
1154 | } | |
1155 | ||
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; | |
1161 | ||
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); | |
1174 | linePos = 0; | |
1175 | } | |
1176 | } | |
1177 | if (linePos > 0) { // Last line does not have ending characters | |
1178 | ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler, valueSeparate); | |
1179 | } | |
1180 | } | |
1181 | ||
1182 | static bool latexIsSpecial(int ch) { | |
1183 | return (ch == '#') || (ch == '$') || (ch == '%') || (ch == '&') || (ch == '_') || | |
1184 | (ch == '{') || (ch == '}') || (ch == ' '); | |
1185 | } | |
1186 | ||
1187 | static bool latexIsBlank(int ch) { | |
1188 | return (ch == ' ') || (ch == '\t'); | |
1189 | } | |
1190 | ||
1191 | static bool latexIsBlankAndNL(int ch) { | |
1192 | return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'); | |
1193 | } | |
1194 | ||
1195 | static bool latexIsLetter(int ch) { | |
1196 | return isascii(ch) && isalpha(ch); | |
1197 | } | |
1198 | ||
1199 | static bool latexIsTagValid(int &i, int l, Accessor &styler) { | |
1200 | while (i < l) { | |
1201 | if (styler.SafeGetCharAt(i) == '{') { | |
1202 | while (i < l) { | |
1203 | i++; | |
1204 | if (styler.SafeGetCharAt(i) == '}') { | |
1205 | return true; | |
1206 | } else if (!latexIsLetter(styler.SafeGetCharAt(i)) && | |
1207 | styler.SafeGetCharAt(i)!='*') { | |
1208 | return false; | |
1209 | } | |
1210 | } | |
1211 | } else if (!latexIsBlank(styler.SafeGetCharAt(i))) { | |
1212 | return false; | |
1213 | } | |
1214 | i++; | |
1215 | } | |
1216 | return false; | |
1217 | } | |
1218 | ||
1219 | static bool latexNextNotBlankIs(int i, int l, Accessor &styler, char needle) { | |
1220 | char ch; | |
1221 | while (i < l) { | |
1222 | ch = styler.SafeGetCharAt(i); | |
1223 | if (!latexIsBlankAndNL(ch) && ch != '*') { | |
1224 | if (ch == needle) | |
1225 | return true; | |
1226 | else | |
1227 | return false; | |
1228 | } | |
1229 | i++; | |
1230 | } | |
1231 | return false; | |
1232 | } | |
1233 | ||
1234 | static bool latexLastWordIs(int start, Accessor &styler, const char *needle) { | |
1235 | unsigned int i = 0; | |
1236 | unsigned int l = static_cast<unsigned int>(strlen(needle)); | |
1237 | int ini = start-l+1; | |
1238 | char s[32]; | |
1239 | ||
1240 | while (i < l && i < 32) { | |
1241 | s[i] = styler.SafeGetCharAt(ini + i); | |
1242 | i++; | |
1243 | } | |
1244 | s[i] = '\0'; | |
1245 | ||
1246 | return (strcmp(s, needle) == 0); | |
1247 | } | |
1248 | ||
1249 | static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle, | |
1250 | WordList *[], Accessor &styler) { | |
1251 | ||
1252 | styler.StartAt(startPos); | |
1253 | ||
1254 | int state = initStyle; | |
1255 | char chNext = styler.SafeGetCharAt(startPos); | |
1256 | styler.StartSegment(startPos); | |
1257 | int lengthDoc = startPos + length; | |
1258 | char chVerbatimDelim = '\0'; | |
1259 | ||
1260 | for (int i = startPos; i < lengthDoc; i++) { | |
1261 | char ch = chNext; | |
1262 | chNext = styler.SafeGetCharAt(i + 1); | |
1263 | ||
1264 | if (styler.IsLeadByte(ch)) { | |
1265 | i++; | |
1266 | chNext = styler.SafeGetCharAt(i + 1); | |
1267 | continue; | |
1268 | } | |
1269 | ||
1270 | switch (state) { | |
1271 | case SCE_L_DEFAULT : | |
1272 | switch (ch) { | |
1273 | case '\\' : | |
1274 | styler.ColourTo(i - 1, state); | |
1275 | if (latexIsSpecial(chNext)) { | |
1276 | state = SCE_L_SPECIAL; | |
1277 | } else { | |
1278 | if (latexIsLetter(chNext)) { | |
1279 | state = SCE_L_COMMAND; | |
1280 | } else { | |
1281 | if (chNext == '(' || chNext == '[') { | |
1282 | styler.ColourTo(i-1, state); | |
1283 | styler.ColourTo(i+1, SCE_L_SHORTCMD); | |
1284 | state = SCE_L_MATH; | |
1285 | if (chNext == '[') | |
1286 | state = SCE_L_MATH2; | |
1287 | i++; | |
1288 | chNext = styler.SafeGetCharAt(i+1); | |
1289 | } else { | |
1290 | state = SCE_L_SHORTCMD; | |
1291 | } | |
1292 | } | |
1293 | } | |
1294 | break; | |
1295 | case '$' : | |
1296 | styler.ColourTo(i - 1, state); | |
1297 | state = SCE_L_MATH; | |
1298 | if (chNext == '$') { | |
1299 | state = SCE_L_MATH2; | |
1300 | i++; | |
1301 | chNext = styler.SafeGetCharAt(i + 1); | |
1302 | } | |
1303 | break; | |
1304 | case '%' : | |
1305 | styler.ColourTo(i - 1, state); | |
1306 | state = SCE_L_COMMENT; | |
1307 | break; | |
1308 | } | |
1309 | break; | |
1310 | case SCE_L_ERROR: | |
1311 | styler.ColourTo(i-1, state); | |
1312 | state = SCE_L_DEFAULT; | |
1313 | break; | |
1314 | case SCE_L_SPECIAL: | |
1315 | case SCE_L_SHORTCMD: | |
1316 | styler.ColourTo(i, state); | |
1317 | state = SCE_L_DEFAULT; | |
1318 | break; | |
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")) { | |
1326 | state = SCE_L_TAG; | |
1327 | } else if (latexLastWordIs(i, styler, "\\end")) { | |
1328 | state = SCE_L_TAG2; | |
1329 | } else if (latexLastWordIs(i, styler, "\\verb") && | |
1330 | chNext != '*' && chNext != ' ') { | |
1331 | chVerbatimDelim = chNext; | |
1332 | state = SCE_L_VERBATIM; | |
1333 | } | |
1334 | } | |
1335 | break; | |
1336 | case SCE_L_CMDOPT : | |
1337 | if (ch == ']') { | |
1338 | styler.ColourTo(i, state); | |
1339 | state = SCE_L_DEFAULT; | |
1340 | } | |
1341 | break; | |
1342 | case SCE_L_TAG : | |
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}")) { | |
1351 | state = SCE_L_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; | |
1356 | } | |
1357 | } else { | |
1358 | state = SCE_L_ERROR; | |
1359 | styler.ColourTo(i, state); | |
1360 | state = SCE_L_DEFAULT; | |
1361 | } | |
1362 | chNext = styler.SafeGetCharAt(i+1); | |
1363 | break; | |
1364 | case SCE_L_TAG2 : | |
1365 | if (latexIsTagValid(i, lengthDoc, styler)) { | |
1366 | styler.ColourTo(i, state); | |
1367 | state = SCE_L_DEFAULT; | |
1368 | } else { | |
1369 | state = SCE_L_ERROR; | |
1370 | } | |
1371 | chNext = styler.SafeGetCharAt(i+1); | |
1372 | break; | |
1373 | case SCE_L_MATH : | |
1374 | if (ch == '$') { | |
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); | |
1380 | i++; | |
1381 | chNext = styler.SafeGetCharAt(i+1); | |
1382 | state = SCE_L_DEFAULT; | |
1383 | } else if (ch == '\\') { | |
1384 | int match = i + 3; | |
1385 | if (latexLastWordIs(match, styler, "\\end")) { | |
1386 | match++; | |
1387 | if (latexIsTagValid(match, lengthDoc, styler)) { | |
1388 | if (latexLastWordIs(match, styler, "{math}")) { | |
1389 | styler.ColourTo(i-1, state); | |
1390 | state = SCE_L_COMMAND; | |
1391 | } | |
1392 | } | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | break; | |
1397 | case SCE_L_MATH2 : | |
1398 | if (ch == '$') { | |
1399 | if (chNext == '$') { | |
1400 | i++; | |
1401 | chNext = styler.SafeGetCharAt(i + 1); | |
1402 | styler.ColourTo(i, state); | |
1403 | state = SCE_L_DEFAULT; | |
1404 | } else { | |
1405 | styler.ColourTo(i, SCE_L_ERROR); | |
1406 | state = SCE_L_DEFAULT; | |
1407 | } | |
1408 | } else if (ch == '\\' && chNext == ']') { | |
1409 | styler.ColourTo(i-1, state); | |
1410 | styler.ColourTo(i+1, SCE_L_SHORTCMD); | |
1411 | i++; | |
1412 | chNext = styler.SafeGetCharAt(i+1); | |
1413 | state = SCE_L_DEFAULT; | |
1414 | } else if (ch == '\\') { | |
1415 | int match = i + 3; | |
1416 | if (latexLastWordIs(match, styler, "\\end")) { | |
1417 | match++; | |
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; | |
1425 | } | |
1426 | } | |
1427 | } | |
1428 | } | |
1429 | break; | |
1430 | case SCE_L_COMMENT : | |
1431 | if (ch == '\r' || ch == '\n') { | |
1432 | styler.ColourTo(i - 1, state); | |
1433 | state = SCE_L_DEFAULT; | |
1434 | } | |
1435 | break; | |
1436 | case SCE_L_COMMENT2 : | |
1437 | if (ch == '\\') { | |
1438 | int match = i + 3; | |
1439 | if (latexLastWordIs(match, styler, "\\end")) { | |
1440 | match++; | |
1441 | if (latexIsTagValid(match, lengthDoc, styler)) { | |
1442 | if (latexLastWordIs(match, styler, "{comment}")) { | |
1443 | styler.ColourTo(i-1, state); | |
1444 | state = SCE_L_COMMAND; | |
1445 | } | |
1446 | } | |
1447 | } | |
1448 | } | |
1449 | break; | |
1450 | case SCE_L_VERBATIM : | |
1451 | if (ch == '\\') { | |
1452 | int match = i + 3; | |
1453 | if (latexLastWordIs(match, styler, "\\end")) { | |
1454 | match++; | |
1455 | if (latexIsTagValid(match, lengthDoc, styler)) { | |
1456 | if (latexLastWordIs(match, styler, "{verbatim}")) { | |
1457 | styler.ColourTo(i-1, state); | |
1458 | state = SCE_L_COMMAND; | |
1459 | } | |
1460 | } | |
1461 | } | |
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'; | |
1470 | } | |
1471 | break; | |
1472 | } | |
1473 | } | |
1474 | styler.ColourTo(lengthDoc-1, state); | |
1475 | } | |
1476 | ||
1477 | static const char *const batchWordListDesc[] = { | |
1478 | "Internal Commands", | |
1479 | "External Commands", | |
1480 | 0 | |
1481 | }; | |
1482 | ||
1483 | static const char *const emptyWordListDesc[] = { | |
1484 | 0 | |
1485 | }; | |
1486 | ||
1487 | static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[], | |
1488 | Accessor &styler) { | |
1489 | // Null language means all style bytes are 0 so just mark the end - no need to fill in. | |
1490 | if (length > 0) { | |
1491 | styler.StartAt(startPos + length - 1); | |
1492 | styler.StartSegment(startPos + length - 1); | |
1493 | styler.ColourTo(startPos + length - 1, 0); | |
1494 | } | |
1495 | } | |
1496 | ||
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"); |