// Scintilla source code edit control /** @file LexOthers.cxx ** Lexers for batch files, diff results, properties files, make files and error lists. ** Also lexer for LaTeX documents. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" static bool Is0To9(char ch) { return (ch >= '0') && (ch <= '9'); } static bool Is1To9(char ch) { return (ch >= '1') && (ch <= '9'); } static inline bool AtEOL(Accessor &styler, unsigned int i) { return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); } static void ColouriseBatchLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, WordList &keywords, Accessor &styler) { unsigned int i = 0; unsigned int state = SCE_BAT_DEFAULT; while ((i < lengthLine) && isspacechar(lineBuffer[i])) { // Skip initial spaces i++; } if (lineBuffer[i] == '@') { // Hide command (ECHO OFF) styler.ColourTo(startLine + i, SCE_BAT_HIDE); i++; while ((i < lengthLine) && isspacechar(lineBuffer[i])) { // Skip next spaces i++; } } if (lineBuffer[i] == ':') { // Label if (lineBuffer[i + 1] == ':') { // :: is a fake label, similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm styler.ColourTo(endPos, SCE_BAT_COMMENT); } else { // Real label styler.ColourTo(endPos, SCE_BAT_LABEL); } } else { // Check if initial word is a keyword char wordBuffer[21]; unsigned int wbl = 0, offset = i; // Copy word in buffer for (; offset < lengthLine && wbl < 20 && !isspacechar(lineBuffer[offset]); wbl++, offset++) { wordBuffer[wbl] = static_cast(tolower(lineBuffer[offset])); } wordBuffer[wbl] = '\0'; // Check if it is a comment if (CompareCaseInsensitive(wordBuffer, "rem") == 0) { styler.ColourTo(endPos, SCE_BAT_COMMENT); return; } // Check if it is in the list if (keywords.InList(wordBuffer)) { styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); // Regular keyword } else { // Search end of word (can be a long path) while (offset < lengthLine && !isspacechar(lineBuffer[offset])) { offset++; } styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); // External command / program } // Remainder of the line: colourise the variables. while (offset < lengthLine) { if (state == SCE_BAT_DEFAULT && lineBuffer[offset] == '%') { styler.ColourTo(startLine + offset - 1, state); if (Is0To9(lineBuffer[offset + 1])) { styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER); offset += 2; } else if (lineBuffer[offset + 1] == '%' && !isspacechar(lineBuffer[offset + 2])) { // Should be safe, as there is CRLF at the end of the line... styler.ColourTo(startLine + offset + 2, SCE_BAT_IDENTIFIER); offset += 3; } else { state = SCE_BAT_IDENTIFIER; } } else if (state == SCE_BAT_IDENTIFIER && lineBuffer[offset] == '%') { styler.ColourTo(startLine + offset, state); state = SCE_BAT_DEFAULT; } else if (state == SCE_BAT_DEFAULT && (lineBuffer[offset] == '*' || lineBuffer[offset] == '?' || lineBuffer[offset] == '=' || lineBuffer[offset] == '<' || lineBuffer[offset] == '>' || lineBuffer[offset] == '|')) { styler.ColourTo(startLine + offset - 1, state); styler.ColourTo(startLine + offset, SCE_BAT_OPERATOR); } offset++; } // if (endPos > startLine + offset - 1) { styler.ColourTo(endPos, SCE_BAT_DEFAULT); // Remainder of line, currently not lexed // } } } // ToDo: (not necessarily at beginning of line) GOTO, [IF] NOT, ERRORLEVEL // IF [NO] (test) (command) -- test is EXIST (filename) | (string1)==(string2) | ERRORLEVEL (number) // FOR %%(variable) IN (set) DO (command) -- variable is [a-zA-Z] -- eg for %%X in (*.txt) do type %%X // ToDo: %n (parameters), %EnvironmentVariable% colourising // ToDo: Colourise = > >> < | " static void ColouriseBatchDoc( unsigned int startPos, int length, int /*initStyle*/, WordList *keywordlists[], Accessor &styler) { char lineBuffer[1024]; WordList &keywords = *keywordlists[0]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywords, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1, keywords, styler); } } static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) { // It is needed to remember the current state to recognize starting // comment lines before the first "diff " or "--- ". If a real // difference starts then each line starting with ' ' is a whitespace // otherwise it is considered a comment (Only in..., Binary file...) if (0 == strncmp(lineBuffer, "diff ", 5)) { styler.ColourTo(endLine, SCE_DIFF_COMMAND); } else if (0 == strncmp(lineBuffer, "--- ", 4)) { // In a context diff, --- appears in both the header and the position markers if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "+++ ", 4)) { // I don't know of any diff where "+++ " is a position marker, but for // consistency, do the same as with "--- " and "*** ". if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "====", 4)) { // For p4's diff styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "***", 3)) { // In a context diff, *** appears in both the header and the position markers. // Also ******** is a chunk header, but here it's treated as part of the // position marker since there is no separate style for a chunk header. if (lineBuffer[3] == ' ' && atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else if (lineBuffer[3] == '*') styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "? ", 2)) { // For difflib styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (lineBuffer[0] == '@') { styler.ColourTo(endLine, SCE_DIFF_POSITION); } else if (lineBuffer[0] >= '0' && lineBuffer[0] <= '9') { styler.ColourTo(endLine, SCE_DIFF_POSITION); } else if (lineBuffer[0] == '-' || lineBuffer[0] == '<') { styler.ColourTo(endLine, SCE_DIFF_DELETED); } else if (lineBuffer[0] == '+' || lineBuffer[0] == '>') { styler.ColourTo(endLine, SCE_DIFF_ADDED); } else if (lineBuffer[0] != ' ') { styler.ColourTo(endLine, SCE_DIFF_COMMENT); } else { styler.ColourTo(endLine, SCE_DIFF_DEFAULT); } } static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseDiffLine(lineBuffer, i, styler); linePos = 0; } } if (linePos > 0) { // Last line does not have ending characters ColouriseDiffLine(lineBuffer, startPos + length - 1, styler); } } static void FoldDiffDoc(unsigned int startPos, int length, int, WordList*[], Accessor &styler) { int curLine = styler.GetLine(startPos); int prevLevel = SC_FOLDLEVELBASE; if (curLine > 0) prevLevel = styler.LevelAt(curLine-1); int curLineStart = styler.LineStart(curLine); do { int nextLevel = prevLevel; if (prevLevel & SC_FOLDLEVELHEADERFLAG) nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1; int lineType = styler.StyleAt(curLineStart); if (lineType == SCE_DIFF_COMMAND) nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG; else if (lineType == SCE_DIFF_HEADER) { nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG; } else if (lineType == SCE_DIFF_POSITION) nextLevel = (SC_FOLDLEVELBASE + 3) | SC_FOLDLEVELHEADERFLAG; if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel)) styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG); styler.SetLevel(curLine, nextLevel); prevLevel = nextLevel; curLineStart = styler.LineStart(++curLine); } while (static_cast(startPos) + length > curLineStart); } static void ColourisePropsLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, Accessor &styler) { unsigned int i = 0; while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces i++; if (i < lengthLine) { if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') { styler.ColourTo(endPos, SCE_PROPS_COMMENT); } else if (lineBuffer[i] == '[') { styler.ColourTo(endPos, SCE_PROPS_SECTION); } else if (lineBuffer[i] == '@') { styler.ColourTo(startLine + i, SCE_PROPS_DEFVAL); if (lineBuffer[++i] == '=') styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT); styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } else { // Search for the '=' character while ((i < lengthLine) && (lineBuffer[i] != '=')) i++; if ((i < lengthLine) && (lineBuffer[i] == '=')) { styler.ColourTo(startLine + i - 1, SCE_PROPS_DEFAULT); styler.ColourTo(startLine + i, 3); styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } else { styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } } } else { styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } } static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColourisePropsLine(lineBuffer, linePos, startLine, i, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); } } // adaption by ksc, using the "} else {" trick of 1.53 // 030721 static void FoldPropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); bool headerPoint = false; int lev; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler[i+1]; int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_PROPS_SECTION) { headerPoint = true; } if (atEOL) { lev = SC_FOLDLEVELBASE; if (lineCurrent > 0) { int levelPrevious = styler.LevelAt(lineCurrent - 1); if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { lev = SC_FOLDLEVELBASE + 1; } else { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; } } if (headerPoint) { lev = SC_FOLDLEVELBASE; } if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (headerPoint) { lev |= SC_FOLDLEVELHEADERFLAG; } if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; visibleChars = 0; headerPoint = false; } if (!isspacechar(ch)) visibleChars++; } if (lineCurrent > 0) { int levelPrevious = styler.LevelAt(lineCurrent - 1); if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { lev = SC_FOLDLEVELBASE + 1; } else { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; } } else { lev = SC_FOLDLEVELBASE; } int flagsNext = styler.LevelAt(lineCurrent); styler.SetLevel(lineCurrent, lev | flagsNext & ~SC_FOLDLEVELNUMBERMASK); } static void ColouriseMakeLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, Accessor &styler) { unsigned int i = 0; int lastNonSpace = -1; unsigned int state = SCE_MAKE_DEFAULT; bool bSpecial = false; // Skip initial spaces while ((i < lengthLine) && isspacechar(lineBuffer[i])) { i++; } if (lineBuffer[i] == '#') { // Comment styler.ColourTo(endPos, SCE_MAKE_COMMENT); return; } if (lineBuffer[i] == '!') { // Special directive styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR); return; } while (i < lengthLine) { if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') { styler.ColourTo(startLine + i - 1, state); state = SCE_MAKE_IDENTIFIER; } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') { styler.ColourTo(startLine + i, state); state = SCE_MAKE_DEFAULT; } if (!bSpecial) { if (lineBuffer[i] == ':') { // We should check that no colouring was made since the beginning of the line, // to avoid colouring stuff like /OUT:file if (lastNonSpace >= 0) styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET); styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); bSpecial = true; // Only react to the first ':' of the line state = SCE_MAKE_DEFAULT; } else if (lineBuffer[i] == '=') { if (lastNonSpace >= 0) styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER); styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); bSpecial = true; // Only react to the first '=' of the line state = SCE_MAKE_DEFAULT; } } if (!isspacechar(lineBuffer[i])) { lastNonSpace = i; } i++; } if (state == SCE_MAKE_IDENTIFIER) { styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended } else { styler.ColourTo(endPos, SCE_MAKE_DEFAULT); } } static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); } } static bool strstart(const char *haystack, const char *needle) { return strncmp(haystack, needle, strlen(needle)) == 0; } static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine) { if (lineBuffer[0] == '>') { // Command or return status return SCE_ERR_CMD; } else if (lineBuffer[0] == '<') { // Diff removal, but not interested. Trapped to avoid hitting CTAG cases. return SCE_ERR_DEFAULT; } else if (lineBuffer[0] == '!') { return SCE_ERR_DIFF_CHANGED; } else if (lineBuffer[0] == '+') { return SCE_ERR_DIFF_ADDITION; } else if (lineBuffer[0] == '-' && lineBuffer[1] == '-' && lineBuffer[2] == '-') { return SCE_ERR_DIFF_MESSAGE; } else if (lineBuffer[0] == '-') { return SCE_ERR_DIFF_DELETION; } else if (strstart(lineBuffer, "cf90-")) { // Absoft Pro Fortran 90/95 v8.2 error and/or warning message return SCE_ERR_ABSF; } else if (strstart(lineBuffer, "fortcom:")) { // Intel Fortran Compiler v8.0 error/warning message return SCE_ERR_IFORT; } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) { return SCE_ERR_PYTHON; } else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) { return SCE_ERR_PHP; } else if ((strstart(lineBuffer, "Error ") || strstart(lineBuffer, "Warning ")) && strstr(lineBuffer, " at (") && strstr(lineBuffer, ") : ") && (strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) { // Intel Fortran Compiler error/warning message return SCE_ERR_IFC; } else if (strstart(lineBuffer, "Error ")) { // Borland error message return SCE_ERR_BORLAND; } else if (strstart(lineBuffer, "Warning ")) { // Borland warning message return SCE_ERR_BORLAND; } else if (strstr(lineBuffer, "at line " ) && (strstr(lineBuffer, "at line " ) < (lineBuffer + lengthLine)) && strstr(lineBuffer, "file ") && (strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) { // Lua 4 error message return SCE_ERR_LUA; } else if (strstr(lineBuffer, " at " ) && (strstr(lineBuffer, " at " ) < (lineBuffer + lengthLine)) && strstr(lineBuffer, " line ") && (strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) && (strstr(lineBuffer, " at " ) < (strstr(lineBuffer, " line ")))) { // perl error message return SCE_ERR_PERL; } else if ((memcmp(lineBuffer, " at ", 6) == 0) && strstr(lineBuffer, ":line ")) { // A .NET traceback return SCE_ERR_NET; } else if (strstart(lineBuffer, "Line ") && strstr(lineBuffer, ", file ")) { // Essential Lahey Fortran error message return SCE_ERR_ELF; } else if (strstart(lineBuffer, "line ") && strstr(lineBuffer, " column ")) { // HTML tidy style: line 42 column 1 return SCE_ERR_TIDY; } else if (strstart(lineBuffer, "\tat ") && strstr(lineBuffer, "(") && strstr(lineBuffer, ".java:")) { // Java stack back trace return SCE_ERR_JAVA_STACK; } else { // Look for one of the following formats: // GCC: :: // Microsoft: () : // Common: (): warning|error|note|remark|catastrophic|fatal // Common: () warning|error|note|remark|catastrophic|fatal // Microsoft: (,) // CTags: \t // Lua 5 traceback: \t:: bool initialTab = (lineBuffer[0] == '\t'); enum { stInitial, stGccStart, stGccDigit, stGcc, stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet, stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags, stUnrecognized } state = stInitial; for (unsigned int i = 0; i < lengthLine; i++) { char ch = lineBuffer[i]; char chNext = ' '; if ((i + 1) < lengthLine) chNext = lineBuffer[i + 1]; if (state == stInitial) { if (ch == ':') { // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix) if ((chNext != '\\') && (chNext != '/')) { // This check is not completely accurate as may be on // GTK+ with a file name that includes ':'. state = stGccStart; } } else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) { // May be Microsoft // Check against '0' often removes phone numbers state = stMsStart; } else if ((ch == '\t') && (!initialTab)) { // May be CTags state = stCtagsStart; } } else if (state == stGccStart) { // : state = Is1To9(ch) ? stGccDigit : stUnrecognized; } else if (state == stGccDigit) { // : if (ch == ':') { state = stGcc; // :9.*: is GCC break; } else if (!Is0To9(ch)) { state = stUnrecognized; } } else if (state == stMsStart) { // ( state = Is0To9(ch) ? stMsDigit : stUnrecognized; } else if (state == stMsDigit) { // ( if (ch == ',') { state = stMsDigitComma; } else if (ch == ')') { state = stMsBracket; } else if ((ch != ' ') && !Is0To9(ch)) { state = stUnrecognized; } } else if (state == stMsBracket) { // () if ((ch == ' ') && (chNext == ':')) { state = stMsVc; } else if ((ch == ':' && chNext == ' ') || (ch == ' ')) { // Possibly Delphi.. don't test against chNext as it's one of the strings below. char word[512]; unsigned int j, chPos; unsigned numstep; chPos = 0; if (ch == ' ') numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i. else numstep = 2; // otherwise add 2. for (j = i + numstep; j < lengthLine && isalpha(lineBuffer[j]) && chPos < sizeof(word) - 1; j++) word[chPos++] = lineBuffer[j]; word[chPos] = 0; if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") || !CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") || !CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) { state = stMsVc; } else state = stUnrecognized; } else { state = stUnrecognized; } } else if (state == stMsDigitComma) { // (, if (ch == ')') { state = stMsDotNet; break; } else if ((ch != ' ') && !Is0To9(ch)) { state = stUnrecognized; } } else if (state == stCtagsStart) { if ((lineBuffer[i - 1] == '\t') && ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) { state = stCtags; break; } else if ((ch == '/') && (lineBuffer[i + 1] == '^')) { state = stCtagsStartString; } } else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) { state = stCtagsStringDollar; break; } } if (state == stGcc) { return SCE_ERR_GCC; } else if ((state == stMsVc) || (state == stMsDotNet)) { return SCE_ERR_MS; } else if ((state == stCtagsStringDollar) || (state == stCtags)) { return SCE_ERR_CTAG; } else { return SCE_ERR_DEFAULT; } } } static void ColouriseErrorListLine( char *lineBuffer, unsigned int lengthLine, unsigned int endPos, Accessor &styler) { styler.ColourTo(endPos, RecogniseErrorListLine(lineBuffer, lengthLine)); } static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseErrorListLine(lineBuffer, linePos, i, styler); linePos = 0; } } if (linePos > 0) { // Last line does not have ending characters ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler); } } static int isSpecial(char s) { return (s == '\\') || (s == ',') || (s == ';') || (s == '\'') || (s == ' ') || (s == '\"') || (s == '`') || (s == '^') || (s == '~'); } static int isTag(int start, Accessor &styler) { char s[6]; unsigned int i = 0, e = 1; while (i < 5 && e) { s[i] = styler[start + i]; i++; e = styler[start + i] != '{'; } s[i] = '\0'; return (strcmp(s, "begin") == 0) || (strcmp(s, "end") == 0); } static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { styler.StartAt(startPos); int state = initStyle; char chNext = styler[startPos]; styler.StartSegment(startPos); int lengthDoc = startPos + length; for (int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); i++; continue; } switch (state) { case SCE_L_DEFAULT : switch (ch) { case '\\' : styler.ColourTo(i - 1, state); if (isSpecial(styler[i + 1])) { styler.ColourTo(i + 1, SCE_L_COMMAND); i++; chNext = styler.SafeGetCharAt(i + 1); } else { if (isTag(i + 1, styler)) state = SCE_L_TAG; else state = SCE_L_COMMAND; } break; case '$' : styler.ColourTo(i - 1, state); state = SCE_L_MATH; if (chNext == '$') { i++; chNext = styler.SafeGetCharAt(i + 1); } break; case '%' : styler.ColourTo(i - 1, state); state = SCE_L_COMMENT; break; } break; case SCE_L_COMMAND : if (chNext == '[' || chNext == '{' || chNext == '}' || chNext == ' ' || chNext == '\r' || chNext == '\n') { styler.ColourTo(i, state); state = SCE_L_DEFAULT; i++; chNext = styler.SafeGetCharAt(i + 1); } break; case SCE_L_TAG : if (ch == '}') { styler.ColourTo(i, state); state = SCE_L_DEFAULT; } break; case SCE_L_MATH : if (ch == '$') { if (chNext == '$') { i++; chNext = styler.SafeGetCharAt(i + 1); } styler.ColourTo(i, state); state = SCE_L_DEFAULT; } break; case SCE_L_COMMENT : if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, state); state = SCE_L_DEFAULT; } } } styler.ColourTo(lengthDoc-1, state); } static const char * const batchWordListDesc[] = { "Keywords", 0 }; static const char * const emptyWordListDesc[] = { 0 }; static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { // Null language means all style bytes are 0 so just mark the end - no need to fill in. if (length > 0) { styler.StartAt(startPos + length - 1); styler.StartSegment(startPos + length - 1); styler.ColourTo(startPos + length - 1, 0); } } LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc); LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc); LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc); LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc); LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc); LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex", 0, emptyWordListDesc); LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null");