50
59
unsigned int lengthLine,
51
60
unsigned int startLine,
52
61
unsigned int endPos,
62
WordList *keywordlists[],
54
63
Accessor &styler) {
56
65
unsigned int offset = 0; // Line Buffer Offset
57
unsigned int enVarEnd; // Environment Variable End point
58
66
unsigned int cmdLoc; // External Command / Program Location
59
67
char wordBuffer[81]; // Word Buffer - large to catch long paths
60
68
unsigned int wbl; // Word Buffer Length
61
69
unsigned int wbo; // Word Buffer Offset - also Special Keyword Buffer Length
62
bool forFound = false; // No Local Variable without FOR statement
70
WordList &keywords = *keywordlists[0]; // Internal Commands
71
WordList &keywords2 = *keywordlists[1]; // External Commands (optional)
63
73
// CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords
64
74
// Toggling Regular Keyword Checking off improves readability
65
75
// Other Regular Keywords and External Commands / Programs might also benefit from toggling
105
115
if (lineBuffer[offset] == '@') {
106
116
styler.ColourTo(startLine + offset, SCE_BAT_HIDE);
108
// Check for Argument (%n) or Environment Variable (%x...%)
109
} else if (lineBuffer[offset] == '%') {
110
enVarEnd = offset + 1;
111
// Search end of word for second % (can be a long path)
112
while ((enVarEnd < lengthLine) &&
113
(!isspacechar(lineBuffer[enVarEnd])) &&
114
(lineBuffer[enVarEnd] != '%') &&
115
(!IsBOperator(lineBuffer[enVarEnd])) &&
116
(!IsBSeparator(lineBuffer[enVarEnd]))) {
119
// Check for Argument (%n)
120
if ((Is0To9(lineBuffer[offset + 1])) &&
121
(lineBuffer[enVarEnd] != '%')) {
123
styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER);
125
// Check for External Command / Program
126
if (!isspacechar(lineBuffer[offset])) {
129
// Check for Environment Variable (%x...%)
130
} else if ((lineBuffer[offset + 1] != '%') &&
131
(lineBuffer[enVarEnd] == '%')) {
133
// Colorize Environment Variable
134
styler.ColourTo(startLine + offset, SCE_BAT_IDENTIFIER);
136
// Check for External Command / Program
137
if (!isspacechar(lineBuffer[offset])) {
142
119
// Skip next spaces
143
120
while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) {
174
151
// Reset Offset to re-process remainder of word
175
152
offset -= (wbl - 1);
176
153
// Colorize External Command / Program
177
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
155
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
156
} else if (keywords2.InList(wordBuffer)) {
157
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
159
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
178
161
// Reset External Command / Program Location
309
// Colorize External command / program
310
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
290
// Colorize External Command / Program
292
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
293
} else if (keywords2.InList(wordBuffer)) {
294
styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND);
296
styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT);
311
298
// No need to Reset Offset
312
299
// Check for Default Text
314
301
// Read up to %, Operator or Separator
315
302
while ((wbo < wbl) &&
316
303
(wordBuffer[wbo] != '%') &&
304
(wordBuffer[wbo] != '!') &&
317
305
(!IsBOperator(wordBuffer[wbo])) &&
318
306
(!IsBSeparator(wordBuffer[wbo]))) {
347
335
styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER);
348
336
// Reset Offset to re-process remainder of word
349
337
offset -= (wbl - 2);
338
// Check for Expanded Argument (%~...) / Variable (%%~...)
339
} else if (((wbl > 1) && (wordBuffer[1] == '~')) ||
340
((wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] == '~'))) {
341
// Check for External Command / Program
342
if (cmdLoc == offset - wbl) {
343
cmdLoc = offset - (wbl - wbo);
345
// Colorize Expanded Argument / Variable
346
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
347
// Reset Offset to re-process remainder of word
348
offset -= (wbl - wbo);
350
349
// Check for Environment Variable (%x...%)
351
350
} else if ((wordBuffer[1] != '%') &&
352
351
(wordBuffer[wbo] == '%')) {
354
353
// Check for External Command / Program
355
354
if (cmdLoc == offset - wbl) {
356
355
cmdLoc = offset - (wbl - wbo);
358
357
// Colorize Environment Variable
359
358
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
360
359
// Reset Offset to re-process remainder of word
361
360
offset -= (wbl - wbo);
362
361
// Check for Local Variable (%%a)
363
} else if ((forFound) &&
364
364
(wordBuffer[1] == '%') &&
365
365
(wordBuffer[2] != '%') &&
366
366
(!IsBOperator(wordBuffer[2])) &&
374
374
// Reset Offset to re-process remainder of word
375
375
offset -= (wbl - 3);
377
// Check for Environment Variable (!x...!)
378
} else if (wordBuffer[0] == '!') {
379
// Colorize Default Text
380
styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT);
382
// Search to end of word for second ! (can be a long path)
383
while ((wbo < wbl) &&
384
(wordBuffer[wbo] != '!') &&
385
(!IsBOperator(wordBuffer[wbo])) &&
386
(!IsBSeparator(wordBuffer[wbo]))) {
389
if (wordBuffer[wbo] == '!') {
391
// Check for External Command / Program
392
if (cmdLoc == offset - wbl) {
393
cmdLoc = offset - (wbl - wbo);
395
// Colorize Environment Variable
396
styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER);
397
// Reset Offset to re-process remainder of word
398
offset -= (wbl - wbo);
377
400
// Check for Operator
378
401
} else if (IsBOperator(wordBuffer[0])) {
379
402
// Colorize Default Text
458
481
if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
459
482
// End of line (or of line buffer) met, colourise it
460
483
lineBuffer[linePos] = '\0';
461
ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywords, styler);
484
ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywordlists, styler);
463
486
startLine = i + 1;
466
489
if (linePos > 0) { // Last line does not have ending characters
490
lineBuffer[linePos] = '\0';
467
491
ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1,
492
keywordlists, styler);
476
500
// otherwise it is considered a comment (Only in..., Binary file...)
477
501
if (0 == strncmp(lineBuffer, "diff ", 5)) {
478
502
styler.ColourTo(endLine, SCE_DIFF_COMMAND);
479
} else if (0 == strncmp(lineBuffer, "--- ", 4)) {
503
} else if (0 == strncmp(lineBuffer, "Index: ", 7)) { // For subversion's diff
504
styler.ColourTo(endLine, SCE_DIFF_COMMAND);
505
} else if (0 == strncmp(lineBuffer, "---", 3)) {
480
506
// In a context diff, --- appears in both the header and the position markers
481
if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/'))
507
if (lineBuffer[3] == ' ' && atoi(lineBuffer + 4) && !strchr(lineBuffer, '/'))
508
styler.ColourTo(endLine, SCE_DIFF_POSITION);
509
else if (lineBuffer[3] == '\r' || lineBuffer[3] == '\n')
482
510
styler.ColourTo(endLine, SCE_DIFF_POSITION);
484
512
styler.ColourTo(endLine, SCE_DIFF_HEADER);
540
static void FoldDiffDoc(unsigned int startPos, int length, int, WordList*[], Accessor &styler) {
570
static void FoldDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
541
571
int curLine = styler.GetLine(startPos);
542
int prevLevel = SC_FOLDLEVELBASE;
544
prevLevel = styler.LevelAt(curLine-1);
546
572
int curLineStart = styler.LineStart(curLine);
573
int prevLevel = curLine > 0 ? styler.LevelAt(curLine - 1) : SC_FOLDLEVELBASE;
548
int nextLevel = prevLevel;
549
if (prevLevel & SC_FOLDLEVELHEADERFLAG)
550
nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1;
552
577
int lineType = styler.StyleAt(curLineStart);
553
578
if (lineType == SCE_DIFF_COMMAND)
579
nextLevel = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
580
else if (lineType == SCE_DIFF_HEADER)
554
581
nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG;
555
else if (lineType == SCE_DIFF_HEADER) {
582
else if (lineType == SCE_DIFF_POSITION && styler[curLineStart] != '-')
556
583
nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG;
557
} else if (lineType == SCE_DIFF_POSITION)
558
nextLevel = (SC_FOLDLEVELBASE + 3) | SC_FOLDLEVELHEADERFLAG;
584
else if (prevLevel & SC_FOLDLEVELHEADERFLAG)
585
nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1;
587
nextLevel = prevLevel;
560
589
if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel))
561
590
styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG);
567
596
} while (static_cast<int>(startPos) + length > curLineStart);
599
static void ColourisePoLine(
601
unsigned int lengthLine,
602
unsigned int startLine,
607
static unsigned int state = SCE_PO_DEFAULT;
608
unsigned int state_start = SCE_PO_DEFAULT;
610
while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces
612
if (i < lengthLine) {
613
if (lineBuffer[i] == '#') {
614
// check if the comment contains any flags ("#, ") and
615
// then whether the flags contain "fuzzy"
616
if (strstart(lineBuffer, "#, ") && strstr(lineBuffer, "fuzzy"))
617
styler.ColourTo(endPos, SCE_PO_FUZZY);
619
styler.ColourTo(endPos, SCE_PO_COMMENT);
621
if (lineBuffer[0] == '"') {
622
// line continuation, use previous style
623
styler.ColourTo(endPos, state);
625
// this implicitly also matches "msgid_plural"
626
} else if (strstart(lineBuffer, "msgid")) {
627
state_start = SCE_PO_MSGID;
628
state = SCE_PO_MSGID_TEXT;
629
} else if (strstart(lineBuffer, "msgstr")) {
630
state_start = SCE_PO_MSGSTR;
631
state = SCE_PO_MSGSTR_TEXT;
632
} else if (strstart(lineBuffer, "msgctxt")) {
633
state_start = SCE_PO_MSGCTXT;
634
state = SCE_PO_MSGCTXT_TEXT;
636
if (state_start != SCE_PO_DEFAULT) {
637
// find the next space
638
while ((i < lengthLine) && ! isspacechar(lineBuffer[i]))
640
styler.ColourTo(startLine + i - 1, state_start);
641
styler.ColourTo(startLine + i, SCE_PO_DEFAULT);
642
styler.ColourTo(endPos, state);
646
styler.ColourTo(endPos, SCE_PO_DEFAULT);
650
static void ColourisePoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
651
char lineBuffer[1024];
652
styler.StartAt(startPos);
653
styler.StartSegment(startPos);
654
unsigned int linePos = 0;
655
unsigned int startLine = startPos;
656
for (unsigned int i = startPos; i < startPos + length; i++) {
657
lineBuffer[linePos++] = styler[i];
658
if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
659
// End of line (or of line buffer) met, colourise it
660
lineBuffer[linePos] = '\0';
661
ColourisePoLine(lineBuffer, linePos, startLine, i, styler);
666
if (linePos > 0) { // Last line does not have ending characters
667
ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);
671
static inline bool isassignchar(unsigned char ch) {
672
return (ch == '=') || (ch == ':');
571
675
static void ColourisePropsLine(
572
676
char *lineBuffer,
573
677
unsigned int lengthLine,
574
678
unsigned int startLine,
575
679
unsigned int endPos,
681
bool allowInitialSpaces) {
578
683
unsigned int i = 0;
579
while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces
684
if (allowInitialSpaces) {
685
while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces
688
if (isspacechar(lineBuffer[i])) // don't allow initial spaces
581
692
if (i < lengthLine) {
582
693
if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') {
583
694
styler.ColourTo(endPos, SCE_PROPS_COMMENT);
585
696
styler.ColourTo(endPos, SCE_PROPS_SECTION);
586
697
} else if (lineBuffer[i] == '@') {
587
698
styler.ColourTo(startLine + i, SCE_PROPS_DEFVAL);
588
if (lineBuffer[++i] == '=')
699
if (isassignchar(lineBuffer[i++]))
589
700
styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT);
590
701
styler.ColourTo(endPos, SCE_PROPS_DEFAULT);
592
703
// Search for the '=' character
593
while ((i < lengthLine) && (lineBuffer[i] != '='))
704
while ((i < lengthLine) && !isassignchar(lineBuffer[i]))
595
if ((i < lengthLine) && (lineBuffer[i] == '=')) {
596
styler.ColourTo(startLine + i - 1, SCE_PROPS_DEFAULT);
597
styler.ColourTo(startLine + i, 3);
706
if ((i < lengthLine) && isassignchar(lineBuffer[i])) {
707
styler.ColourTo(startLine + i - 1, SCE_PROPS_KEY);
708
styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT);
598
709
styler.ColourTo(endPos, SCE_PROPS_DEFAULT);
600
711
styler.ColourTo(endPos, SCE_PROPS_DEFAULT);
611
722
styler.StartSegment(startPos);
612
723
unsigned int linePos = 0;
613
724
unsigned int startLine = startPos;
726
// property lexer.props.allow.initial.spaces
727
// For properties files, set to 0 to style all lines that start with whitespace in the default style.
728
// This is not suitable for SciTE .properties files which use indentation for flow control but
729
// can be used for RFC2822 text where indentation is used for continuation lines.
730
bool allowInitialSpaces = styler.GetPropertyInt("lexer.props.allow.initial.spaces", 1) != 0;
614
732
for (unsigned int i = startPos; i < startPos + length; i++) {
615
733
lineBuffer[linePos++] = styler[i];
616
734
if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
617
735
// End of line (or of line buffer) met, colourise it
618
736
lineBuffer[linePos] = '\0';
619
ColourisePropsLine(lineBuffer, linePos, startLine, i, styler);
737
ColourisePropsLine(lineBuffer, linePos, startLine, i, styler, allowInitialSpaces);
621
739
startLine = i + 1;
624
742
if (linePos > 0) { // Last line does not have ending characters
625
ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler);
743
ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler, allowInitialSpaces);
731
855
styler.ColourTo(startLine + i, state);
732
856
state = SCE_MAKE_DEFAULT;
859
// skip identifier and target styling if this is a command line
860
if (!bSpecial && !bCommand) {
735
861
if (lineBuffer[i] == ':') {
736
// We should check that no colouring was made since the beginning of the line,
737
// to avoid colouring stuff like /OUT:file
738
if (lastNonSpace >= 0)
739
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);
740
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
741
styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
862
if (((i + 1) < lengthLine) && (lineBuffer[i + 1] == '=')) {
863
// it's a ':=', so style as an identifier
864
if (lastNonSpace >= 0)
865
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER);
866
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
867
styler.ColourTo(startLine + i + 1, SCE_MAKE_OPERATOR);
869
// We should check that no colouring was made since the beginning of the line,
870
// to avoid colouring stuff like /OUT:file
871
if (lastNonSpace >= 0)
872
styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET);
873
styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT);
874
styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR);
742
876
bSpecial = true; // Only react to the first ':' of the line
743
877
state = SCE_MAKE_DEFAULT;
744
878
} else if (lineBuffer[i] == '=') {
870
1000
// Microsoft: <filename>(<line>,<column>)<message>
871
1001
// CTags: \t<message>
872
1002
// Lua 5 traceback: \t<filename>:<line>:<message>
1003
// Lua 5.1: <exe>: <filename>:<line>:<message>
873
1004
bool initialTab = (lineBuffer[0] == '\t');
1005
bool initialColonPart = false;
875
1007
stGccStart, stGccDigit, stGcc,
876
1008
stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet,
877
1009
stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags,
933
1068
for (j = i + numstep; j < lengthLine && isalpha(lineBuffer[j]) && chPos < sizeof(word) - 1; j++)
934
1069
word[chPos++] = lineBuffer[j];
935
1070
word[chPos] = 0;
936
if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") ||
937
!CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") ||
1071
if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") ||
1072
!CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") ||
938
1073
!CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) {
978
1113
char *lineBuffer,
979
1114
unsigned int lengthLine,
980
1115
unsigned int endPos,
982
styler.ColourTo(endPos, RecogniseErrorListLine(lineBuffer, lengthLine));
1117
bool valueSeparate) {
1118
int startValue = -1;
1119
int style = RecogniseErrorListLine(lineBuffer, lengthLine, startValue);
1120
if (valueSeparate && (startValue >= 0)) {
1121
styler.ColourTo(endPos - (lengthLine - startValue), style);
1122
styler.ColourTo(endPos, SCE_ERR_VALUE);
1124
styler.ColourTo(endPos, style);
985
1128
static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
987
1130
styler.StartAt(startPos);
988
1131
styler.StartSegment(startPos);
989
1132
unsigned int linePos = 0;
1134
// property lexer.errorlist.value.separate
1135
// For lines in the output pane that are matches from Find in Files or GCC-style
1136
// diagnostics, style the path and line number separately from the rest of the
1137
// line with style 21 used for the rest of the line.
1138
// This allows matched text to be more easily distinguished from its location.
1139
bool valueSeparate = styler.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;
990
1140
for (unsigned int i = startPos; i < startPos + length; i++) {
991
1141
lineBuffer[linePos++] = styler[i];
992
1142
if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
993
1143
// End of line (or of line buffer) met, colourise it
994
1144
lineBuffer[linePos] = '\0';
995
ColouriseErrorListLine(lineBuffer, linePos, i, styler);
1145
ColouriseErrorListLine(lineBuffer, linePos, i, styler, valueSeparate);
999
1149
if (linePos > 0) { // Last line does not have ending characters
1000
ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler);
1150
ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler, valueSeparate);
1124
1275
LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc);
1125
1276
LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc);
1277
LexerModule lmPo(SCLEX_PO, ColourisePoDoc, "po", 0, emptyWordListDesc);
1126
1278
LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc);
1127
1279
LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc);
1128
1280
LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc);