diff options
author | nyamatongwe <unknown> | 2005-07-22 05:29:46 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2005-07-22 05:29:46 +0000 |
commit | 43145f3a9376e1d729ac6b8c15992c0b0ef9843d (patch) | |
tree | 0c648d6948363d0f32b057276941326e8da5a521 | |
parent | 13711e0199f918f700406727d9f26cb7b6f7932b (diff) | |
download | scintilla-mirror-43145f3a9376e1d729ac6b8c15992c0b0ef9843d.tar.gz |
Patch from Steve Menard improves batch file lexing, recognizing more
builtin syntax.
-rw-r--r-- | doc/ScintillaHistory.html | 1 | ||||
-rw-r--r-- | src/LexOthers.cxx | 442 |
2 files changed, 376 insertions, 67 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index e95f080e4..8a04361e6 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -206,6 +206,7 @@ <li>Ben Harper</li> <li>Adam Strzelecki</li> <li>Kamen Stanev</li> + <li>Steve Menard</li> </ul> <p> Images used in GTK+ version diff --git a/src/LexOthers.cxx b/src/LexOthers.cxx index 4ad58495a..662b36308 100644 --- a/src/LexOthers.cxx +++ b/src/LexOthers.cxx @@ -33,6 +33,18 @@ static inline bool AtEOL(Accessor &styler, unsigned int i) { ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); } +// Tests for BATCH Operators +static bool IsBOperator(char ch) { + return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || + (ch == '|') || (ch == '?') || (ch == '*'); +} + +// Tests for BATCH Separators +static bool IsBSeparator(char ch) { + return (ch == ':') || (ch == '\\') || (ch == '.') || (ch == ';') || + (ch == '\"') || (ch == '\'') || (ch == '/') || (ch == ')'); +} + static void ColouriseBatchLine( char *lineBuffer, unsigned int lengthLine, @@ -41,95 +53,391 @@ static void ColouriseBatchLine( WordList &keywords, Accessor &styler) { - unsigned int i = 0; - unsigned int state = SCE_BAT_DEFAULT; + unsigned int offset = 0; // Line Buffer Offset + unsigned int enVarEnd; // Environment Variable End point + unsigned int cmdLoc; // External Command / Program Location + char wordBuffer[81]; // Word Buffer - large to catch long paths + unsigned int wbl; // Word Buffer Length + unsigned int wbo; // Word Buffer Offset - also Special Keyword Buffer Length + bool forFound = false; // No Local Variable without FOR statement + // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords + // Toggling Regular Keyword Checking off improves readability + // Other Regular Keywords and External Commands / Programs might also benefit from toggling + // Need a more robust algorithm to properly toggle Regular Keyword Checking + bool continueProcessing = true; // Used to toggle Regular Keyword Checking + // Special Keywords are those that allow certain characters without whitespace after the command + // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path= + // Special Keyword Buffer used to determine if the first n characters is a Keyword + char sKeywordBuffer[10]; // Special Keyword Buffer + bool sKeywordFound; // Exit Special Keyword for-loop if found - 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++; - } + // Skip initial spaces + while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { + offset++; } - 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 + // Colorize Default Text + styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); + // Set External Command / Program Location + cmdLoc = offset; + + // Check for Fake Label (Comment) or Real Label - return if found + if (lineBuffer[offset] == ':') { + if (lineBuffer[offset + 1] == ':') { + // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm styler.ColourTo(endPos, SCE_BAT_COMMENT); - } else { // Real label + } else { + // Colorize 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 && + return; + // Check for Drive Change (Drive Change is internal command) - return if found + } else if ((isalpha(lineBuffer[offset])) && + (lineBuffer[offset + 1] == ':') && + ((isspacechar(lineBuffer[offset + 2])) || + (((lineBuffer[offset + 2] == '\\')) && + (isspacechar(lineBuffer[offset + 3]))))) { + // Colorize Regular Keyword + styler.ColourTo(endPos, SCE_BAT_WORD); + return; + } + + // Check for Hide Command (@ECHO OFF/ON) + if (lineBuffer[offset] == '@') { + styler.ColourTo(startLine + offset, SCE_BAT_HIDE); + offset++; + // Check for Argument (%n) or Environment Variable (%x...%) + } else if (lineBuffer[offset] == '%') { + enVarEnd = offset + 1; + // Search end of word for second % (can be a long path) + while ((enVarEnd < lengthLine) && + (!isspacechar(lineBuffer[enVarEnd])) && + (lineBuffer[enVarEnd] != '%') && + (!IsBOperator(lineBuffer[enVarEnd])) && + (!IsBSeparator(lineBuffer[enVarEnd]))) { + enVarEnd++; + } + // Check for Argument (%n) + if ((Is0To9(lineBuffer[offset + 1])) && + (lineBuffer[enVarEnd] != '%')) { + // Colorize Argument + styler.ColourTo(startLine + offset + 1, SCE_BAT_IDENTIFIER); + offset += 2; + // Check for External Command / Program + if (!isspacechar(lineBuffer[offset])) { + cmdLoc = offset; + } + // Check for Environment Variable (%x...%) + } else if ((lineBuffer[offset + 1] != '%') && + (lineBuffer[enVarEnd] == '%')) { + offset = enVarEnd; + // Colorize Environment Variable + styler.ColourTo(startLine + offset, SCE_BAT_IDENTIFIER); + offset++; + // Check for External Command / Program + if (!isspacechar(lineBuffer[offset])) { + cmdLoc = offset; + } + } + } + // Skip next spaces + while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { + offset++; + } + + // Read remainder of line word-at-a-time or remainder-of-word-at-a-time + while (offset < lengthLine) { + if (offset > startLine) { + // Colorize Default Text + styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); + } + // Copy word from Line Buffer into Word Buffer + wbl = 0; + for (; offset < lengthLine && wbl < 80 && !isspacechar(lineBuffer[offset]); wbl++, offset++) { wordBuffer[wbl] = static_cast<char>(tolower(lineBuffer[offset])); } wordBuffer[wbl] = '\0'; - // Check if it is a comment + wbo = 0; + + // Check for Comment - return if found 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++; + // Check for Separator + if (IsBSeparator(wordBuffer[0])) { + // Check for External Command / Program + if ((cmdLoc == offset - wbl) && + ((wordBuffer[0] == ':') || + (wordBuffer[0] == '\\') || + (wordBuffer[0] == '.'))) { + // Reset Offset to re-process remainder of word + offset -= (wbl - 1); + // Colorize External Command / Program + styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); + // Reset External Command / Program Location + cmdLoc = offset; + } else { + // Reset Offset to re-process remainder of word + offset -= (wbl - 1); + // Colorize Default Text + styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); + } + // Check for Regular Keyword in list + } else if ((keywords.InList(wordBuffer)) && + (continueProcessing)) { + // Local Variables do not exist if no FOR statement + if (CompareCaseInsensitive(wordBuffer, "for") == 0) { + forFound = true; + } + // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking + if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) || + (CompareCaseInsensitive(wordBuffer, "goto") == 0) || + (CompareCaseInsensitive(wordBuffer, "prompt") == 0) || + (CompareCaseInsensitive(wordBuffer, "set") == 0)) { + continueProcessing = false; + } + // Identify External Command / Program Location for ERRORLEVEL, and EXIST + if ((CompareCaseInsensitive(wordBuffer, "errorlevel") == 0) || + (CompareCaseInsensitive(wordBuffer, "exist") == 0)) { + // Reset External Command / Program Location + cmdLoc = offset; + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Skip comparison + while ((cmdLoc < lengthLine) && + (!isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH + } else if ((CompareCaseInsensitive(wordBuffer, "call") == 0) || + (CompareCaseInsensitive(wordBuffer, "do") == 0) || + (CompareCaseInsensitive(wordBuffer, "loadhigh") == 0) || + (CompareCaseInsensitive(wordBuffer, "lh") == 0)) { + // Reset External Command / Program Location + cmdLoc = offset; + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + } + // Colorize Regular keyword + styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); + // No need to Reset Offset + // Check for Special Keyword in list, External Command / Program, or Default Text + } else if ((wordBuffer[0] != '%') && + (!IsBOperator(wordBuffer[0])) && + (continueProcessing)) { + // Check for Special Keyword + // Affected Commands are in Length range 2-6 + // Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected + sKeywordFound = false; + for (unsigned int keywordLength = 2; keywordLength < wbl && keywordLength < 7 && !sKeywordFound; keywordLength++) { + wbo = 0; + // Copy Keyword Length from Word Buffer into Special Keyword Buffer + for (; wbo < keywordLength; wbo++) { + sKeywordBuffer[wbo] = static_cast<char>(wordBuffer[wbo]); + } + sKeywordBuffer[wbo] = '\0'; + // Check for Special Keyword in list + if ((keywords.InList(sKeywordBuffer)) && + ((IsBOperator(wordBuffer[wbo])) || + (IsBSeparator(wordBuffer[wbo])))) { + sKeywordFound = true; + // ECHO requires no further Regular Keyword Checking + if (CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) { + continueProcessing = false; + } + // Colorize Special Keyword as Regular Keyword + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD); + // Reset Offset to re-process remainder of word + offset -= (wbl - wbo); } - 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; + // Check for External Command / Program or Default Text + if (!sKeywordFound) { + wbo = 0; + // Check for External Command / Program + if (cmdLoc == offset - wbl) { + // Read up to %, Operator or Separator + while ((wbo < wbl) && + (wordBuffer[wbo] != '%') && + (!IsBOperator(wordBuffer[wbo])) && + (!IsBSeparator(wordBuffer[wbo]))) { + wbo++; + } + // Reset External Command / Program Location + cmdLoc = offset - (wbl - wbo); + // Reset Offset to re-process remainder of word + offset -= (wbl - wbo); + // CHOICE requires no further Regular Keyword Checking + if (CompareCaseInsensitive(wordBuffer, "choice") == 0) { + continueProcessing = false; + } + // Check for START (and its switches) - What follows is External Command \ Program + if (CompareCaseInsensitive(wordBuffer, "start") == 0) { + // Reset External Command / Program Location + cmdLoc = offset; + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Reset External Command / Program Location if command switch detected + if (lineBuffer[cmdLoc] == '/') { + // Skip command switch + while ((cmdLoc < lengthLine) && + (!isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + } + } + // Colorize External command / program + styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); + // No need to Reset Offset + // Check for Default Text } else { - state = SCE_BAT_IDENTIFIER; + // Read up to %, Operator or Separator + while ((wbo < wbl) && + (wordBuffer[wbo] != '%') && + (!IsBOperator(wordBuffer[wbo])) && + (!IsBSeparator(wordBuffer[wbo]))) { + wbo++; + } + // Colorize Default Text + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); + // Reset Offset to re-process remainder of word + offset -= (wbl - wbo); } - } 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); } + // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a) + } else if (wordBuffer[0] == '%') { + // Colorize Default Text + styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); + wbo++; + // Search to end of word for second % (can be a long path) + while ((wbo < wbl) && + (wordBuffer[wbo] != '%') && + (!IsBOperator(wordBuffer[wbo])) && + (!IsBSeparator(wordBuffer[wbo]))) { + wbo++; + } + // Check for Argument (%n) + if ((Is0To9(wordBuffer[1])) && + (wordBuffer[wbo] != '%')) { + // Check for External Command / Program + if (cmdLoc == offset - wbl) { + cmdLoc = offset - (wbl - 2); + } + // Colorize Argument + styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER); + // Reset Offset to re-process remainder of word + offset -= (wbl - 2); + // Check for Environment Variable (%x...%) + } else if ((wordBuffer[1] != '%') && + (wordBuffer[wbo] == '%')) { + wbo++; + // Check for External Command / Program + if (cmdLoc == offset - wbl) { + cmdLoc = offset - (wbl - wbo); + } + // Colorize Environment Variable + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); + // Reset Offset to re-process remainder of word + offset -= (wbl - wbo); + // Check for Local Variable (%%a) + } else if ((forFound) && + (wordBuffer[1] == '%') && + (wordBuffer[2] != '%') && + (!IsBOperator(wordBuffer[2])) && + (!IsBSeparator(wordBuffer[2]))) { + // Check for External Command / Program + if (cmdLoc == offset - wbl) { + cmdLoc = offset - (wbl - 3); + } + // Colorize Local Variable + styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER); + // Reset Offset to re-process remainder of word + offset -= (wbl - 3); + } + // Check for Operator + } else if (IsBOperator(wordBuffer[0])) { + // Colorize Default Text + styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); + // Check for Comparison Operator + if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) { + // Identify External Command / Program Location for IF + cmdLoc = offset; + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Colorize Comparison Operator + styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR); + // Reset Offset to re-process remainder of word + offset -= (wbl - 2); + // Check for Pipe Operator + } else if (wordBuffer[0] == '|') { + // Reset External Command / Program Location + cmdLoc = offset - wbl + 1; + // Skip next spaces + while ((cmdLoc < lengthLine) && + (isspacechar(lineBuffer[cmdLoc]))) { + cmdLoc++; + } + // Colorize Pipe Operator + styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); + // Reset Offset to re-process remainder of word + offset -= (wbl - 1); + // Check for Other Operator + } else { + // Check for > Operator + if (wordBuffer[0] == '>') { + // Turn Keyword and External Command / Program checking back on + continueProcessing = true; + } + // Colorize Other Operator + styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); + // Reset Offset to re-process remainder of word + offset -= (wbl - 1); + } + // Check for Default Text + } else { + // Read up to %, Operator or Separator + while ((wbo < wbl) && + (wordBuffer[wbo] != '%') && + (!IsBOperator(wordBuffer[wbo])) && + (!IsBSeparator(wordBuffer[wbo]))) { + wbo++; + } + // Colorize Default Text + styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); + // Reset Offset to re-process remainder of word + offset -= (wbl - wbo); + } + // Skip next spaces - nothing happens if Offset was Reset + while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } - // if (endPos > startLine + offset - 1) { - styler.ColourTo(endPos, SCE_BAT_DEFAULT); // Remainder of line, currently not lexed - // } } - + // Colorize Default Text for remainder of line - currently not lexed + styler.ColourTo(endPos, SCE_BAT_DEFAULT); } -// 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, |