]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexYAML.cxx
   1 // Scintilla source code edit control 
   5 // Copyright 2003- by Sean O'Dell <sean@celsoft.com> 
   6 // Release under the same license as Scintilla/SciTE. 
  18 #include "StyleContext.h" 
  20 #include "Scintilla.h" 
  23 static const char * const yamlWordListDesc
[] = { 
  28 static inline bool AtEOL(Accessor 
&styler
, unsigned int i
) { 
  29         return (styler
[i
] == '\n') || 
  30                 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i 
+ 1) != '\n')); 
  33 static unsigned int SpaceCount(char* lineBuffer
) { 
  34         if (lineBuffer 
== NULL
) 
  37         char* headBuffer 
= lineBuffer
; 
  39         while (*headBuffer 
== ' ') 
  42         return headBuffer 
- lineBuffer
; 
  45 #define YAML_STATE_BITSIZE 16 
  46 #define YAML_STATE_MASK                 (0xFFFF0000) 
  47 #define YAML_STATE_DOCUMENT             (1 << YAML_STATE_BITSIZE) 
  48 #define YAML_STATE_VALUE                        (2 << YAML_STATE_BITSIZE) 
  49 #define YAML_STATE_COMMENT              (3 << YAML_STATE_BITSIZE) 
  50 #define YAML_STATE_TEXT_PARENT  (4 << YAML_STATE_BITSIZE) 
  51 #define YAML_STATE_TEXT                 (5 << YAML_STATE_BITSIZE) 
  53 static void ColouriseYAMLLine( 
  55         unsigned int currentLine
, 
  56         unsigned int lengthLine
, 
  57         unsigned int startLine
, 
  63         bool bInQuotes 
= false; 
  64         unsigned int indentAmount 
= SpaceCount(lineBuffer
); 
  66         if (currentLine 
> 0) { 
  67                 int parentLineState 
= styler
.GetLineState(currentLine 
- 1); 
  69                 if ((parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT 
|| (parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT_PARENT
) { 
  70                         unsigned int parentIndentAmount 
= parentLineState
&(~YAML_STATE_MASK
); 
  71                         if (indentAmount 
> parentIndentAmount
) { 
  72                                 styler
.SetLineState(currentLine
, YAML_STATE_TEXT 
| parentIndentAmount
); 
  73                                 styler
.ColourTo(endPos
, SCE_YAML_TEXT
); 
  78         styler
.SetLineState(currentLine
, 0); 
  79         if (strncmp(lineBuffer
, "---", 3) == 0) {       // Document marker 
  80                 styler
.SetLineState(currentLine
, YAML_STATE_DOCUMENT
); 
  81                 styler
.ColourTo(endPos
, SCE_YAML_DOCUMENT
); 
  84         // Skip initial spaces 
  85         while ((i 
< lengthLine
) && lineBuffer
[i
] == ' ') { // YAML always uses space, never TABS or anything else 
  88         if (lineBuffer
[i
] == '\t') { // if we skipped all spaces, and we are NOT inside a text block, this is wrong 
  89                 styler
.ColourTo(endPos
, SCE_YAML_ERROR
); 
  92         if (lineBuffer
[i
] == '#') {     // Comment 
  93                 styler
.SetLineState(currentLine
, YAML_STATE_COMMENT
); 
  94                 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
); 
  97         while (i 
< lengthLine
) { 
  98                 if (lineBuffer
[i
] == '\'' || lineBuffer
[i
] == '\"') { 
  99                         bInQuotes 
= !bInQuotes
; 
 100                 } else if (lineBuffer
[i
] == ':' && !bInQuotes
) { 
 101                         styler
.ColourTo(startLine 
+ i
, SCE_YAML_IDENTIFIER
); 
 102                         // Non-folding scalar 
 104                         while ((i 
< lengthLine
) && isspacechar(lineBuffer
[i
])) 
 106                         unsigned int endValue 
= lengthLine 
- 1; 
 107                         while ((endValue 
>= i
) && isspacechar(lineBuffer
[endValue
])) 
 109                         lineBuffer
[endValue 
+ 1] = '\0'; 
 110                         if (lineBuffer
[i
] == '|' || lineBuffer
[i
] == '>') { 
 112                                 if (lineBuffer
[i
] == '+' || lineBuffer
[i
] == '-') 
 114                                 while ((i 
< lengthLine
) && isspacechar(lineBuffer
[i
])) 
 116                                 if (lineBuffer
[i
] == '\0') { 
 117                                         styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT 
| indentAmount
); 
 118                                         styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
); 
 120                                 } else if (lineBuffer
[i
] == '#') { 
 121                                         styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT 
| indentAmount
); 
 122                                         styler
.ColourTo(startLine 
+ i 
- 1, SCE_YAML_DEFAULT
); 
 123                                         styler
.ColourTo(endPos
, SCE_YAML_COMMENT
); 
 126                                         styler
.ColourTo(endPos
, SCE_YAML_ERROR
); 
 130                         styler
.SetLineState(currentLine
, YAML_STATE_VALUE
); 
 131                         if (lineBuffer
[i
] == '&' || lineBuffer
[i
] == '*') { 
 132                                 styler
.ColourTo(endPos
, SCE_YAML_REFERENCE
); 
 135                         if (keywords
.InList(&lineBuffer
[i
])) { // Convertible value (true/false, etc.) 
 136                                 styler
.ColourTo(endPos
, SCE_YAML_KEYWORD
); 
 140                                 while ((i 
< lengthLine
) && lineBuffer
[i
]) { 
 141                                         if (!isdigit(lineBuffer
[i
]) && lineBuffer
[i
] != '-' && lineBuffer
[i
] != '.' && lineBuffer
[i
] != ',') { 
 142                                                 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
); 
 148                                         styler
.ColourTo(endPos
, SCE_YAML_NUMBER
); 
 152                         break; // shouldn't get here, but just in case, the rest of the line is coloured the default 
 156         styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
); 
 159 static void ColouriseYAMLDoc(unsigned int startPos
, int length
, int, WordList 
*keywordLists
[], Accessor 
&styler
) { 
 160         char lineBuffer
[1024]; 
 161         styler
.StartAt(startPos
); 
 162         styler
.StartSegment(startPos
); 
 163         unsigned int linePos 
= 0; 
 164         unsigned int startLine 
= startPos
; 
 165         unsigned int endPos 
= startPos 
+ length
; 
 166         unsigned int maxPos 
= styler
.Length(); 
 167         unsigned int lineCurrent 
= styler
.GetLine(startPos
); 
 169         for (unsigned int i 
= startPos
; i 
< maxPos 
&& i 
< endPos
; i
++) { 
 170                 lineBuffer
[linePos
++] = styler
[i
]; 
 171                 if (AtEOL(styler
, i
) || (linePos 
>= sizeof(lineBuffer
) - 1)) { 
 172                         // End of line (or of line buffer) met, colourise it 
 173                         lineBuffer
[linePos
] = '\0'; 
 174                         ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, i
, *keywordLists
[0], styler
); 
 180         if (linePos 
> 0) {      // Last line does not have ending characters 
 181                 ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, startPos 
+ length 
- 1, *keywordLists
[0], styler
); 
 185 static bool IsCommentLine(int line
, Accessor 
&styler
) { 
 186         int pos 
= styler
.LineStart(line
); 
 187         if (styler
[pos
] == '#') 
 192 static void FoldYAMLDoc(unsigned int startPos
, int length
, int /*initStyle - unused*/, 
 193                       WordList 
*[], Accessor 
&styler
) { 
 194         const int maxPos 
= startPos 
+ length
; 
 195         const int maxLines 
= styler
.GetLine(maxPos 
- 1);             // Requested last line 
 196         const int docLines 
= styler
.GetLine(styler
.Length() - 1);  // Available last line 
 197         const bool foldComment 
= styler
.GetPropertyInt("fold.comment.yaml") != 0; 
 199         // Backtrack to previous non-blank line so we can determine indent level 
 200         // for any white space lines 
 201         // and so we can fix any preceding fold level (which is why we go back 
 202         // at least one line in all cases) 
 204         int lineCurrent 
= styler
.GetLine(startPos
); 
 205         int indentCurrent 
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
); 
 206         while (lineCurrent 
> 0) { 
 208                 indentCurrent 
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
); 
 209                 if (!(indentCurrent 
& SC_FOLDLEVELWHITEFLAG
) && 
 210                         (!IsCommentLine(lineCurrent
, styler
))) 
 213         int indentCurrentLevel 
= indentCurrent 
& SC_FOLDLEVELNUMBERMASK
; 
 215         // Set up initial loop state 
 217         if (lineCurrent 
>= 1) 
 218                 prevComment 
= foldComment 
&& IsCommentLine(lineCurrent 
- 1, styler
); 
 220         // Process all characters to end of requested range 
 221         // or comment that hangs over the end of the range.  Cap processing in all cases 
 222         // to end of document (in case of unclosed comment at end). 
 223         while ((lineCurrent 
<= docLines
) && ((lineCurrent 
<= maxLines
) || prevComment
)) { 
 226                 int lev 
= indentCurrent
; 
 227                 int lineNext 
= lineCurrent 
+ 1; 
 228                 int indentNext 
= indentCurrent
; 
 229                 if (lineNext 
<= docLines
) { 
 230                         // Information about next line is only available if not at end of document 
 231                         indentNext 
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
); 
 233                 const int comment 
= foldComment 
&& IsCommentLine(lineCurrent
, styler
); 
 234                 const int comment_start 
= (comment 
&& !prevComment 
&& (lineNext 
<= docLines
) && 
 235                                            IsCommentLine(lineNext
, styler
) && (lev 
> SC_FOLDLEVELBASE
)); 
 236                 const int comment_continue 
= (comment 
&& prevComment
); 
 238                         indentCurrentLevel 
= indentCurrent 
& SC_FOLDLEVELNUMBERMASK
; 
 239                 if (indentNext 
& SC_FOLDLEVELWHITEFLAG
) 
 240                         indentNext 
= SC_FOLDLEVELWHITEFLAG 
| indentCurrentLevel
; 
 243                         // Place fold point at start of a block of comments 
 244                         lev 
|= SC_FOLDLEVELHEADERFLAG
; 
 245                 } else if (comment_continue
) { 
 246                         // Add level to rest of lines in the block 
 250                 // Skip past any blank lines for next indent level info; we skip also 
 251                 // comments (all comments, not just those starting in column 0) 
 252                 // which effectively folds them into surrounding code rather 
 253                 // than screwing up folding. 
 255                 while ((lineNext 
< docLines
) && 
 256                         ((indentNext 
& SC_FOLDLEVELWHITEFLAG
) || 
 257                          (lineNext 
<= docLines 
&& IsCommentLine(lineNext
, styler
)))) { 
 260                         indentNext 
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
); 
 263                 const int levelAfterComments 
= indentNext 
& SC_FOLDLEVELNUMBERMASK
; 
 264                 const int levelBeforeComments 
= Platform::Maximum(indentCurrentLevel
,levelAfterComments
); 
 266                 // Now set all the indent levels on the lines we skipped 
 267                 // Do this from end to start.  Once we encounter one line 
 268                 // which is indented more than the line after the end of 
 269                 // the comment-block, use the level of the block before 
 271                 int skipLine 
= lineNext
; 
 272                 int skipLevel 
= levelAfterComments
; 
 274                 while (--skipLine 
> lineCurrent
) { 
 275                         int skipLineIndent 
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
); 
 277                         if ((skipLineIndent 
& SC_FOLDLEVELNUMBERMASK
) > levelAfterComments
) 
 278                                 skipLevel 
= levelBeforeComments
; 
 280                         int whiteFlag 
= skipLineIndent 
& SC_FOLDLEVELWHITEFLAG
; 
 282                         styler
.SetLevel(skipLine
, skipLevel 
| whiteFlag
); 
 285                 // Set fold header on non-comment line 
 286                 if (!comment 
&& !(indentCurrent 
& SC_FOLDLEVELWHITEFLAG
) ) { 
 287                         if ((indentCurrent 
& SC_FOLDLEVELNUMBERMASK
) < (indentNext 
& SC_FOLDLEVELNUMBERMASK
)) 
 288                                 lev 
|= SC_FOLDLEVELHEADERFLAG
; 
 291                 // Keep track of block comment state of previous line 
 292                 prevComment 
= comment_start 
|| comment_continue
; 
 294                 // Set fold level for this line and move to next line 
 295                 styler
.SetLevel(lineCurrent
, lev
); 
 296                 indentCurrent 
= indentNext
; 
 297                 lineCurrent 
= lineNext
; 
 300         // NOTE: Cannot set level of last line here because indentCurrent doesn't have 
 301         // header flag set; the loop above is crafted to take care of this case! 
 302         //styler.SetLevel(lineCurrent, indentCurrent); 
 305 LexerModule 
lmYAML(SCLEX_YAML
, ColouriseYAMLDoc
, "yaml", FoldYAMLDoc
, yamlWordListDesc
);