PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Tools/MaterialEditor/wxscintilla_1.69.2/src/scintilla/src/LexYAML.cxx

https://bitbucket.org/CaptainOz/ogre
C++ | 305 lines | 232 code | 38 blank | 35 comment | 102 complexity | 95fd53b9ada7da6059017ad898623e66 MD5 | raw file
Possible License(s): LGPL-2.1, MIT
  1. // Scintilla source code edit control
  2. /** @file LexYAML.cxx
  3. ** Lexer for YAML.
  4. **/
  5. // Copyright 2003- by Sean O'Dell <sean@celsoft.com>
  6. // Release under the same license as Scintilla/SciTE.
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include "Platform.h"
  13. #include "PropSet.h"
  14. #include "Accessor.h"
  15. #include "StyleContext.h"
  16. #include "KeyWords.h"
  17. #include "Scintilla.h"
  18. #include "SciLexer.h"
  19. static const char * const yamlWordListDesc[] = {
  20. "Keywords",
  21. 0
  22. };
  23. static inline bool AtEOL(Accessor &styler, unsigned int i) {
  24. return (styler[i] == '\n') ||
  25. ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
  26. }
  27. static unsigned int SpaceCount(char* lineBuffer) {
  28. if (lineBuffer == NULL)
  29. return 0;
  30. char* headBuffer = lineBuffer;
  31. while (*headBuffer == ' ')
  32. headBuffer++;
  33. return headBuffer - lineBuffer;
  34. }
  35. #define YAML_STATE_BITSIZE 16
  36. #define YAML_STATE_MASK (0xFFFF0000)
  37. #define YAML_STATE_DOCUMENT (1 << YAML_STATE_BITSIZE)
  38. #define YAML_STATE_VALUE (2 << YAML_STATE_BITSIZE)
  39. #define YAML_STATE_COMMENT (3 << YAML_STATE_BITSIZE)
  40. #define YAML_STATE_TEXT_PARENT (4 << YAML_STATE_BITSIZE)
  41. #define YAML_STATE_TEXT (5 << YAML_STATE_BITSIZE)
  42. static void ColouriseYAMLLine(
  43. char *lineBuffer,
  44. unsigned int currentLine,
  45. unsigned int lengthLine,
  46. unsigned int startLine,
  47. unsigned int endPos,
  48. WordList &keywords,
  49. Accessor &styler) {
  50. unsigned int i = 0;
  51. bool bInQuotes = false;
  52. unsigned int indentAmount = SpaceCount(lineBuffer);
  53. if (currentLine > 0) {
  54. int parentLineState = styler.GetLineState(currentLine - 1);
  55. if ((parentLineState&YAML_STATE_MASK) == YAML_STATE_TEXT || (parentLineState&YAML_STATE_MASK) == YAML_STATE_TEXT_PARENT) {
  56. unsigned int parentIndentAmount = parentLineState&(~YAML_STATE_MASK);
  57. if (indentAmount > parentIndentAmount) {
  58. styler.SetLineState(currentLine, YAML_STATE_TEXT | parentIndentAmount);
  59. styler.ColourTo(endPos, SCE_YAML_TEXT);
  60. return;
  61. }
  62. }
  63. }
  64. styler.SetLineState(currentLine, 0);
  65. if (strncmp(lineBuffer, "---", 3) == 0) { // Document marker
  66. styler.SetLineState(currentLine, YAML_STATE_DOCUMENT);
  67. styler.ColourTo(endPos, SCE_YAML_DOCUMENT);
  68. return;
  69. }
  70. // Skip initial spaces
  71. while ((i < lengthLine) && lineBuffer[i] == ' ') { // YAML always uses space, never TABS or anything else
  72. i++;
  73. }
  74. if (lineBuffer[i] == '\t') { // if we skipped all spaces, and we are NOT inside a text block, this is wrong
  75. styler.ColourTo(endPos, SCE_YAML_ERROR);
  76. return;
  77. }
  78. if (lineBuffer[i] == '#') { // Comment
  79. styler.SetLineState(currentLine, YAML_STATE_COMMENT);
  80. styler.ColourTo(endPos, SCE_YAML_COMMENT);
  81. return;
  82. }
  83. while (i < lengthLine) {
  84. if (lineBuffer[i] == '\'' || lineBuffer[i] == '\"') {
  85. bInQuotes = !bInQuotes;
  86. } else if (lineBuffer[i] == ':' && !bInQuotes) {
  87. styler.ColourTo(startLine + i, SCE_YAML_IDENTIFIER);
  88. // Non-folding scalar
  89. i++;
  90. while ((i < lengthLine) && isspacechar(lineBuffer[i]))
  91. i++;
  92. unsigned int endValue = lengthLine - 1;
  93. while ((endValue >= i) && isspacechar(lineBuffer[endValue]))
  94. endValue--;
  95. lineBuffer[endValue + 1] = '\0';
  96. if (lineBuffer[i] == '|' || lineBuffer[i] == '>') {
  97. i++;
  98. if (lineBuffer[i] == '+' || lineBuffer[i] == '-')
  99. i++;
  100. while ((i < lengthLine) && isspacechar(lineBuffer[i]))
  101. i++;
  102. if (lineBuffer[i] == '\0') {
  103. styler.SetLineState(currentLine, YAML_STATE_TEXT_PARENT | indentAmount);
  104. styler.ColourTo(endPos, SCE_YAML_DEFAULT);
  105. return;
  106. } else if (lineBuffer[i] == '#') {
  107. styler.SetLineState(currentLine, YAML_STATE_TEXT_PARENT | indentAmount);
  108. styler.ColourTo(startLine + i - 1, SCE_YAML_DEFAULT);
  109. styler.ColourTo(endPos, SCE_YAML_COMMENT);
  110. return;
  111. } else {
  112. styler.ColourTo(endPos, SCE_YAML_ERROR);
  113. return;
  114. }
  115. }
  116. styler.SetLineState(currentLine, YAML_STATE_VALUE);
  117. if (lineBuffer[i] == '&' || lineBuffer[i] == '*') {
  118. styler.ColourTo(endPos, SCE_YAML_REFERENCE);
  119. return;
  120. }
  121. if (keywords.InList(&lineBuffer[i])) { // Convertible value (true/false, etc.)
  122. styler.ColourTo(endPos, SCE_YAML_KEYWORD);
  123. return;
  124. } else {
  125. unsigned int i2 = i;
  126. while ((i < lengthLine) && lineBuffer[i]) {
  127. if (!isdigit(lineBuffer[i]) && lineBuffer[i] != '-' && lineBuffer[i] != '.' && lineBuffer[i] != ',') {
  128. styler.ColourTo(endPos, SCE_YAML_DEFAULT);
  129. return;
  130. }
  131. i++;
  132. }
  133. if (i > i2) {
  134. styler.ColourTo(endPos, SCE_YAML_NUMBER);
  135. return;
  136. }
  137. }
  138. break; // shouldn't get here, but just in case, the rest of the line is coloured the default
  139. }
  140. i++;
  141. }
  142. styler.ColourTo(endPos, SCE_YAML_DEFAULT);
  143. }
  144. static void ColouriseYAMLDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) {
  145. char lineBuffer[1024];
  146. styler.StartAt(startPos);
  147. styler.StartSegment(startPos);
  148. unsigned int linePos = 0;
  149. unsigned int startLine = startPos;
  150. unsigned int endPos = startPos + length;
  151. unsigned int maxPos = styler.Length();
  152. unsigned int lineCurrent = styler.GetLine(startPos);
  153. for (unsigned int i = startPos; i < maxPos && i < endPos; i++) {
  154. lineBuffer[linePos++] = styler[i];
  155. if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
  156. // End of line (or of line buffer) met, colourise it
  157. lineBuffer[linePos] = '\0';
  158. ColouriseYAMLLine(lineBuffer, lineCurrent, linePos, startLine, i, *keywordLists[0], styler);
  159. linePos = 0;
  160. startLine = i + 1;
  161. lineCurrent++;
  162. }
  163. }
  164. if (linePos > 0) { // Last line does not have ending characters
  165. ColouriseYAMLLine(lineBuffer, lineCurrent, linePos, startLine, startPos + length - 1, *keywordLists[0], styler);
  166. }
  167. }
  168. static bool IsCommentLine(int line, Accessor &styler) {
  169. int pos = styler.LineStart(line);
  170. if (styler[pos] == '#')
  171. return true;
  172. return false;
  173. }
  174. static void FoldYAMLDoc(unsigned int startPos, int length, int /*initStyle - unused*/,
  175. WordList *[], Accessor &styler) {
  176. const int maxPos = startPos + length;
  177. const int maxLines = styler.GetLine(maxPos - 1); // Requested last line
  178. const int docLines = styler.GetLine(styler.Length() - 1); // Available last line
  179. const bool foldComment = styler.GetPropertyInt("fold.comment.yaml") != 0;
  180. // Backtrack to previous non-blank line so we can determine indent level
  181. // for any white space lines
  182. // and so we can fix any preceding fold level (which is why we go back
  183. // at least one line in all cases)
  184. int spaceFlags = 0;
  185. int lineCurrent = styler.GetLine(startPos);
  186. int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
  187. while (lineCurrent > 0) {
  188. lineCurrent--;
  189. indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
  190. if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) &&
  191. (!IsCommentLine(lineCurrent, styler)))
  192. break;
  193. }
  194. int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
  195. // Set up initial loop state
  196. int prevComment = 0;
  197. if (lineCurrent >= 1)
  198. prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);
  199. // Process all characters to end of requested range
  200. // or comment that hangs over the end of the range. Cap processing in all cases
  201. // to end of document (in case of unclosed comment at end).
  202. while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevComment)) {
  203. // Gather info
  204. int lev = indentCurrent;
  205. int lineNext = lineCurrent + 1;
  206. int indentNext = indentCurrent;
  207. if (lineNext <= docLines) {
  208. // Information about next line is only available if not at end of document
  209. indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
  210. }
  211. const int comment = foldComment && IsCommentLine(lineCurrent, styler);
  212. const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&
  213. IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE));
  214. const int comment_continue = (comment && prevComment);
  215. if (!comment)
  216. indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
  217. if (indentNext & SC_FOLDLEVELWHITEFLAG)
  218. indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
  219. if (comment_start) {
  220. // Place fold point at start of a block of comments
  221. lev |= SC_FOLDLEVELHEADERFLAG;
  222. } else if (comment_continue) {
  223. // Add level to rest of lines in the block
  224. lev = lev + 1;
  225. }
  226. // Skip past any blank lines for next indent level info; we skip also
  227. // comments (all comments, not just those starting in column 0)
  228. // which effectively folds them into surrounding code rather
  229. // than screwing up folding.
  230. while ((lineNext < docLines) &&
  231. ((indentNext & SC_FOLDLEVELWHITEFLAG) ||
  232. (lineNext <= docLines && IsCommentLine(lineNext, styler)))) {
  233. lineNext++;
  234. indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
  235. }
  236. const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK;
  237. const int levelBeforeComments = Platform::Maximum(indentCurrentLevel,levelAfterComments);
  238. // Now set all the indent levels on the lines we skipped
  239. // Do this from end to start. Once we encounter one line
  240. // which is indented more than the line after the end of
  241. // the comment-block, use the level of the block before
  242. int skipLine = lineNext;
  243. int skipLevel = levelAfterComments;
  244. while (--skipLine > lineCurrent) {
  245. int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL);
  246. if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)
  247. skipLevel = levelBeforeComments;
  248. int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
  249. styler.SetLevel(skipLine, skipLevel | whiteFlag);
  250. }
  251. // Set fold header on non-comment line
  252. if (!comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) {
  253. if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
  254. lev |= SC_FOLDLEVELHEADERFLAG;
  255. }
  256. // Keep track of block comment state of previous line
  257. prevComment = comment_start || comment_continue;
  258. // Set fold level for this line and move to next line
  259. styler.SetLevel(lineCurrent, lev);
  260. indentCurrent = indentNext;
  261. lineCurrent = lineNext;
  262. }
  263. // NOTE: Cannot set level of last line here because indentCurrent doesn't have
  264. // header flag set; the loop above is crafted to take care of this case!
  265. //styler.SetLevel(lineCurrent, indentCurrent);
  266. }
  267. LexerModule lmYAML(SCLEX_YAML, ColouriseYAMLDoc, "yaml", FoldYAMLDoc, yamlWordListDesc);