aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornyamatongwe <unknown>2003-09-27 01:22:05 +0000
committernyamatongwe <unknown>2003-09-27 01:22:05 +0000
commitabdf78a3f59883cbe716d673b963068d602a220b (patch)
tree06348549358cd6d1c664eb0cd0faa3f175696ce9
parent2a126445d41d00d240ac6d00136db5bdb0772917 (diff)
downloadscintilla-mirror-abdf78a3f59883cbe716d673b963068d602a220b.tar.gz
Updated YAML lexer.
-rw-r--r--src/LexYAML.cxx308
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);