diff options
author | nyamatongwe <unknown> | 2003-09-27 01:22:05 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2003-09-27 01:22:05 +0000 |
commit | abdf78a3f59883cbe716d673b963068d602a220b (patch) | |
tree | 06348549358cd6d1c664eb0cd0faa3f175696ce9 /src | |
parent | 2a126445d41d00d240ac6d00136db5bdb0772917 (diff) | |
download | scintilla-mirror-abdf78a3f59883cbe716d673b963068d602a220b.tar.gz |
Updated YAML lexer.
Diffstat (limited to 'src')
-rw-r--r-- | src/LexYAML.cxx | 308 |
1 files changed, 215 insertions, 93 deletions
diff --git a/src/LexYAML.cxx b/src/LexYAML.cxx index 156ca279d..e3053f814 100644 --- a/src/LexYAML.cxx +++ b/src/LexYAML.cxx @@ -9,11 +9,13 @@ #include <string.h> #include <ctype.h> #include <stdio.h> +#include <stdarg.h> #include "Platform.h" #include "PropSet.h" #include "Accessor.h" +#include "StyleContext.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" @@ -28,68 +30,126 @@ static inline bool AtEOL(Accessor &styler, unsigned int i) { ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); } -static void ColouriseYAMLLine( - char *lineBuffer, - unsigned int lengthLine, - unsigned int startLine, - unsigned int endPos, - WordList &keywords, - Accessor &styler) { +static unsigned int SpaceCount(char* lineBuffer) { + if (lineBuffer == NULL) + return 0; + + char* headBuffer = lineBuffer; + + while (*headBuffer == ' ') + headBuffer++; + + return headBuffer - lineBuffer; +} +#define YAML_STATE_BITSIZE 16 +#define YAML_STATE_MASK (0xFFFF0000) +#define YAML_STATE_DOCUMENT (1 << YAML_STATE_BITSIZE) +#define YAML_STATE_VALUE (2 << YAML_STATE_BITSIZE) +#define YAML_STATE_COMMENT (3 << YAML_STATE_BITSIZE) +#define YAML_STATE_TEXT_PARENT (4 << YAML_STATE_BITSIZE) +#define YAML_STATE_TEXT (5 << YAML_STATE_BITSIZE) + +static void ColouriseYAMLLine( + char *lineBuffer, + unsigned int currentLine, + unsigned int lengthLine, + unsigned int startLine, + unsigned int endPos, + WordList &keywords, + Accessor &styler) { + unsigned int i = 0; bool bInQuotes = false; - unsigned int startValue, endValue, valueLen; - char scalar[256]; - if (lineBuffer[0] == '#') { // Comment - styler.ColourTo(endPos, SCE_YAML_COMMENT); - return; + unsigned int indentAmount = SpaceCount(lineBuffer); + + if (currentLine > 0) { + int parentLineState = styler.GetLineState(currentLine - 1); + + if ((parentLineState&YAML_STATE_MASK) == YAML_STATE_TEXT || (parentLineState&YAML_STATE_MASK) == YAML_STATE_TEXT_PARENT) { + unsigned int parentIndentAmount = parentLineState&(~YAML_STATE_MASK); + if (indentAmount > parentIndentAmount) { + styler.SetLineState(currentLine, YAML_STATE_TEXT | parentIndentAmount); + styler.ColourTo(endPos, SCE_YAML_TEXT); + return; + } + } } + styler.SetLineState(currentLine, 0); if (strncmp(lineBuffer, "---", 3) == 0) { // Document marker + styler.SetLineState(currentLine, YAML_STATE_DOCUMENT); styler.ColourTo(endPos, SCE_YAML_DOCUMENT); return; } // Skip initial spaces - while ((i < lengthLine) && isspacechar(lineBuffer[i])) { + while ((i < lengthLine) && lineBuffer[i] == ' ') { // YAML always uses space, never TABS or anything else i++; } + if (lineBuffer[i] == '\t') { // if we skipped all spaces, and we are NOT inside a text block, this is wrong + styler.ColourTo(endPos, SCE_YAML_ERROR); + return; + } + if (lineBuffer[i] == '#') { // Comment + styler.SetLineState(currentLine, YAML_STATE_COMMENT); + styler.ColourTo(endPos, SCE_YAML_COMMENT); + return; + } while (i < lengthLine) { if (lineBuffer[i] == '\'' || lineBuffer[i] == '\"') { bInQuotes = !bInQuotes; } else if (lineBuffer[i] == ':' && !bInQuotes) { styler.ColourTo(startLine + i, SCE_YAML_IDENTIFIER); // Non-folding scalar - startValue = i + 1; - while ((startValue < lengthLine) && isspacechar(lineBuffer[startValue])) { - startValue++; - } - endValue = lengthLine - 1; - while ((endValue >= startValue) && isspacechar(lineBuffer[endValue])) { + i++; + while ((i < lengthLine) && isspacechar(lineBuffer[i])) + i++; + unsigned int endValue = lengthLine - 1; + while ((endValue >= i) && isspacechar(lineBuffer[endValue])) endValue--; + lineBuffer[endValue + 1] = '\0'; + if (lineBuffer[i] == '|' || lineBuffer[i] == '>') { + i++; + if (lineBuffer[i] == '+' || lineBuffer[i] == '-') + i++; + while ((i < lengthLine) && isspacechar(lineBuffer[i])) + i++; + if (lineBuffer[i] == '\0') { + styler.SetLineState(currentLine, YAML_STATE_TEXT_PARENT | indentAmount); + styler.ColourTo(endPos, SCE_YAML_DEFAULT); + return; + } else if (lineBuffer[i] == '#') { + styler.SetLineState(currentLine, YAML_STATE_TEXT_PARENT | indentAmount); + styler.ColourTo(startLine + i - 1, SCE_YAML_DEFAULT); + styler.ColourTo(endPos, SCE_YAML_COMMENT); + return; + } else { + styler.ColourTo(endPos, SCE_YAML_ERROR); + return; + } } - valueLen = endValue - startValue + 1; - if (endValue < startValue || valueLen > sizeof(scalar)) { - break; - } - strncpy(scalar, &lineBuffer[startValue], valueLen); - scalar[valueLen] = '\0'; - if (scalar[0] == '&' || scalar[0] == '*') { - styler.ColourTo(startLine + endValue, SCE_YAML_REFERENCE); + styler.SetLineState(currentLine, YAML_STATE_VALUE); + if (lineBuffer[i] == '&' || lineBuffer[i] == '*') { + styler.ColourTo(endPos, SCE_YAML_REFERENCE); + return; } - else if (keywords.InList(scalar)) { // Convertible value (true/false, etc.) - styler.ColourTo(startLine + endValue, SCE_YAML_KEYWORD); + if (keywords.InList(&lineBuffer[i])) { // Convertible value (true/false, etc.) + styler.ColourTo(endPos, SCE_YAML_KEYWORD); + return; } else { - startValue = 0; - while (startValue < valueLen) { - if (!isdigit(scalar[startValue]) && scalar[startValue] != '-' && scalar[startValue] != '.' && scalar[startValue] != ',') { - break; + unsigned int i2 = i; + while ((i < lengthLine) && lineBuffer[i]) { + if (!isdigit(lineBuffer[i]) && lineBuffer[i] != '-' && lineBuffer[i] != '.' && lineBuffer[i] != ',') { + styler.ColourTo(endPos, SCE_YAML_DEFAULT); + return; } - startValue++; + i++; } - if (startValue >= valueLen) { - styler.ColourTo(startLine + endValue, SCE_YAML_NUMBER); + if (i > i2) { + styler.ColourTo(endPos, SCE_YAML_NUMBER); + return; } } - break; // the rest of the line is coloured the default + break; // shouldn't get here, but just in case, the rest of the line is coloured the default } i++; } @@ -102,82 +162,144 @@ static void ColouriseYAMLDoc(unsigned int startPos, int length, int, WordList *k styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; - for (unsigned int i = startPos; i < startPos + length; i++) { + unsigned int endPos = startPos + length; + unsigned int maxPos = styler.Length(); + unsigned int lineCurrent = styler.GetLine(startPos); + + for (unsigned int i = startPos; i < maxPos && i < endPos; 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'; - ColouriseYAMLLine(lineBuffer, linePos, startLine, i, *keywordLists[0], styler); + ColouriseYAMLLine(lineBuffer, lineCurrent, linePos, startLine, i, *keywordLists[0], styler); linePos = 0; startLine = i + 1; + lineCurrent++; } } if (linePos > 0) { // Last line does not have ending characters - ColouriseYAMLLine(lineBuffer, linePos, startLine, startPos + length - 1, *keywordLists[0], styler); + ColouriseYAMLLine(lineBuffer, lineCurrent, linePos, startLine, startPos + length - 1, *keywordLists[0], styler); } } -static int IdentifierLevelYAMLLine( - char *lineBuffer, - unsigned int lengthLine) { +static bool IsCommentLine(int line, Accessor &styler) { + int pos = styler.LineStart(line); + if (styler[pos] == '#') + return true; + return false; +} - unsigned int i = 0; - bool bInQuotes = false; - int level; - if (lineBuffer[0] == '#') { // Comment - return 0xFFFFFFFF; - } - if (strncmp(lineBuffer, "---", 3) == 0) { // Document marker - return 0; +static void FoldYAMLDoc(unsigned int startPos, int length, int /*initStyle - unused*/, + WordList *[], Accessor &styler) { + const int maxPos = startPos + length; + const int maxLines = styler.GetLine(maxPos - 1); // Requested last line + const int docLines = styler.GetLine(styler.Length() - 1); // Available last line + const bool foldComment = styler.GetPropertyInt("fold.comment.yaml") != 0; + + // Backtrack to previous non-blank line so we can determine indent level + // for any white space lines + // and so we can fix any preceding fold level (which is why we go back + // at least one line in all cases) + int spaceFlags = 0; + int lineCurrent = styler.GetLine(startPos); + int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); + while (lineCurrent > 0) { + lineCurrent--; + indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) && + (!IsCommentLine(lineCurrent, styler))) + break; } - // Count initial spaces and '-' character - while ((i < lengthLine) && (isspacechar(lineBuffer[i]) || lineBuffer[i] == '-')) { - i++; + int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; + + // Set up initial loop state + int prevComment = 0; + if (lineCurrent >= 1) + prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler); + + // Process all characters to end of requested range + // or comment that hangs over the end of the range. Cap processing in all cases + // to end of document (in case of unclosed comment at end). + while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevComment)) { + + // Gather info + int lev = indentCurrent; + int lineNext = lineCurrent + 1; + int indentNext = indentCurrent; + if (lineNext <= docLines) { + // Information about next line is only available if not at end of document + indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); } - level = i; - while (i < lengthLine) { - if (lineBuffer[i] == '\'' || lineBuffer[i] == '\"') { - bInQuotes = !bInQuotes; - } else if (lineBuffer[i] == ':' && !bInQuotes) { - return level; + const int comment = foldComment && IsCommentLine(lineCurrent, styler); + const int comment_start = (comment && !prevComment && (lineNext <= docLines) && + IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE)); + const int comment_continue = (comment && prevComment); + if (!comment) + indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; + if (indentNext & SC_FOLDLEVELWHITEFLAG) + indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel; + + if (comment_start) { + // Place fold point at start of a block of comments + lev |= SC_FOLDLEVELHEADERFLAG; + } else if (comment_continue) { + // Add level to rest of lines in the block + lev = lev + 1; } - i++; - } - return -level; // Scalar -} -static void FoldYAMLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { - char lineBuffer[1024]; - styler.StartAt(startPos); - styler.StartSegment(startPos); - unsigned int linePos = 0; - int currentLevel; - int lastLevel = 0xFFFFFFFF; - unsigned int lineCurrent = 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'; - currentLevel = IdentifierLevelYAMLLine(lineBuffer, linePos); - if (currentLevel != static_cast<int>(0xFFFFFFFF)) { - if (abs(currentLevel) > abs(lastLevel) && lastLevel >= 0) { // indented higher than last, and last was an identifier line - styler.SetLevel(lineCurrent - 1, SC_FOLDLEVELHEADERFLAG); - } - lastLevel = currentLevel; - } - linePos = 0; - lineCurrent++; + // Skip past any blank lines for next indent level info; we skip also + // comments (all comments, not just those starting in column 0) + // which effectively folds them into surrounding code rather + // than screwing up folding. + + while ((lineNext < docLines) && + ((indentNext & SC_FOLDLEVELWHITEFLAG) || + (lineNext <= docLines && IsCommentLine(lineNext, styler)))) { + + lineNext++; + indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); } - } - if (linePos > 0) { // Last line does not have ending characters - currentLevel = IdentifierLevelYAMLLine(lineBuffer, linePos); - if (currentLevel != static_cast<int>(0xFFFFFFFF)) { - if (abs(currentLevel) > abs(lastLevel) && lastLevel >= 0) { - styler.SetLevel(lineCurrent - 1, SC_FOLDLEVELHEADERFLAG); - } + + const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK; + const int levelBeforeComments = Platform::Maximum(indentCurrentLevel,levelAfterComments); + + // Now set all the indent levels on the lines we skipped + // Do this from end to start. Once we encounter one line + // which is indented more than the line after the end of + // the comment-block, use the level of the block before + + int skipLine = lineNext; + int skipLevel = levelAfterComments; + + while (--skipLine > lineCurrent) { + int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL); + + if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments) + skipLevel = levelBeforeComments; + + int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG; + + styler.SetLevel(skipLine, skipLevel | whiteFlag); + } + + // Set fold header on non-comment line + if (!comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) { + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) + lev |= SC_FOLDLEVELHEADERFLAG; } + + // Keep track of block comment state of previous line + prevComment = comment_start || comment_continue; + + // Set fold level for this line and move to next line + styler.SetLevel(lineCurrent, lev); + indentCurrent = indentNext; + lineCurrent = lineNext; } + + // NOTE: Cannot set level of last line here because indentCurrent doesn't have + // header flag set; the loop above is crafted to take care of this case! + //styler.SetLevel(lineCurrent, indentCurrent); } LexerModule lmYAML(SCLEX_YAML, ColouriseYAMLDoc, "yaml", FoldYAMLDoc, yamlWordListDesc); |