]>
Commit | Line | Data |
---|---|---|
65ec6247 RD |
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> | |
f6bcfd97 BP |
7 | // The License.txt file describes the conditions under which this software may be distributed. |
8 | ||
65ec6247 RD |
9 | #include <stdlib.h> |
10 | #include <string.h> | |
11 | #include <ctype.h> | |
12 | #include <stdio.h> | |
13 | #include <stdarg.h> | |
f6bcfd97 BP |
14 | |
15 | #include "Platform.h" | |
16 | ||
17 | #include "PropSet.h" | |
18 | #include "Accessor.h" | |
19 | #include "KeyWords.h" | |
20 | #include "Scintilla.h" | |
21 | #include "SciLexer.h" | |
22 | ||
9e730a78 RD |
23 | static bool Is0To9(char ch) { |
24 | return (ch >= '0') && (ch <= '9'); | |
25 | } | |
26 | ||
27 | static bool Is1To9(char ch) { | |
28 | return (ch >= '1') && (ch <= '9'); | |
29 | } | |
30 | ||
1a2fb4cd RD |
31 | static inline bool AtEOL(Accessor &styler, unsigned int i) { |
32 | return (styler[i] == '\n') || | |
1e9bafca RD |
33 | ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); |
34 | } | |
35 | ||
36 | // Tests for BATCH Operators | |
37 | static bool IsBOperator(char ch) { | |
38 | return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || | |
39 | (ch == '|') || (ch == '?') || (ch == '*'); | |
40 | } | |
41 | ||
42 | // Tests for BATCH Separators | |
43 | static bool IsBSeparator(char ch) { | |
44 | return (ch == ':') || (ch == '\\') || (ch == '.') || (ch == ';') || | |
45 | (ch == '\"') || (ch == '\'') || (ch == '/') || (ch == ')'); | |
1a2fb4cd RD |
46 | } |
47 | ||
65ec6247 RD |
48 | static void ColouriseBatchLine( |
49 | char *lineBuffer, | |
50 | unsigned int lengthLine, | |
51 | unsigned int startLine, | |
52 | unsigned int endPos, | |
53 | WordList &keywords, | |
54 | Accessor &styler) { | |
55 | ||
1e9bafca RD |
56 | unsigned int offset = 0; // Line Buffer Offset |
57 | unsigned int enVarEnd; // Environment Variable End point | |
58 | unsigned int cmdLoc; // External Command / Program Location | |
59 | char wordBuffer[81]; // Word Buffer - large to catch long paths | |
60 | unsigned int wbl; // Word Buffer Length | |
61 | unsigned int wbo; // Word Buffer Offset - also Special Keyword Buffer Length | |
62 | bool forFound = false; // No Local Variable without FOR statement | |
63 | // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords | |
64 | // Toggling Regular Keyword Checking off improves readability | |
65 | // Other Regular Keywords and External Commands / Programs might also benefit from toggling | |
66 | // Need a more robust algorithm to properly toggle Regular Keyword Checking | |
67 | bool continueProcessing = true; // Used to toggle Regular Keyword Checking | |
68 | // Special Keywords are those that allow certain characters without whitespace after the command | |
69 | // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path= | |
70 | // Special Keyword Buffer used to determine if the first n characters is a Keyword | |
71 | char sKeywordBuffer[10]; // Special Keyword Buffer | |
72 | bool sKeywordFound; // Exit Special Keyword for-loop if found | |
65ec6247 | 73 | |
1e9bafca RD |
74 | // Skip initial spaces |
75 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
76 | offset++; | |
65ec6247 | 77 | } |
1e9bafca RD |
78 | // Colorize Default Text |
79 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
80 | // Set External Command / Program Location | |
81 | cmdLoc = offset; | |
82 | ||
83 | // Check for Fake Label (Comment) or Real Label - return if found | |
84 | if (lineBuffer[offset] == ':') { | |
85 | if (lineBuffer[offset + 1] == ':') { | |
86 | // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm | |
65ec6247 | 87 | styler.ColourTo(endPos, SCE_BAT_COMMENT); |
1e9bafca RD |
88 | } else { |
89 | // Colorize Real Label | |
65ec6247 RD |
90 | styler.ColourTo(endPos, SCE_BAT_LABEL); |
91 | } | |
1e9bafca RD |
92 | return; |
93 | // Check for Drive Change (Drive Change is internal command) - return if found | |
94 | } else if ((isalpha(lineBuffer[offset])) && | |
95 | (lineBuffer[offset + 1] == ':') && | |
96 | ((isspacechar(lineBuffer[offset + 2])) || | |
97 | (((lineBuffer[offset + 2] == '\\')) && | |
98 | (isspacechar(lineBuffer[offset + 3]))))) { | |
99 | // Colorize Regular Keyword | |
100 | styler.ColourTo(endPos, SCE_BAT_WORD); | |
101 | return; | |
102 | } | |
103 | ||
104 | // Check for Hide Command (@ECHO OFF/ON) | |
105 | if (lineBuffer[offset] == '@') { | |
106 | styler.ColourTo(startLine + offset, SCE_BAT_HIDE); | |
107 | offset++; | |
108 | // Check for Argument (%n) or Environment Variable (%x...%) | |
109 | } else if (lineBuffer[offset] == '%') { | |
110 | enVarEnd = offset + 1; | |
111 | // Search end of word for second % (can be a long path) | |
112 | while ((enVarEnd < lengthLine) && | |
113 | (!isspacechar(lineBuffer[enVarEnd])) && | |
114 | (lineBuffer[enVarEnd] != '%') && | |
115 | (!IsBOperator(lineBuffer[enVarEnd])) && | |
116 | (!IsBSeparator(lineBuffer[enVarEnd]))) { | |
117 | enVarEnd++; | |
118 | } | |
119 | // Check for Argument (%n) | |
120 | if ((Is0To9(lineBuffer[offset + 1])) && | |
121 | (lineBuffer[enVarEnd] != '%')) { | |
122 | // Colorize Argument | |
123 | styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER); | |
124 | offset += 2; | |
125 | // Check for External Command / Program | |
126 | if (!isspacechar(lineBuffer[offset])) { | |
127 | cmdLoc = offset; | |
128 | } | |
129 | // Check for Environment Variable (%x...%) | |
130 | } else if ((lineBuffer[offset + 1] != '%') && | |
131 | (lineBuffer[enVarEnd] == '%')) { | |
132 | offset = enVarEnd; | |
133 | // Colorize Environment Variable | |
134 | styler.ColourTo(startLine + offset, SCE_BAT_IDENTIFIER); | |
135 | offset++; | |
136 | // Check for External Command / Program | |
137 | if (!isspacechar(lineBuffer[offset])) { | |
138 | cmdLoc = offset; | |
139 | } | |
140 | } | |
141 | } | |
142 | // Skip next spaces | |
143 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
144 | offset++; | |
145 | } | |
146 | ||
147 | // Read remainder of line word-at-a-time or remainder-of-word-at-a-time | |
148 | while (offset < lengthLine) { | |
149 | if (offset > startLine) { | |
150 | // Colorize Default Text | |
151 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
152 | } | |
153 | // Copy word from Line Buffer into Word Buffer | |
154 | wbl = 0; | |
155 | for (; offset < lengthLine && wbl < 80 && | |
65ec6247 RD |
156 | !isspacechar(lineBuffer[offset]); wbl++, offset++) { |
157 | wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset])); | |
158 | } | |
159 | wordBuffer[wbl] = '\0'; | |
1e9bafca RD |
160 | wbo = 0; |
161 | ||
162 | // Check for Comment - return if found | |
65ec6247 RD |
163 | if (CompareCaseInsensitive(wordBuffer, "rem") == 0) { |
164 | styler.ColourTo(endPos, SCE_BAT_COMMENT); | |
1e9bafca | 165 | return; |
65ec6247 | 166 | } |
1e9bafca RD |
167 | // Check for Separator |
168 | if (IsBSeparator(wordBuffer[0])) { | |
169 | // Check for External Command / Program | |
170 | if ((cmdLoc == offset - wbl) && | |
171 | ((wordBuffer[0] == ':') || | |
172 | (wordBuffer[0] == '\\') || | |
173 | (wordBuffer[0] == '.'))) { | |
174 | // Reset Offset to re-process remainder of word | |
175 | offset -= (wbl - 1); | |
176 | // Colorize External Command / Program | |
177 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
178 | // Reset External Command / Program Location | |
179 | cmdLoc = offset; | |
180 | } else { | |
181 | // Reset Offset to re-process remainder of word | |
182 | offset -= (wbl - 1); | |
183 | // Colorize Default Text | |
184 | styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); | |
185 | } | |
186 | // Check for Regular Keyword in list | |
187 | } else if ((keywords.InList(wordBuffer)) && | |
188 | (continueProcessing)) { | |
189 | // Local Variables do not exist if no FOR statement | |
190 | if (CompareCaseInsensitive(wordBuffer, "for") == 0) { | |
191 | forFound = true; | |
192 | } | |
193 | // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking | |
194 | if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) || | |
195 | (CompareCaseInsensitive(wordBuffer, "goto") == 0) || | |
196 | (CompareCaseInsensitive(wordBuffer, "prompt") == 0) || | |
197 | (CompareCaseInsensitive(wordBuffer, "set") == 0)) { | |
198 | continueProcessing = false; | |
199 | } | |
200 | // Identify External Command / Program Location for ERRORLEVEL, and EXIST | |
201 | if ((CompareCaseInsensitive(wordBuffer, "errorlevel") == 0) || | |
202 | (CompareCaseInsensitive(wordBuffer, "exist") == 0)) { | |
203 | // Reset External Command / Program Location | |
204 | cmdLoc = offset; | |
205 | // Skip next spaces | |
206 | while ((cmdLoc < lengthLine) && | |
207 | (isspacechar(lineBuffer[cmdLoc]))) { | |
208 | cmdLoc++; | |
209 | } | |
210 | // Skip comparison | |
211 | while ((cmdLoc < lengthLine) && | |
212 | (!isspacechar(lineBuffer[cmdLoc]))) { | |
213 | cmdLoc++; | |
214 | } | |
215 | // Skip next spaces | |
216 | while ((cmdLoc < lengthLine) && | |
217 | (isspacechar(lineBuffer[cmdLoc]))) { | |
218 | cmdLoc++; | |
219 | } | |
220 | // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH | |
221 | } else if ((CompareCaseInsensitive(wordBuffer, "call") == 0) || | |
222 | (CompareCaseInsensitive(wordBuffer, "do") == 0) || | |
223 | (CompareCaseInsensitive(wordBuffer, "loadhigh") == 0) || | |
224 | (CompareCaseInsensitive(wordBuffer, "lh") == 0)) { | |
225 | // Reset External Command / Program Location | |
226 | cmdLoc = offset; | |
227 | // Skip next spaces | |
228 | while ((cmdLoc < lengthLine) && | |
229 | (isspacechar(lineBuffer[cmdLoc]))) { | |
230 | cmdLoc++; | |
231 | } | |
232 | } | |
233 | // Colorize Regular keyword | |
234 | styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); | |
235 | // No need to Reset Offset | |
236 | // Check for Special Keyword in list, External Command / Program, or Default Text | |
237 | } else if ((wordBuffer[0] != '%') && | |
238 | (!IsBOperator(wordBuffer[0])) && | |
239 | (continueProcessing)) { | |
240 | // Check for Special Keyword | |
241 | // Affected Commands are in Length range 2-6 | |
242 | // Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected | |
243 | sKeywordFound = false; | |
244 | for (unsigned int keywordLength = 2; keywordLength < wbl && keywordLength < 7 && !sKeywordFound; keywordLength++) { | |
245 | wbo = 0; | |
246 | // Copy Keyword Length from Word Buffer into Special Keyword Buffer | |
247 | for (; wbo < keywordLength; wbo++) { | |
248 | sKeywordBuffer[wbo] = static_cast<char>(wordBuffer[wbo]); | |
249 | } | |
250 | sKeywordBuffer[wbo] = '\0'; | |
251 | // Check for Special Keyword in list | |
252 | if ((keywords.InList(sKeywordBuffer)) && | |
253 | ((IsBOperator(wordBuffer[wbo])) || | |
254 | (IsBSeparator(wordBuffer[wbo])))) { | |
255 | sKeywordFound = true; | |
256 | // ECHO requires no further Regular Keyword Checking | |
257 | if (CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) { | |
258 | continueProcessing = false; | |
259 | } | |
260 | // Colorize Special Keyword as Regular Keyword | |
261 | styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD); | |
262 | // Reset Offset to re-process remainder of word | |
263 | offset -= (wbl - wbo); | |
65ec6247 | 264 | } |
65ec6247 | 265 | } |
1e9bafca RD |
266 | // Check for External Command / Program or Default Text |
267 | if (!sKeywordFound) { | |
268 | wbo = 0; | |
269 | // Check for External Command / Program | |
270 | if (cmdLoc == offset - wbl) { | |
271 | // Read up to %, Operator or Separator | |
272 | while ((wbo < wbl) && | |
273 | (wordBuffer[wbo] != '%') && | |
274 | (!IsBOperator(wordBuffer[wbo])) && | |
275 | (!IsBSeparator(wordBuffer[wbo]))) { | |
276 | wbo++; | |
277 | } | |
278 | // Reset External Command / Program Location | |
279 | cmdLoc = offset - (wbl - wbo); | |
280 | // Reset Offset to re-process remainder of word | |
281 | offset -= (wbl - wbo); | |
282 | // CHOICE requires no further Regular Keyword Checking | |
283 | if (CompareCaseInsensitive(wordBuffer, "choice") == 0) { | |
284 | continueProcessing = false; | |
285 | } | |
286 | // Check for START (and its switches) - What follows is External Command \ Program | |
287 | if (CompareCaseInsensitive(wordBuffer, "start") == 0) { | |
288 | // Reset External Command / Program Location | |
289 | cmdLoc = offset; | |
290 | // Skip next spaces | |
291 | while ((cmdLoc < lengthLine) && | |
292 | (isspacechar(lineBuffer[cmdLoc]))) { | |
293 | cmdLoc++; | |
294 | } | |
295 | // Reset External Command / Program Location if command switch detected | |
296 | if (lineBuffer[cmdLoc] == '/') { | |
297 | // Skip command switch | |
298 | while ((cmdLoc < lengthLine) && | |
299 | (!isspacechar(lineBuffer[cmdLoc]))) { | |
300 | cmdLoc++; | |
301 | } | |
302 | // Skip next spaces | |
303 | while ((cmdLoc < lengthLine) && | |
304 | (isspacechar(lineBuffer[cmdLoc]))) { | |
305 | cmdLoc++; | |
306 | } | |
307 | } | |
308 | } | |
309 | // Colorize External command / program | |
310 | styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); | |
311 | // No need to Reset Offset | |
312 | // Check for Default Text | |
65ec6247 | 313 | } else { |
1e9bafca RD |
314 | // Read up to %, Operator or Separator |
315 | while ((wbo < wbl) && | |
316 | (wordBuffer[wbo] != '%') && | |
317 | (!IsBOperator(wordBuffer[wbo])) && | |
318 | (!IsBSeparator(wordBuffer[wbo]))) { | |
319 | wbo++; | |
320 | } | |
321 | // Colorize Default Text | |
322 | styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); | |
323 | // Reset Offset to re-process remainder of word | |
324 | offset -= (wbl - wbo); | |
325 | } | |
326 | } | |
327 | // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a) | |
328 | } else if (wordBuffer[0] == '%') { | |
329 | // Colorize Default Text | |
330 | styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); | |
331 | wbo++; | |
332 | // Search to end of word for second % (can be a long path) | |
333 | while ((wbo < wbl) && | |
334 | (wordBuffer[wbo] != '%') && | |
335 | (!IsBOperator(wordBuffer[wbo])) && | |
336 | (!IsBSeparator(wordBuffer[wbo]))) { | |
337 | wbo++; | |
338 | } | |
339 | // Check for Argument (%n) | |
340 | if ((Is0To9(wordBuffer[1])) && | |
341 | (wordBuffer[wbo] != '%')) { | |
342 | // Check for External Command / Program | |
343 | if (cmdLoc == offset - wbl) { | |
344 | cmdLoc = offset - (wbl - 2); | |
65ec6247 | 345 | } |
1e9bafca RD |
346 | // Colorize Argument |
347 | styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER); | |
348 | // Reset Offset to re-process remainder of word | |
349 | offset -= (wbl - 2); | |
350 | // Check for Environment Variable (%x...%) | |
351 | } else if ((wordBuffer[1] != '%') && | |
352 | (wordBuffer[wbo] == '%')) { | |
353 | wbo++; | |
354 | // Check for External Command / Program | |
355 | if (cmdLoc == offset - wbl) { | |
356 | cmdLoc = offset - (wbl - wbo); | |
65ec6247 | 357 | } |
1e9bafca RD |
358 | // Colorize Environment Variable |
359 | styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); | |
360 | // Reset Offset to re-process remainder of word | |
361 | offset -= (wbl - wbo); | |
362 | // Check for Local Variable (%%a) | |
363 | } else if ((forFound) && | |
364 | (wordBuffer[1] == '%') && | |
365 | (wordBuffer[2] != '%') && | |
366 | (!IsBOperator(wordBuffer[2])) && | |
367 | (!IsBSeparator(wordBuffer[2]))) { | |
368 | // Check for External Command / Program | |
369 | if (cmdLoc == offset - wbl) { | |
370 | cmdLoc = offset - (wbl - 3); | |
371 | } | |
372 | // Colorize Local Variable | |
373 | styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER); | |
374 | // Reset Offset to re-process remainder of word | |
375 | offset -= (wbl - 3); | |
376 | } | |
377 | // Check for Operator | |
378 | } else if (IsBOperator(wordBuffer[0])) { | |
379 | // Colorize Default Text | |
380 | styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); | |
381 | // Check for Comparison Operator | |
382 | if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) { | |
383 | // Identify External Command / Program Location for IF | |
384 | cmdLoc = offset; | |
385 | // Skip next spaces | |
386 | while ((cmdLoc < lengthLine) && | |
387 | (isspacechar(lineBuffer[cmdLoc]))) { | |
388 | cmdLoc++; | |
389 | } | |
390 | // Colorize Comparison Operator | |
391 | styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR); | |
392 | // Reset Offset to re-process remainder of word | |
393 | offset -= (wbl - 2); | |
394 | // Check for Pipe Operator | |
395 | } else if (wordBuffer[0] == '|') { | |
396 | // Reset External Command / Program Location | |
397 | cmdLoc = offset - wbl + 1; | |
398 | // Skip next spaces | |
399 | while ((cmdLoc < lengthLine) && | |
400 | (isspacechar(lineBuffer[cmdLoc]))) { | |
401 | cmdLoc++; | |
402 | } | |
403 | // Colorize Pipe Operator | |
404 | styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); | |
405 | // Reset Offset to re-process remainder of word | |
406 | offset -= (wbl - 1); | |
407 | // Check for Other Operator | |
408 | } else { | |
409 | // Check for > Operator | |
410 | if (wordBuffer[0] == '>') { | |
411 | // Turn Keyword and External Command / Program checking back on | |
412 | continueProcessing = true; | |
413 | } | |
414 | // Colorize Other Operator | |
415 | styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); | |
416 | // Reset Offset to re-process remainder of word | |
417 | offset -= (wbl - 1); | |
418 | } | |
419 | // Check for Default Text | |
420 | } else { | |
421 | // Read up to %, Operator or Separator | |
422 | while ((wbo < wbl) && | |
423 | (wordBuffer[wbo] != '%') && | |
424 | (!IsBOperator(wordBuffer[wbo])) && | |
425 | (!IsBSeparator(wordBuffer[wbo]))) { | |
426 | wbo++; | |
427 | } | |
428 | // Colorize Default Text | |
429 | styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); | |
430 | // Reset Offset to re-process remainder of word | |
431 | offset -= (wbl - wbo); | |
432 | } | |
433 | // Skip next spaces - nothing happens if Offset was Reset | |
434 | while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { | |
65ec6247 RD |
435 | offset++; |
436 | } | |
f6bcfd97 | 437 | } |
1e9bafca RD |
438 | // Colorize Default Text for remainder of line - currently not lexed |
439 | styler.ColourTo(endPos, SCE_BAT_DEFAULT); | |
f6bcfd97 | 440 | } |
65ec6247 RD |
441 | |
442 | static void ColouriseBatchDoc( | |
443 | unsigned int startPos, | |
444 | int length, | |
445 | int /*initStyle*/, | |
446 | WordList *keywordlists[], | |
447 | Accessor &styler) { | |
f6bcfd97 | 448 | |
f6bcfd97 | 449 | char lineBuffer[1024]; |
65ec6247 RD |
450 | WordList &keywords = *keywordlists[0]; |
451 | ||
f6bcfd97 BP |
452 | styler.StartAt(startPos); |
453 | styler.StartSegment(startPos); | |
1a2fb4cd RD |
454 | unsigned int linePos = 0; |
455 | unsigned int startLine = startPos; | |
456 | for (unsigned int i = startPos; i < startPos + length; i++) { | |
f6bcfd97 | 457 | lineBuffer[linePos++] = styler[i]; |
1a2fb4cd | 458 | if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { |
65ec6247 | 459 | // End of line (or of line buffer) met, colourise it |
65ec6247 RD |
460 | lineBuffer[linePos] = '\0'; |
461 | ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywords, styler); | |
f6bcfd97 | 462 | linePos = 0; |
65ec6247 | 463 | startLine = i + 1; |
f6bcfd97 BP |
464 | } |
465 | } | |
1a2fb4cd RD |
466 | if (linePos > 0) { // Last line does not have ending characters |
467 | ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1, | |
65ec6247 RD |
468 | keywords, styler); |
469 | } | |
f6bcfd97 BP |
470 | } |
471 | ||
d134f170 RD |
472 | static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) { |
473 | // It is needed to remember the current state to recognize starting | |
474 | // comment lines before the first "diff " or "--- ". If a real | |
475 | // difference starts then each line starting with ' ' is a whitespace | |
476 | // otherwise it is considered a comment (Only in..., Binary file...) | |
591d01be | 477 | if (0 == strncmp(lineBuffer, "diff ", 5)) { |
a834585d | 478 | styler.ColourTo(endLine, SCE_DIFF_COMMAND); |
591d01be RD |
479 | } else if (0 == strncmp(lineBuffer, "--- ", 4)) { |
480 | // In a context diff, --- appears in both the header and the position markers | |
481 | if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) | |
482 | styler.ColourTo(endLine, SCE_DIFF_POSITION); | |
483 | else | |
484 | styler.ColourTo(endLine, SCE_DIFF_HEADER); | |
485 | } else if (0 == strncmp(lineBuffer, "+++ ", 4)) { | |
486 | // I don't know of any diff where "+++ " is a position marker, but for | |
487 | // consistency, do the same as with "--- " and "*** ". | |
488 | if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) | |
489 | styler.ColourTo(endLine, SCE_DIFF_POSITION); | |
490 | else | |
491 | styler.ColourTo(endLine, SCE_DIFF_HEADER); | |
9e730a78 RD |
492 | } else if (0 == strncmp(lineBuffer, "====", 4)) { // For p4's diff |
493 | styler.ColourTo(endLine, SCE_DIFF_HEADER); | |
591d01be RD |
494 | } else if (0 == strncmp(lineBuffer, "***", 3)) { |
495 | // In a context diff, *** appears in both the header and the position markers. | |
496 | // Also ******** is a chunk header, but here it's treated as part of the | |
497 | // position marker since there is no separate style for a chunk header. | |
498 | if (lineBuffer[3] == ' ' && atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) | |
499 | styler.ColourTo(endLine, SCE_DIFF_POSITION); | |
500 | else if (lineBuffer[3] == '*') | |
501 | styler.ColourTo(endLine, SCE_DIFF_POSITION); | |
502 | else | |
503 | styler.ColourTo(endLine, SCE_DIFF_HEADER); | |
9e730a78 | 504 | } else if (0 == strncmp(lineBuffer, "? ", 2)) { // For difflib |
a834585d | 505 | styler.ColourTo(endLine, SCE_DIFF_HEADER); |
d134f170 | 506 | } else if (lineBuffer[0] == '@') { |
a834585d | 507 | styler.ColourTo(endLine, SCE_DIFF_POSITION); |
591d01be RD |
508 | } else if (lineBuffer[0] >= '0' && lineBuffer[0] <= '9') { |
509 | styler.ColourTo(endLine, SCE_DIFF_POSITION); | |
9e730a78 | 510 | } else if (lineBuffer[0] == '-' || lineBuffer[0] == '<') { |
a834585d | 511 | styler.ColourTo(endLine, SCE_DIFF_DELETED); |
9e730a78 | 512 | } else if (lineBuffer[0] == '+' || lineBuffer[0] == '>') { |
a834585d | 513 | styler.ColourTo(endLine, SCE_DIFF_ADDED); |
d134f170 | 514 | } else if (lineBuffer[0] != ' ') { |
a834585d | 515 | styler.ColourTo(endLine, SCE_DIFF_COMMENT); |
d134f170 | 516 | } else { |
a834585d | 517 | styler.ColourTo(endLine, SCE_DIFF_DEFAULT); |
d134f170 RD |
518 | } |
519 | } | |
520 | ||
521 | static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
522 | char lineBuffer[1024]; | |
523 | styler.StartAt(startPos); | |
524 | styler.StartSegment(startPos); | |
525 | unsigned int linePos = 0; | |
526 | for (unsigned int i = startPos; i < startPos + length; i++) { | |
527 | lineBuffer[linePos++] = styler[i]; | |
1a2fb4cd RD |
528 | if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { |
529 | // End of line (or of line buffer) met, colourise it | |
530 | lineBuffer[linePos] = '\0'; | |
d134f170 RD |
531 | ColouriseDiffLine(lineBuffer, i, styler); |
532 | linePos = 0; | |
533 | } | |
534 | } | |
1a2fb4cd RD |
535 | if (linePos > 0) { // Last line does not have ending characters |
536 | ColouriseDiffLine(lineBuffer, startPos + length - 1, styler); | |
537 | } | |
d134f170 RD |
538 | } |
539 | ||
591d01be RD |
540 | static void FoldDiffDoc(unsigned int startPos, int length, int, WordList*[], Accessor &styler) { |
541 | int curLine = styler.GetLine(startPos); | |
542 | int prevLevel = SC_FOLDLEVELBASE; | |
543 | if (curLine > 0) | |
544 | prevLevel = styler.LevelAt(curLine-1); | |
545 | ||
546 | int curLineStart = styler.LineStart(curLine); | |
547 | do { | |
548 | int nextLevel = prevLevel; | |
549 | if (prevLevel & SC_FOLDLEVELHEADERFLAG) | |
550 | nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1; | |
1e9bafca | 551 | |
591d01be RD |
552 | int lineType = styler.StyleAt(curLineStart); |
553 | if (lineType == SCE_DIFF_COMMAND) | |
554 | nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG; | |
555 | else if (lineType == SCE_DIFF_HEADER) { | |
556 | nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG; | |
557 | } else if (lineType == SCE_DIFF_POSITION) | |
558 | nextLevel = (SC_FOLDLEVELBASE + 3) | SC_FOLDLEVELHEADERFLAG; | |
1e9bafca | 559 | |
591d01be RD |
560 | if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel)) |
561 | styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG); | |
562 | ||
563 | styler.SetLevel(curLine, nextLevel); | |
564 | prevLevel = nextLevel; | |
1e9bafca | 565 | |
591d01be RD |
566 | curLineStart = styler.LineStart(++curLine); |
567 | } while (static_cast<int>(startPos) + length > curLineStart); | |
568 | } | |
569 | ||
570 | ||
65ec6247 RD |
571 | static void ColourisePropsLine( |
572 | char *lineBuffer, | |
573 | unsigned int lengthLine, | |
574 | unsigned int startLine, | |
575 | unsigned int endPos, | |
576 | Accessor &styler) { | |
577 | ||
578 | unsigned int i = 0; | |
1a2fb4cd | 579 | while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces |
f6bcfd97 | 580 | i++; |
1a2fb4cd RD |
581 | if (i < lengthLine) { |
582 | if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') { | |
a834585d | 583 | styler.ColourTo(endPos, SCE_PROPS_COMMENT); |
1a2fb4cd | 584 | } else if (lineBuffer[i] == '[') { |
a834585d | 585 | styler.ColourTo(endPos, SCE_PROPS_SECTION); |
1a2fb4cd | 586 | } else if (lineBuffer[i] == '@') { |
a834585d | 587 | styler.ColourTo(startLine + i, SCE_PROPS_DEFVAL); |
1a2fb4cd | 588 | if (lineBuffer[++i] == '=') |
a834585d RD |
589 | styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT); |
590 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); | |
f6bcfd97 | 591 | } else { |
1a2fb4cd RD |
592 | // Search for the '=' character |
593 | while ((i < lengthLine) && (lineBuffer[i] != '=')) | |
594 | i++; | |
595 | if ((i < lengthLine) && (lineBuffer[i] == '=')) { | |
a834585d | 596 | styler.ColourTo(startLine + i - 1, SCE_PROPS_DEFAULT); |
1a2fb4cd | 597 | styler.ColourTo(startLine + i, 3); |
a834585d | 598 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); |
1a2fb4cd | 599 | } else { |
a834585d | 600 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); |
1a2fb4cd | 601 | } |
f6bcfd97 | 602 | } |
1a2fb4cd | 603 | } else { |
a834585d | 604 | styler.ColourTo(endPos, SCE_PROPS_DEFAULT); |
f6bcfd97 BP |
605 | } |
606 | } | |
607 | ||
608 | static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
609 | char lineBuffer[1024]; | |
610 | styler.StartAt(startPos); | |
611 | styler.StartSegment(startPos); | |
1a2fb4cd RD |
612 | unsigned int linePos = 0; |
613 | unsigned int startLine = startPos; | |
614 | for (unsigned int i = startPos; i < startPos + length; i++) { | |
f6bcfd97 | 615 | lineBuffer[linePos++] = styler[i]; |
1a2fb4cd RD |
616 | if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { |
617 | // End of line (or of line buffer) met, colourise it | |
f6bcfd97 BP |
618 | lineBuffer[linePos] = '\0'; |
619 | ColourisePropsLine(lineBuffer, linePos, startLine, i, styler); | |
620 | linePos = 0; | |
65ec6247 | 621 | startLine = i + 1; |
f6bcfd97 BP |
622 | } |
623 | } | |
1a2fb4cd RD |
624 | if (linePos > 0) { // Last line does not have ending characters |
625 | ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); | |
626 | } | |
f6bcfd97 BP |
627 | } |
628 | ||
88a8b04e RD |
629 | // adaption by ksc, using the "} else {" trick of 1.53 |
630 | // 030721 | |
631 | static void FoldPropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
632 | bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; | |
633 | ||
634 | unsigned int endPos = startPos + length; | |
635 | int visibleChars = 0; | |
636 | int lineCurrent = styler.GetLine(startPos); | |
637 | ||
638 | char chNext = styler[startPos]; | |
639 | int styleNext = styler.StyleAt(startPos); | |
640 | bool headerPoint = false; | |
a33203cb | 641 | int lev; |
88a8b04e RD |
642 | |
643 | for (unsigned int i = startPos; i < endPos; i++) { | |
644 | char ch = chNext; | |
645 | chNext = styler[i+1]; | |
646 | ||
647 | int style = styleNext; | |
648 | styleNext = styler.StyleAt(i + 1); | |
649 | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); | |
650 | ||
a33203cb | 651 | if (style == SCE_PROPS_SECTION) { |
88a8b04e RD |
652 | headerPoint = true; |
653 | } | |
654 | ||
655 | if (atEOL) { | |
a33203cb RD |
656 | lev = SC_FOLDLEVELBASE; |
657 | ||
658 | if (lineCurrent > 0) { | |
659 | int levelPrevious = styler.LevelAt(lineCurrent - 1); | |
88a8b04e | 660 | |
a33203cb RD |
661 | if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { |
662 | lev = SC_FOLDLEVELBASE + 1; | |
663 | } else { | |
664 | lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; | |
665 | } | |
666 | } | |
667 | ||
668 | if (headerPoint) { | |
669 | lev = SC_FOLDLEVELBASE; | |
670 | } | |
88a8b04e RD |
671 | if (visibleChars == 0 && foldCompact) |
672 | lev |= SC_FOLDLEVELWHITEFLAG; | |
673 | ||
a33203cb | 674 | if (headerPoint) { |
88a8b04e | 675 | lev |= SC_FOLDLEVELHEADERFLAG; |
a33203cb | 676 | } |
88a8b04e RD |
677 | if (lev != styler.LevelAt(lineCurrent)) { |
678 | styler.SetLevel(lineCurrent, lev); | |
679 | } | |
680 | ||
681 | lineCurrent++; | |
682 | visibleChars = 0; | |
1e9bafca | 683 | headerPoint = false; |
88a8b04e RD |
684 | } |
685 | if (!isspacechar(ch)) | |
686 | visibleChars++; | |
687 | } | |
688 | ||
a33203cb RD |
689 | if (lineCurrent > 0) { |
690 | int levelPrevious = styler.LevelAt(lineCurrent - 1); | |
691 | if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { | |
692 | lev = SC_FOLDLEVELBASE + 1; | |
693 | } else { | |
694 | lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; | |
695 | } | |
696 | } else { | |
697 | lev = SC_FOLDLEVELBASE; | |
698 | } | |
699 | int flagsNext = styler.LevelAt(lineCurrent); | |
700 | styler.SetLevel(lineCurrent, lev | flagsNext & ~SC_FOLDLEVELNUMBERMASK); | |
88a8b04e RD |
701 | } |
702 | ||
65ec6247 RD |
703 | static void ColouriseMakeLine( |
704 | char *lineBuffer, | |
705 | unsigned int lengthLine, | |
706 | unsigned int startLine, | |
707 | unsigned int endPos, | |
708 | Accessor &styler) { | |
709 | ||
710 | unsigned int i = 0; | |
9e730a78 | 711 | int lastNonSpace = -1; |
65ec6247 RD |
712 | unsigned int state = SCE_MAKE_DEFAULT; |
713 | bool bSpecial = false; | |
714 | // Skip initial spaces | |
1a2fb4cd | 715 | while ((i < lengthLine) && isspacechar(lineBuffer[i])) { |
f6bcfd97 | 716 | i++; |
65ec6247 RD |
717 | } |
718 | if (lineBuffer[i] == '#') { // Comment | |
719 | styler.ColourTo(endPos, SCE_MAKE_COMMENT); | |
720 | return; | |
721 | } | |
722 | if (lineBuffer[i] == '!') { // Special directive | |
723 | styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR); | |
724 | return; | |
725 | } | |
726 | while (i < lengthLine) { | |
727 | if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') { | |
728 | styler.ColourTo(startLine + i - 1, state); | |
729 | state = SCE_MAKE_IDENTIFIER; | |
730 | } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') { | |
731 | styler.ColourTo(startLine + i, state); | |
732 | state = SCE_MAKE_DEFAULT; | |
733 | } | |
734 | if (!bSpecial) { | |
735 | if (lineBuffer[i] == ':') { | |
1a2fb4cd RD |
736 | // We should check that no colouring was made since the beginning of the line, |
737 | // to avoid colouring stuff like /OUT:file | |
9e730a78 RD |
738 | if (lastNonSpace >= 0) |
739 | styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET); | |
65ec6247 RD |
740 | styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); |
741 | styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); | |
742 | bSpecial = true; // Only react to the first ':' of the line | |
743 | state = SCE_MAKE_DEFAULT; | |
744 | } else if (lineBuffer[i] == '=') { | |
9e730a78 RD |
745 | if (lastNonSpace >= 0) |
746 | styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER); | |
65ec6247 RD |
747 | styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); |
748 | styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); | |
749 | bSpecial = true; // Only react to the first '=' of the line | |
750 | state = SCE_MAKE_DEFAULT; | |
751 | } | |
752 | } | |
753 | if (!isspacechar(lineBuffer[i])) { | |
754 | lastNonSpace = i; | |
755 | } | |
756 | i++; | |
757 | } | |
758 | if (state == SCE_MAKE_IDENTIFIER) { | |
759 | styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended | |
f6bcfd97 | 760 | } else { |
65ec6247 | 761 | styler.ColourTo(endPos, SCE_MAKE_DEFAULT); |
f6bcfd97 BP |
762 | } |
763 | } | |
764 | ||
765 | static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
766 | char lineBuffer[1024]; | |
767 | styler.StartAt(startPos); | |
768 | styler.StartSegment(startPos); | |
1a2fb4cd RD |
769 | unsigned int linePos = 0; |
770 | unsigned int startLine = startPos; | |
771 | for (unsigned int i = startPos; i < startPos + length; i++) { | |
f6bcfd97 | 772 | lineBuffer[linePos++] = styler[i]; |
1a2fb4cd RD |
773 | if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { |
774 | // End of line (or of line buffer) met, colourise it | |
65ec6247 RD |
775 | lineBuffer[linePos] = '\0'; |
776 | ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler); | |
f6bcfd97 | 777 | linePos = 0; |
65ec6247 | 778 | startLine = i + 1; |
f6bcfd97 BP |
779 | } |
780 | } | |
1a2fb4cd RD |
781 | if (linePos > 0) { // Last line does not have ending characters |
782 | ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); | |
65ec6247 | 783 | } |
f6bcfd97 BP |
784 | } |
785 | ||
1e9bafca | 786 | static bool strstart(const char *haystack, const char *needle) { |
9e730a78 RD |
787 | return strncmp(haystack, needle, strlen(needle)) == 0; |
788 | } | |
789 | ||
1e9bafca | 790 | static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine) { |
f6bcfd97 BP |
791 | if (lineBuffer[0] == '>') { |
792 | // Command or return status | |
1e9bafca | 793 | return SCE_ERR_CMD; |
f114b858 RD |
794 | } else if (lineBuffer[0] == '<') { |
795 | // Diff removal, but not interested. Trapped to avoid hitting CTAG cases. | |
1e9bafca | 796 | return SCE_ERR_DEFAULT; |
65ec6247 | 797 | } else if (lineBuffer[0] == '!') { |
1e9bafca | 798 | return SCE_ERR_DIFF_CHANGED; |
65ec6247 | 799 | } else if (lineBuffer[0] == '+') { |
1e9bafca RD |
800 | if (strstart(lineBuffer, "+++ ")) { |
801 | return SCE_ERR_DIFF_MESSAGE; | |
802 | } else { | |
803 | return SCE_ERR_DIFF_ADDITION; | |
804 | } | |
591d01be | 805 | } else if (lineBuffer[0] == '-') { |
1e9bafca RD |
806 | if (strstart(lineBuffer, "--- ")) { |
807 | return SCE_ERR_DIFF_MESSAGE; | |
808 | } else { | |
809 | return SCE_ERR_DIFF_DELETION; | |
810 | } | |
8e54aaed RD |
811 | } else if (strstart(lineBuffer, "cf90-")) { |
812 | // Absoft Pro Fortran 90/95 v8.2 error and/or warning message | |
1e9bafca | 813 | return SCE_ERR_ABSF; |
8e54aaed RD |
814 | } else if (strstart(lineBuffer, "fortcom:")) { |
815 | // Intel Fortran Compiler v8.0 error/warning message | |
1e9bafca | 816 | return SCE_ERR_IFORT; |
f6bcfd97 | 817 | } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) { |
1e9bafca | 818 | return SCE_ERR_PYTHON; |
9e730a78 | 819 | } else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) { |
1e9bafca | 820 | return SCE_ERR_PHP; |
9e730a78 | 821 | } else if ((strstart(lineBuffer, "Error ") || |
1e9bafca RD |
822 | strstart(lineBuffer, "Warning ")) && |
823 | strstr(lineBuffer, " at (") && | |
824 | strstr(lineBuffer, ") : ") && | |
825 | (strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) { | |
9e730a78 | 826 | // Intel Fortran Compiler error/warning message |
1e9bafca | 827 | return SCE_ERR_IFC; |
9e730a78 | 828 | } else if (strstart(lineBuffer, "Error ")) { |
f6bcfd97 | 829 | // Borland error message |
1e9bafca | 830 | return SCE_ERR_BORLAND; |
9e730a78 | 831 | } else if (strstart(lineBuffer, "Warning ")) { |
f6bcfd97 | 832 | // Borland warning message |
1e9bafca | 833 | return SCE_ERR_BORLAND; |
65ec6247 | 834 | } else if (strstr(lineBuffer, "at line " ) && |
1a2fb4cd | 835 | (strstr(lineBuffer, "at line " ) < (lineBuffer + lengthLine)) && |
65ec6247 | 836 | strstr(lineBuffer, "file ") && |
1a2fb4cd | 837 | (strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) { |
591d01be | 838 | // Lua 4 error message |
1e9bafca | 839 | return SCE_ERR_LUA; |
65ec6247 | 840 | } else if (strstr(lineBuffer, " at " ) && |
1a2fb4cd | 841 | (strstr(lineBuffer, " at " ) < (lineBuffer + lengthLine)) && |
65ec6247 | 842 | strstr(lineBuffer, " line ") && |
9e730a78 | 843 | (strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) && |
1e9bafca | 844 | (strstr(lineBuffer, " at " ) < (strstr(lineBuffer, " line ")))) { |
d134f170 | 845 | // perl error message |
1e9bafca | 846 | return SCE_ERR_PERL; |
65ec6247 | 847 | } else if ((memcmp(lineBuffer, " at ", 6) == 0) && |
1e9bafca | 848 | strstr(lineBuffer, ":line ")) { |
65ec6247 | 849 | // A .NET traceback |
1e9bafca | 850 | return SCE_ERR_NET; |
9e730a78 | 851 | } else if (strstart(lineBuffer, "Line ") && |
1e9bafca | 852 | strstr(lineBuffer, ", file ")) { |
9e730a78 | 853 | // Essential Lahey Fortran error message |
1e9bafca | 854 | return SCE_ERR_ELF; |
a33203cb | 855 | } else if (strstart(lineBuffer, "line ") && |
1e9bafca | 856 | strstr(lineBuffer, " column ")) { |
a33203cb | 857 | // HTML tidy style: line 42 column 1 |
1e9bafca | 858 | return SCE_ERR_TIDY; |
a33203cb | 859 | } else if (strstart(lineBuffer, "\tat ") && |
1e9bafca RD |
860 | strstr(lineBuffer, "(") && |
861 | strstr(lineBuffer, ".java:")) { | |
a33203cb | 862 | // Java stack back trace |
1e9bafca | 863 | return SCE_ERR_JAVA_STACK; |
f6bcfd97 | 864 | } else { |
1e9bafca RD |
865 | // Look for one of the following formats: |
866 | // GCC: <filename>:<line>:<message> | |
867 | // Microsoft: <filename>(<line>) :<message> | |
868 | // Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal | |
869 | // Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal | |
870 | // Microsoft: <filename>(<line>,<column>)<message> | |
871 | // CTags: \t<message> | |
872 | // Lua 5 traceback: \t<filename>:<line>:<message> | |
591d01be | 873 | bool initialTab = (lineBuffer[0] == '\t'); |
1e9bafca RD |
874 | enum { stInitial, |
875 | stGccStart, stGccDigit, stGcc, | |
876 | stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet, | |
877 | stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags, | |
878 | stUnrecognized | |
879 | } state = stInitial; | |
65ec6247 | 880 | for (unsigned int i = 0; i < lengthLine; i++) { |
9e730a78 RD |
881 | char ch = lineBuffer[i]; |
882 | char chNext = ' '; | |
1e9bafca RD |
883 | if ((i + 1) < lengthLine) |
884 | chNext = lineBuffer[i + 1]; | |
885 | if (state == stInitial) { | |
9e730a78 | 886 | if (ch == ':') { |
591d01be | 887 | // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix) |
9e730a78 RD |
888 | if ((chNext != '\\') && (chNext != '/')) { |
889 | // This check is not completely accurate as may be on | |
890 | // GTK+ with a file name that includes ':'. | |
1e9bafca | 891 | state = stGccStart; |
9e730a78 | 892 | } |
591d01be | 893 | } else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) { |
9e730a78 | 894 | // May be Microsoft |
591d01be | 895 | // Check against '0' often removes phone numbers |
1e9bafca | 896 | state = stMsStart; |
591d01be | 897 | } else if ((ch == '\t') && (!initialTab)) { |
9e730a78 | 898 | // May be CTags |
1e9bafca | 899 | state = stCtagsStart; |
9e730a78 | 900 | } |
1e9bafca RD |
901 | } else if (state == stGccStart) { // <filename>: |
902 | state = Is1To9(ch) ? stGccDigit : stUnrecognized; | |
903 | } else if (state == stGccDigit) { // <filename>:<line> | |
9e730a78 | 904 | if (ch == ':') { |
1e9bafca | 905 | state = stGcc; // :9.*: is GCC |
9e730a78 RD |
906 | break; |
907 | } else if (!Is0To9(ch)) { | |
1e9bafca | 908 | state = stUnrecognized; |
9e730a78 | 909 | } |
1e9bafca RD |
910 | } else if (state == stMsStart) { // <filename>( |
911 | state = Is0To9(ch) ? stMsDigit : stUnrecognized; | |
912 | } else if (state == stMsDigit) { // <filename>(<line> | |
9e730a78 | 913 | if (ch == ',') { |
1e9bafca | 914 | state = stMsDigitComma; |
9e730a78 | 915 | } else if (ch == ')') { |
1e9bafca | 916 | state = stMsBracket; |
9e730a78 | 917 | } else if ((ch != ' ') && !Is0To9(ch)) { |
1e9bafca | 918 | state = stUnrecognized; |
9e730a78 | 919 | } |
1e9bafca | 920 | } else if (state == stMsBracket) { // <filename>(<line>) |
591d01be | 921 | if ((ch == ' ') && (chNext == ':')) { |
1e9bafca RD |
922 | state = stMsVc; |
923 | } else if ((ch == ':' && chNext == ' ') || (ch == ' ')) { | |
924 | // Possibly Delphi.. don't test against chNext as it's one of the strings below. | |
925 | char word[512]; | |
926 | unsigned int j, chPos; | |
927 | unsigned numstep; | |
928 | chPos = 0; | |
929 | if (ch == ' ') | |
930 | numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i. | |
931 | else | |
932 | numstep = 2; // otherwise add 2. | |
933 | for (j = i + numstep; j < lengthLine && isalpha(lineBuffer[j]) && chPos < sizeof(word) - 1; j++) | |
934 | word[chPos++] = lineBuffer[j]; | |
935 | word[chPos] = 0; | |
936 | if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") || | |
937 | !CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") || | |
938 | !CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) { | |
939 | state = stMsVc; | |
940 | } else | |
941 | state = stUnrecognized; | |
591d01be | 942 | } else { |
1e9bafca | 943 | state = stUnrecognized; |
591d01be | 944 | } |
1e9bafca | 945 | } else if (state == stMsDigitComma) { // <filename>(<line>, |
9e730a78 | 946 | if (ch == ')') { |
1e9bafca | 947 | state = stMsDotNet; |
9e730a78 RD |
948 | break; |
949 | } else if ((ch != ' ') && !Is0To9(ch)) { | |
1e9bafca | 950 | state = stUnrecognized; |
9e730a78 | 951 | } |
1e9bafca RD |
952 | } else if (state == stCtagsStart) { |
953 | if ((lineBuffer[i - 1] == '\t') && | |
954 | ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) { | |
955 | state = stCtags; | |
9e730a78 | 956 | break; |
1e9bafca RD |
957 | } else if ((ch == '/') && (lineBuffer[i + 1] == '^')) { |
958 | state = stCtagsStartString; | |
9e730a78 | 959 | } |
1e9bafca RD |
960 | } else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) { |
961 | state = stCtagsStringDollar; | |
9e730a78 | 962 | break; |
f6bcfd97 BP |
963 | } |
964 | } | |
1e9bafca RD |
965 | if (state == stGcc) { |
966 | return SCE_ERR_GCC; | |
967 | } else if ((state == stMsVc) || (state == stMsDotNet)) { | |
968 | return SCE_ERR_MS; | |
969 | } else if ((state == stCtagsStringDollar) || (state == stCtags)) { | |
970 | return SCE_ERR_CTAG; | |
f6bcfd97 | 971 | } else { |
1e9bafca | 972 | return SCE_ERR_DEFAULT; |
f6bcfd97 BP |
973 | } |
974 | } | |
975 | } | |
976 | ||
1e9bafca RD |
977 | static void ColouriseErrorListLine( |
978 | char *lineBuffer, | |
979 | unsigned int lengthLine, | |
980 | unsigned int endPos, | |
981 | Accessor &styler) { | |
982 | styler.ColourTo(endPos, RecogniseErrorListLine(lineBuffer, lengthLine)); | |
983 | } | |
984 | ||
f6bcfd97 | 985 | static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { |
1e9bafca | 986 | char lineBuffer[10000]; |
f6bcfd97 BP |
987 | styler.StartAt(startPos); |
988 | styler.StartSegment(startPos); | |
989 | unsigned int linePos = 0; | |
1a2fb4cd | 990 | for (unsigned int i = startPos; i < startPos + length; i++) { |
f6bcfd97 | 991 | lineBuffer[linePos++] = styler[i]; |
1a2fb4cd RD |
992 | if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { |
993 | // End of line (or of line buffer) met, colourise it | |
994 | lineBuffer[linePos] = '\0'; | |
f6bcfd97 BP |
995 | ColouriseErrorListLine(lineBuffer, linePos, i, styler); |
996 | linePos = 0; | |
997 | } | |
998 | } | |
1a2fb4cd RD |
999 | if (linePos > 0) { // Last line does not have ending characters |
1000 | ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler); | |
1001 | } | |
f6bcfd97 BP |
1002 | } |
1003 | ||
1004 | static int isSpecial(char s) { | |
f6bcfd97 BP |
1005 | return (s == '\\') || (s == ',') || (s == ';') || (s == '\'') || (s == ' ') || |
1006 | (s == '\"') || (s == '`') || (s == '^') || (s == '~'); | |
1007 | } | |
1008 | ||
1009 | static int isTag(int start, Accessor &styler) { | |
f6bcfd97 | 1010 | char s[6]; |
65ec6247 | 1011 | unsigned int i = 0, e = 1; |
f6bcfd97 BP |
1012 | while (i < 5 && e) { |
1013 | s[i] = styler[start + i]; | |
1014 | i++; | |
1015 | e = styler[start + i] != '{'; | |
1016 | } | |
1017 | s[i] = '\0'; | |
1018 | return (strcmp(s, "begin") == 0) || (strcmp(s, "end") == 0); | |
1019 | } | |
1020 | ||
1021 | static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle, | |
65ec6247 | 1022 | WordList *[], Accessor &styler) { |
f6bcfd97 BP |
1023 | |
1024 | styler.StartAt(startPos); | |
1025 | ||
1026 | int state = initStyle; | |
1027 | char chNext = styler[startPos]; | |
1028 | styler.StartSegment(startPos); | |
1029 | int lengthDoc = startPos + length; | |
1030 | ||
1031 | for (int i = startPos; i < lengthDoc; i++) { | |
1032 | char ch = chNext; | |
1033 | chNext = styler.SafeGetCharAt(i + 1); | |
1034 | ||
1035 | if (styler.IsLeadByte(ch)) { | |
1036 | chNext = styler.SafeGetCharAt(i + 2); | |
1037 | i++; | |
1038 | continue; | |
1039 | } | |
65ec6247 RD |
1040 | switch (state) { |
1041 | case SCE_L_DEFAULT : | |
1042 | switch (ch) { | |
1043 | case '\\' : | |
1044 | styler.ColourTo(i - 1, state); | |
1045 | if (isSpecial(styler[i + 1])) { | |
1046 | styler.ColourTo(i + 1, SCE_L_COMMAND); | |
f6bcfd97 BP |
1047 | i++; |
1048 | chNext = styler.SafeGetCharAt(i + 1); | |
65ec6247 RD |
1049 | } else { |
1050 | if (isTag(i + 1, styler)) | |
1051 | state = SCE_L_TAG; | |
1052 | else | |
1053 | state = SCE_L_COMMAND; | |
f6bcfd97 BP |
1054 | } |
1055 | break; | |
65ec6247 RD |
1056 | case '$' : |
1057 | styler.ColourTo(i - 1, state); | |
1058 | state = SCE_L_MATH; | |
1059 | if (chNext == '$') { | |
1060 | i++; | |
1061 | chNext = styler.SafeGetCharAt(i + 1); | |
f6bcfd97 BP |
1062 | } |
1063 | break; | |
65ec6247 RD |
1064 | case '%' : |
1065 | styler.ColourTo(i - 1, state); | |
1066 | state = SCE_L_COMMENT; | |
1067 | break; | |
1068 | } | |
1069 | break; | |
1070 | case SCE_L_COMMAND : | |
1071 | if (chNext == '[' || chNext == '{' || chNext == '}' || | |
1072 | chNext == ' ' || chNext == '\r' || chNext == '\n') { | |
1073 | styler.ColourTo(i, state); | |
1074 | state = SCE_L_DEFAULT; | |
1075 | i++; | |
1076 | chNext = styler.SafeGetCharAt(i + 1); | |
1077 | } | |
1078 | break; | |
1079 | case SCE_L_TAG : | |
1080 | if (ch == '}') { | |
1081 | styler.ColourTo(i, state); | |
1082 | state = SCE_L_DEFAULT; | |
1083 | } | |
1084 | break; | |
1085 | case SCE_L_MATH : | |
1086 | if (ch == '$') { | |
1087 | if (chNext == '$') { | |
1088 | i++; | |
1089 | chNext = styler.SafeGetCharAt(i + 1); | |
f6bcfd97 | 1090 | } |
65ec6247 RD |
1091 | styler.ColourTo(i, state); |
1092 | state = SCE_L_DEFAULT; | |
1093 | } | |
1094 | break; | |
1095 | case SCE_L_COMMENT : | |
1096 | if (ch == '\r' || ch == '\n') { | |
1097 | styler.ColourTo(i - 1, state); | |
1098 | state = SCE_L_DEFAULT; | |
1099 | } | |
1100 | } | |
f6bcfd97 | 1101 | } |
9e730a78 | 1102 | styler.ColourTo(lengthDoc-1, state); |
f6bcfd97 BP |
1103 | } |
1104 | ||
9e730a78 RD |
1105 | static const char * const batchWordListDesc[] = { |
1106 | "Keywords", | |
1107 | 0 | |
1108 | }; | |
1109 | ||
1110 | static const char * const emptyWordListDesc[] = { | |
1111 | 0 | |
1112 | }; | |
1113 | ||
e14d10b0 RD |
1114 | static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[], |
1115 | Accessor &styler) { | |
1116 | // Null language means all style bytes are 0 so just mark the end - no need to fill in. | |
1117 | if (length > 0) { | |
1118 | styler.StartAt(startPos + length - 1); | |
1119 | styler.StartSegment(startPos + length - 1); | |
1120 | styler.ColourTo(startPos + length - 1, 0); | |
1121 | } | |
1122 | } | |
1123 | ||
9e730a78 | 1124 | LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc); |
591d01be | 1125 | LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc); |
88a8b04e | 1126 | LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc); |
9e730a78 RD |
1127 | LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc); |
1128 | LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc); | |
1129 | LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex", 0, emptyWordListDesc); | |
e14d10b0 | 1130 | LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null"); |