]>
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"
24 using namespace Scintilla
;
27 static const char * const yamlWordListDesc
[] = {
32 static inline bool AtEOL(Accessor
&styler
, unsigned int i
) {
33 return (styler
[i
] == '\n') ||
34 ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n'));
37 static unsigned int SpaceCount(char* lineBuffer
) {
38 if (lineBuffer
== NULL
)
41 char* headBuffer
= lineBuffer
;
43 while (*headBuffer
== ' ')
46 return headBuffer
- lineBuffer
;
49 #define YAML_STATE_BITSIZE 16
50 #define YAML_STATE_MASK (0xFFFF0000)
51 #define YAML_STATE_DOCUMENT (1 << YAML_STATE_BITSIZE)
52 #define YAML_STATE_VALUE (2 << YAML_STATE_BITSIZE)
53 #define YAML_STATE_COMMENT (3 << YAML_STATE_BITSIZE)
54 #define YAML_STATE_TEXT_PARENT (4 << YAML_STATE_BITSIZE)
55 #define YAML_STATE_TEXT (5 << YAML_STATE_BITSIZE)
57 static void ColouriseYAMLLine(
59 unsigned int currentLine
,
60 unsigned int lengthLine
,
61 unsigned int startLine
,
67 bool bInQuotes
= false;
68 unsigned int indentAmount
= SpaceCount(lineBuffer
);
70 if (currentLine
> 0) {
71 int parentLineState
= styler
.GetLineState(currentLine
- 1);
73 if ((parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT
|| (parentLineState
&YAML_STATE_MASK
) == YAML_STATE_TEXT_PARENT
) {
74 unsigned int parentIndentAmount
= parentLineState
&(~YAML_STATE_MASK
);
75 if (indentAmount
> parentIndentAmount
) {
76 styler
.SetLineState(currentLine
, YAML_STATE_TEXT
| parentIndentAmount
);
77 styler
.ColourTo(endPos
, SCE_YAML_TEXT
);
82 styler
.SetLineState(currentLine
, 0);
83 if (strncmp(lineBuffer
, "---", 3) == 0) { // Document marker
84 styler
.SetLineState(currentLine
, YAML_STATE_DOCUMENT
);
85 styler
.ColourTo(endPos
, SCE_YAML_DOCUMENT
);
88 // Skip initial spaces
89 while ((i
< lengthLine
) && lineBuffer
[i
] == ' ') { // YAML always uses space, never TABS or anything else
92 if (lineBuffer
[i
] == '\t') { // if we skipped all spaces, and we are NOT inside a text block, this is wrong
93 styler
.ColourTo(endPos
, SCE_YAML_ERROR
);
96 if (lineBuffer
[i
] == '#') { // Comment
97 styler
.SetLineState(currentLine
, YAML_STATE_COMMENT
);
98 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
101 while (i
< lengthLine
) {
102 if (lineBuffer
[i
] == '\'' || lineBuffer
[i
] == '\"') {
103 bInQuotes
= !bInQuotes
;
104 } else if (lineBuffer
[i
] == ':' && !bInQuotes
) {
105 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_IDENTIFIER
);
106 styler
.ColourTo(startLine
+ i
, SCE_YAML_OPERATOR
);
107 // Non-folding scalar
109 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
]))
111 unsigned int endValue
= lengthLine
- 1;
112 while ((endValue
>= i
) && isspacechar(lineBuffer
[endValue
]))
114 lineBuffer
[endValue
+ 1] = '\0';
115 if (lineBuffer
[i
] == '|' || lineBuffer
[i
] == '>') {
117 if (lineBuffer
[i
] == '+' || lineBuffer
[i
] == '-')
119 while ((i
< lengthLine
) && isspacechar(lineBuffer
[i
]))
121 if (lineBuffer
[i
] == '\0') {
122 styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT
| indentAmount
);
123 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
125 } else if (lineBuffer
[i
] == '#') {
126 styler
.SetLineState(currentLine
, YAML_STATE_TEXT_PARENT
| indentAmount
);
127 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_DEFAULT
);
128 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
131 styler
.ColourTo(endPos
, SCE_YAML_ERROR
);
134 } else if (lineBuffer
[i
] == '#') {
135 styler
.ColourTo(startLine
+ i
- 1, SCE_YAML_DEFAULT
);
136 styler
.ColourTo(endPos
, SCE_YAML_COMMENT
);
139 styler
.SetLineState(currentLine
, YAML_STATE_VALUE
);
140 if (lineBuffer
[i
] == '&' || lineBuffer
[i
] == '*') {
141 styler
.ColourTo(endPos
, SCE_YAML_REFERENCE
);
144 if (keywords
.InList(&lineBuffer
[i
])) { // Convertible value (true/false, etc.)
145 styler
.ColourTo(endPos
, SCE_YAML_KEYWORD
);
149 while ((i
< lengthLine
) && lineBuffer
[i
]) {
150 if (!isdigit(lineBuffer
[i
]) && lineBuffer
[i
] != '-' && lineBuffer
[i
] != '.' && lineBuffer
[i
] != ',') {
151 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
157 styler
.ColourTo(endPos
, SCE_YAML_NUMBER
);
161 break; // shouldn't get here, but just in case, the rest of the line is coloured the default
165 styler
.ColourTo(endPos
, SCE_YAML_DEFAULT
);
168 static void ColouriseYAMLDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
) {
169 char lineBuffer
[1024];
170 styler
.StartAt(startPos
);
171 styler
.StartSegment(startPos
);
172 unsigned int linePos
= 0;
173 unsigned int startLine
= startPos
;
174 unsigned int endPos
= startPos
+ length
;
175 unsigned int maxPos
= styler
.Length();
176 unsigned int lineCurrent
= styler
.GetLine(startPos
);
178 for (unsigned int i
= startPos
; i
< maxPos
&& i
< endPos
; i
++) {
179 lineBuffer
[linePos
++] = styler
[i
];
180 if (AtEOL(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
181 // End of line (or of line buffer) met, colourise it
182 lineBuffer
[linePos
] = '\0';
183 ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, i
, *keywordLists
[0], styler
);
189 if (linePos
> 0) { // Last line does not have ending characters
190 ColouriseYAMLLine(lineBuffer
, lineCurrent
, linePos
, startLine
, startPos
+ length
- 1, *keywordLists
[0], styler
);
194 static bool IsCommentLine(int line
, Accessor
&styler
) {
195 int pos
= styler
.LineStart(line
);
196 if (styler
[pos
] == '#')
201 static void FoldYAMLDoc(unsigned int startPos
, int length
, int /*initStyle - unused*/,
202 WordList
*[], Accessor
&styler
) {
203 const int maxPos
= startPos
+ length
;
204 const int maxLines
= styler
.GetLine(maxPos
- 1); // Requested last line
205 const int docLines
= styler
.GetLine(styler
.Length() - 1); // Available last line
206 const bool foldComment
= styler
.GetPropertyInt("fold.comment.yaml") != 0;
208 // Backtrack to previous non-blank line so we can determine indent level
209 // for any white space lines
210 // and so we can fix any preceding fold level (which is why we go back
211 // at least one line in all cases)
213 int lineCurrent
= styler
.GetLine(startPos
);
214 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
215 while (lineCurrent
> 0) {
217 indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
218 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) &&
219 (!IsCommentLine(lineCurrent
, styler
)))
222 int indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
224 // Set up initial loop state
226 if (lineCurrent
>= 1)
227 prevComment
= foldComment
&& IsCommentLine(lineCurrent
- 1, styler
);
229 // Process all characters to end of requested range
230 // or comment that hangs over the end of the range. Cap processing in all cases
231 // to end of document (in case of unclosed comment at end).
232 while ((lineCurrent
<= docLines
) && ((lineCurrent
<= maxLines
) || prevComment
)) {
235 int lev
= indentCurrent
;
236 int lineNext
= lineCurrent
+ 1;
237 int indentNext
= indentCurrent
;
238 if (lineNext
<= docLines
) {
239 // Information about next line is only available if not at end of document
240 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
242 const int comment
= foldComment
&& IsCommentLine(lineCurrent
, styler
);
243 const int comment_start
= (comment
&& !prevComment
&& (lineNext
<= docLines
) &&
244 IsCommentLine(lineNext
, styler
) && (lev
> SC_FOLDLEVELBASE
));
245 const int comment_continue
= (comment
&& prevComment
);
247 indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
248 if (indentNext
& SC_FOLDLEVELWHITEFLAG
)
249 indentNext
= SC_FOLDLEVELWHITEFLAG
| indentCurrentLevel
;
252 // Place fold point at start of a block of comments
253 lev
|= SC_FOLDLEVELHEADERFLAG
;
254 } else if (comment_continue
) {
255 // Add level to rest of lines in the block
259 // Skip past any blank lines for next indent level info; we skip also
260 // comments (all comments, not just those starting in column 0)
261 // which effectively folds them into surrounding code rather
262 // than screwing up folding.
264 while ((lineNext
< docLines
) &&
265 ((indentNext
& SC_FOLDLEVELWHITEFLAG
) ||
266 (lineNext
<= docLines
&& IsCommentLine(lineNext
, styler
)))) {
269 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
272 const int levelAfterComments
= indentNext
& SC_FOLDLEVELNUMBERMASK
;
273 const int levelBeforeComments
= Platform::Maximum(indentCurrentLevel
,levelAfterComments
);
275 // Now set all the indent levels on the lines we skipped
276 // Do this from end to start. Once we encounter one line
277 // which is indented more than the line after the end of
278 // the comment-block, use the level of the block before
280 int skipLine
= lineNext
;
281 int skipLevel
= levelAfterComments
;
283 while (--skipLine
> lineCurrent
) {
284 int skipLineIndent
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
);
286 if ((skipLineIndent
& SC_FOLDLEVELNUMBERMASK
) > levelAfterComments
)
287 skipLevel
= levelBeforeComments
;
289 int whiteFlag
= skipLineIndent
& SC_FOLDLEVELWHITEFLAG
;
291 styler
.SetLevel(skipLine
, skipLevel
| whiteFlag
);
294 // Set fold header on non-comment line
295 if (!comment
&& !(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) ) {
296 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
))
297 lev
|= SC_FOLDLEVELHEADERFLAG
;
300 // Keep track of block comment state of previous line
301 prevComment
= comment_start
|| comment_continue
;
303 // Set fold level for this line and move to next line
304 styler
.SetLevel(lineCurrent
, lev
);
305 indentCurrent
= indentNext
;
306 lineCurrent
= lineNext
;
309 // NOTE: Cannot set level of last line here because indentCurrent doesn't have
310 // header flag set; the loop above is crafted to take care of this case!
311 //styler.SetLevel(lineCurrent, indentCurrent);
314 LexerModule
lmYAML(SCLEX_YAML
, ColouriseYAMLDoc
, "yaml", FoldYAMLDoc
, yamlWordListDesc
);