]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexYAML.cxx
1 // Scintilla source code edit control
5 // Copyright 2003- by Sean O'Dell <sean@celsoft.com>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #include "Scintilla.h"
20 #include "LexAccessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
27 using namespace Scintilla
;
30 static const char * const yamlWordListDesc
[] = {
35 static inline bool AtEOL(Accessor
&styler
, unsigned int i
) {
36 return (styler
[i
] == '\n') ||
37 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n'));
40 static unsigned int SpaceCount(char* lineBuffer
) {
41 if (lineBuffer
== NULL
)
44 char* headBuffer
= lineBuffer
;
46 while (*headBuffer
== ' ')
49 return headBuffer
- lineBuffer
;
52 #define YAML_STATE_BITSIZE 16
53 #define YAML_STATE_MASK (0xFFFF0000)
54 #define YAML_STATE_DOCUMENT (1 << YAML_STATE_BITSIZE)
55 #define YAML_STATE_VALUE (2 << YAML_STATE_BITSIZE)
56 #define YAML_STATE_COMMENT (3 << YAML_STATE_BITSIZE)
57 #define YAML_STATE_TEXT_PARENT (4 << YAML_STATE_BITSIZE)
58 #define YAML_STATE_TEXT (5 << YAML_STATE_BITSIZE)
60 static void ColouriseYAMLLine(
62 unsigned int currentLine
,
63 unsigned int lengthLine
,
64 unsigned int startLine
,
70 bool bInQuotes
= false;
71 unsigned int indentAmount
= SpaceCount(lineBuffer
);
73 if (currentLine
> 0) {
74 int parentLineState
= styler
.GetLineState(currentLine
- 1);
76 if ((parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT
|| (parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT_PARENT
) {
77 unsigned int parentIndentAmount
= parentLineState
&(~YAML_STATE_MASK
);
78 if (indentAmount
> parentIndentAmount
) {
79 styler
.SetLineState(currentLine
, YAML_STATE_TEXT
| parentIndentAmount
);
80 styler
.ColourTo(endPos
, SCE_YAML_TEXT
);
85 styler
.SetLineState(currentLine
, 0);
86 if (strncmp(lineBuffer
, "---", 3) == 0) { // Document marker
87 styler
.SetLineState(currentLine
, YAML_STATE_DOCUMENT
);
88 styler
.ColourTo(endPos
, SCE_YAML_DOCUMENT
);
91 // Skip initial spaces
92 while ((i
< lengthLine
) && lineBuffer
[i
] == ' ') { // YAML always uses space, never TABS or anything else
95 if (lineBuffer
[i
] == '\t') { // if we skipped all spaces, and we are NOT inside a text block, this is wrong
96 styler
.ColourTo(endPos
, SCE_YAML_ERROR
);
99 if (lineBuffer
[i
] == '#') { // Comment
100 styler
.SetLineState(currentLine
, YAML_STATE_COMMENT
);
101 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
104 while (i
< lengthLine
) {
105 if (lineBuffer
[i
] == '\'' || lineBuffer
[i
] == '\"') {
106 bInQuotes
= !bInQuotes
;
107 } else if (lineBuffer
[i
] == ':' && !bInQuotes
) {
108 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_IDENTIFIER
);
109 styler
.ColourTo(startLine
+ i
, SCE_YAML_OPERATOR
);
110 // Non-folding scalar
112 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
]))
114 unsigned int endValue
= lengthLine
- 1;
115 while ((endValue
>= i
) && isspacechar(lineBuffer
[endValue
]))
117 lineBuffer
[endValue
+ 1] = '\0';
118 if (lineBuffer
[i
] == '|' || lineBuffer
[i
] == '>') {
120 if (lineBuffer
[i
] == '+' || lineBuffer
[i
] == '-')
122 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
]))
124 if (lineBuffer
[i
] == '\0') {
125 styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT
| indentAmount
);
126 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
128 } else if (lineBuffer
[i
] == '#') {
129 styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT
| indentAmount
);
130 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_DEFAULT
);
131 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
134 styler
.ColourTo(endPos
, SCE_YAML_ERROR
);
137 } else if (lineBuffer
[i
] == '#') {
138 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_DEFAULT
);
139 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
142 styler
.SetLineState(currentLine
, YAML_STATE_VALUE
);
143 if (lineBuffer
[i
] == '&' || lineBuffer
[i
] == '*') {
144 styler
.ColourTo(endPos
, SCE_YAML_REFERENCE
);
147 if (keywords
.InList(&lineBuffer
[i
])) { // Convertible value (true/false, etc.)
148 styler
.ColourTo(endPos
, SCE_YAML_KEYWORD
);
152 while ((i
< lengthLine
) && lineBuffer
[i
]) {
153 if (!(isascii(lineBuffer
[i
]) && isdigit(lineBuffer
[i
])) && lineBuffer
[i
] != '-' && lineBuffer
[i
] != '.' && lineBuffer
[i
] != ',') {
154 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
160 styler
.ColourTo(endPos
, SCE_YAML_NUMBER
);
164 break; // shouldn't get here, but just in case, the rest of the line is coloured the default
168 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
171 static void ColouriseYAMLDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
) {
172 char lineBuffer
[1024];
173 styler
.StartAt(startPos
);
174 styler
.StartSegment(startPos
);
175 unsigned int linePos
= 0;
176 unsigned int startLine
= startPos
;
177 unsigned int endPos
= startPos
+ length
;
178 unsigned int maxPos
= styler
.Length();
179 unsigned int lineCurrent
= styler
.GetLine(startPos
);
181 for (unsigned int i
= startPos
; i
< maxPos
&& i
< endPos
; i
++) {
182 lineBuffer
[linePos
++] = styler
[i
];
183 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
184 // End of line (or of line buffer) met, colourise it
185 lineBuffer
[linePos
] = '\0';
186 ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, i
, *keywordLists
[0], styler
);
192 if (linePos
> 0) { // Last line does not have ending characters
193 ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, startPos
+ length
- 1, *keywordLists
[0], styler
);
197 static bool IsCommentLine(int line
, Accessor
&styler
) {
198 int pos
= styler
.LineStart(line
);
199 if (styler
[pos
] == '#')
204 static void FoldYAMLDoc(unsigned int startPos
, int length
, int /*initStyle - unused*/,
205 WordList
*[], Accessor
&styler
) {
206 const int maxPos
= startPos
+ length
;
207 const int maxLines
= styler
.GetLine(maxPos
- 1); // Requested last line
208 const int docLines
= styler
.GetLine(styler
.Length() - 1); // Available last line
209 const bool foldComment
= styler
.GetPropertyInt("fold.comment.yaml") != 0;
211 // Backtrack to previous non-blank line so we can determine indent level
212 // for any white space lines
213 // and so we can fix any preceding fold level (which is why we go back
214 // at least one line in all cases)
216 int lineCurrent
= styler
.GetLine(startPos
);
217 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
218 while (lineCurrent
> 0) {
220 indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
221 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) &&
222 (!IsCommentLine(lineCurrent
, styler
)))
225 int indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
227 // Set up initial loop state
229 if (lineCurrent
>= 1)
230 prevComment
= foldComment
&& IsCommentLine(lineCurrent
- 1, styler
);
232 // Process all characters to end of requested range
233 // or comment that hangs over the end of the range. Cap processing in all cases
234 // to end of document (in case of unclosed comment at end).
235 while ((lineCurrent
<= docLines
) && ((lineCurrent
<= maxLines
) || prevComment
)) {
238 int lev
= indentCurrent
;
239 int lineNext
= lineCurrent
+ 1;
240 int indentNext
= indentCurrent
;
241 if (lineNext
<= docLines
) {
242 // Information about next line is only available if not at end of document
243 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
245 const int comment
= foldComment
&& IsCommentLine(lineCurrent
, styler
);
246 const int comment_start
= (comment
&& !prevComment
&& (lineNext
<= docLines
) &&
247 IsCommentLine(lineNext
, styler
) && (lev
> SC_FOLDLEVELBASE
));
248 const int comment_continue
= (comment
&& prevComment
);
250 indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
251 if (indentNext
& SC_FOLDLEVELWHITEFLAG
)
252 indentNext
= SC_FOLDLEVELWHITEFLAG
| indentCurrentLevel
;
255 // Place fold point at start of a block of comments
256 lev
|= SC_FOLDLEVELHEADERFLAG
;
257 } else if (comment_continue
) {
258 // Add level to rest of lines in the block
262 // Skip past any blank lines for next indent level info; we skip also
263 // comments (all comments, not just those starting in column 0)
264 // which effectively folds them into surrounding code rather
265 // than screwing up folding.
267 while ((lineNext
< docLines
) &&
268 ((indentNext
& SC_FOLDLEVELWHITEFLAG
) ||
269 (lineNext
<= docLines
&& IsCommentLine(lineNext
, styler
)))) {
272 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
275 const int levelAfterComments
= indentNext
& SC_FOLDLEVELNUMBERMASK
;
276 const int levelBeforeComments
= Maximum(indentCurrentLevel
,levelAfterComments
);
278 // Now set all the indent levels on the lines we skipped
279 // Do this from end to start. Once we encounter one line
280 // which is indented more than the line after the end of
281 // the comment-block, use the level of the block before
283 int skipLine
= lineNext
;
284 int skipLevel
= levelAfterComments
;
286 while (--skipLine
> lineCurrent
) {
287 int skipLineIndent
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
);
289 if ((skipLineIndent
& SC_FOLDLEVELNUMBERMASK
) > levelAfterComments
)
290 skipLevel
= levelBeforeComments
;
292 int whiteFlag
= skipLineIndent
& SC_FOLDLEVELWHITEFLAG
;
294 styler
.SetLevel(skipLine
, skipLevel
| whiteFlag
);
297 // Set fold header on non-comment line
298 if (!comment
&& !(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) ) {
299 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
))
300 lev
|= SC_FOLDLEVELHEADERFLAG
;
303 // Keep track of block comment state of previous line
304 prevComment
= comment_start
|| comment_continue
;
306 // Set fold level for this line and move to next line
307 styler
.SetLevel(lineCurrent
, lev
);
308 indentCurrent
= indentNext
;
309 lineCurrent
= lineNext
;
312 // NOTE: Cannot set level of last line here because indentCurrent doesn't have
313 // header flag set; the loop above is crafted to take care of this case!
314 //styler.SetLevel(lineCurrent, indentCurrent);
317 LexerModule
lmYAML(SCLEX_YAML
, ColouriseYAMLDoc
, "yaml", FoldYAMLDoc
, yamlWordListDesc
);