]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexNimrod.cxx
8c4d04360673c721a0839b56355b14ea9c0b143d
1 // Scintilla source code edit control
3 // (c) 2009 Andreas Rumpf
4 /** @file LexNimrod.cxx
7 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
20 #include "StyleContext.h"
22 #include "Scintilla.h"
26 using namespace Scintilla
;
29 static inline bool IsAWordChar(int ch
) {
30 return (ch
>= 0x80) || isalnum(ch
) || ch
== '_';
33 static int tillEndOfTripleQuote(Accessor
&styler
, int pos
, int max
) {
36 if (styler
.SafeGetCharAt(pos
, '\0') == '\0') return pos
;
37 if (pos
>= max
) return pos
;
38 if (styler
.Match(pos
, "\"\"\"")) {
45 #define CR 13 /* use both because Scite allows changing the line ending */
48 static bool inline isNewLine(int ch
) {
49 return ch
== CR
|| ch
== LF
;
52 static int scanString(Accessor
&styler
, int pos
, int max
, bool rawMode
) {
54 if (pos
>= max
) return pos
;
55 char ch
= styler
.SafeGetCharAt(pos
, '\0');
56 if (ch
== CR
|| ch
== LF
|| ch
== '\0') return pos
;
57 if (ch
== '"') return pos
;
58 if (ch
== '\\' && !rawMode
) {
66 static int scanChar(Accessor
&styler
, int pos
, int max
) {
68 if (pos
>= max
) return pos
;
69 char ch
= styler
.SafeGetCharAt(pos
, '\0');
70 if (ch
== CR
|| ch
== LF
|| ch
== '\0') return pos
;
71 if (ch
== '\'' && !isalnum(styler
.SafeGetCharAt(pos
+1, '\0')) )
81 static int scanIdent(Accessor
&styler
, int pos
, WordList
&keywords
) {
82 char buf
[100]; /* copy to lowercase and ignore underscores */
86 char ch
= styler
.SafeGetCharAt(pos
, '\0');
87 if (!IsAWordChar(ch
)) break;
88 if (ch
!= '_' && i
< ((int)sizeof(buf
))-1) {
89 buf
[i
] = static_cast<char>(tolower(ch
));
95 /* look for keyword */
96 if (keywords
.InList(buf
)) {
97 styler
.ColourTo(pos
-1, SCE_P_WORD
);
99 styler
.ColourTo(pos
-1, SCE_P_IDENTIFIER
);
104 static int scanNumber(Accessor
&styler
, int pos
) {
106 ch
= styler
.SafeGetCharAt(pos
, '\0');
107 ch2
= styler
.SafeGetCharAt(pos
+1, '\0');
108 if (ch
== '0' && (ch2
== 'b' || ch2
== 'B')) {
112 ch
= styler
.SafeGetCharAt(pos
, '\0');
113 if (ch
== '_' || (ch
>= '0' && ch
<= '1')) ++pos
;
116 } else if (ch
== '0' &&
117 (ch2
== 'o' || ch2
== 'O' || ch2
== 'c' || ch2
== 'C')) {
121 ch
= styler
.SafeGetCharAt(pos
, '\0');
122 if (ch
== '_' || (ch
>= '0' && ch
<= '7')) ++pos
;
125 } else if (ch
== '0' && (ch2
== 'x' || ch2
== 'X')) {
126 /* hexadecimal number: */
129 ch
= styler
.SafeGetCharAt(pos
, '\0');
130 if (ch
== '_' || (ch
>= '0' && ch
<= '9')
131 || (ch
>= 'a' && ch
<= 'f')
132 || (ch
>= 'A' && ch
<= 'F')) ++pos
;
136 // skip decimal part:
138 ch
= styler
.SafeGetCharAt(pos
, '\0');
139 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
142 ch2
= styler
.SafeGetCharAt(pos
+1, '\0');
143 if (ch
== '.' && ch2
>= '0' && ch2
<= '9') {
146 ch
= styler
.SafeGetCharAt(pos
, '\0');
147 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
151 if (ch
== 'e' || ch
== 'E') {
153 ch
= styler
.SafeGetCharAt(pos
, '\0');
154 if (ch
== '-' || ch
== '+') ++pos
;
156 ch
= styler
.SafeGetCharAt(pos
, '\0');
157 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
166 ch
= styler
.SafeGetCharAt(pos
);
167 if ((ch
>= '0' && ch
<= '9') || (ch
>= 'A' && ch
<= 'Z')
168 || (ch
>= 'a' && ch
<= 'z') || ch
== '_') ++pos
;
172 styler
.ColourTo(pos
-1, SCE_P_NUMBER
);
176 /* rewritten from scratch, because I couldn't get rid of the bugs...
177 (A character based approach sucks!)
179 static void ColouriseNimrodDoc(unsigned int startPos
, int length
, int initStyle
,
180 WordList
*keywordlists
[], Accessor
&styler
) {
182 int max
= startPos
+ length
;
184 WordList
&keywords
= *keywordlists
[0];
186 styler
.StartAt(startPos
);
187 styler
.StartSegment(startPos
);
190 /* check where we are: */
191 case SCE_P_TRIPLEDOUBLE
:
192 pos
= tillEndOfTripleQuote(styler
, pos
, max
);
193 styler
.ColourTo(pos
, SCE_P_TRIPLEDOUBLE
);
196 default: /* nothing to do: */
200 ch
= styler
.SafeGetCharAt(pos
, '\0');
204 bool doccomment
= (styler
.SafeGetCharAt(pos
+1) == '#');
205 while (pos
< max
&& !isNewLine(styler
.SafeGetCharAt(pos
, LF
))) pos
++;
207 styler
.ColourTo(pos
, SCE_C_COMMENTLINEDOC
);
209 styler
.ColourTo(pos
, SCE_P_COMMENTLINE
);
211 case 'r': case 'R': {
212 if (styler
.SafeGetCharAt(pos
+1) == '"') {
213 pos
= scanString(styler
, pos
+2, max
, true);
214 styler
.ColourTo(pos
, SCE_P_STRING
);
217 pos
= scanIdent(styler
, pos
, keywords
);
221 if (styler
.Match(pos
+1, "\"\"")) {
222 pos
= tillEndOfTripleQuote(styler
, pos
+3, max
);
223 styler
.ColourTo(pos
, SCE_P_TRIPLEDOUBLE
);
225 pos
= scanString(styler
, pos
+1, max
, false);
226 styler
.ColourTo(pos
, SCE_P_STRING
);
231 pos
= scanChar(styler
, pos
+1, max
);
232 styler
.ColourTo(pos
, SCE_P_CHARACTER
);
235 default: // identifers, numbers, operators, whitespace
236 if (ch
>= '0' && ch
<= '9') {
237 pos
= scanNumber(styler
, pos
);
238 } else if (IsAWordChar(ch
)) {
239 pos
= scanIdent(styler
, pos
, keywords
);
240 } else if (ch
== '`') {
243 ch
= styler
.SafeGetCharAt(pos
, LF
);
248 if (ch
== CR
|| ch
== LF
) break;
251 styler
.ColourTo(pos
, SCE_P_IDENTIFIER
);
252 } else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", ch
)) {
253 styler
.ColourTo(pos
, SCE_P_OPERATOR
);
256 styler
.ColourTo(pos
, SCE_P_DEFAULT
);
264 static bool IsCommentLine(int line
, Accessor
&styler
) {
265 int pos
= styler
.LineStart(line
);
266 int eol_pos
= styler
.LineStart(line
+ 1) - 1;
267 for (int i
= pos
; i
< eol_pos
; i
++) {
271 else if (ch
!= ' ' && ch
!= '\t')
277 static bool IsQuoteLine(int line
, Accessor
&styler
) {
278 int style
= styler
.StyleAt(styler
.LineStart(line
)) & 31;
279 return ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
));
283 static void FoldNimrodDoc(unsigned int startPos
, int length
,
284 int /*initStyle - unused*/,
285 WordList
*[], Accessor
&styler
) {
286 const int maxPos
= startPos
+ length
;
287 const int maxLines
= styler
.GetLine(maxPos
- 1); // Requested last line
288 const int docLines
= styler
.GetLine(styler
.Length() - 1); // Available last line
289 const bool foldComment
= styler
.GetPropertyInt("fold.comment.nimrod") != 0;
290 const bool foldQuotes
= styler
.GetPropertyInt("fold.quotes.nimrod") != 0;
292 // Backtrack to previous non-blank line so we can determine indent level
293 // for any white space lines (needed esp. within triple quoted strings)
294 // and so we can fix any preceding fold level (which is why we go back
295 // at least one line in all cases)
297 int lineCurrent
= styler
.GetLine(startPos
);
298 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
299 while (lineCurrent
> 0) {
301 indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
302 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) &&
303 (!IsCommentLine(lineCurrent
, styler
)) &&
304 (!IsQuoteLine(lineCurrent
, styler
)))
307 int indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
309 // Set up initial loop state
310 startPos
= styler
.LineStart(lineCurrent
);
311 int prev_state
= SCE_P_DEFAULT
& 31;
312 if (lineCurrent
>= 1)
313 prev_state
= styler
.StyleAt(startPos
- 1) & 31;
314 int prevQuote
= foldQuotes
&& ((prev_state
== SCE_P_TRIPLE
) ||
315 (prev_state
== SCE_P_TRIPLEDOUBLE
));
317 if (lineCurrent
>= 1)
318 prevComment
= foldComment
&& IsCommentLine(lineCurrent
- 1, styler
);
320 // Process all characters to end of requested range or end of any triple quote
321 // or comment that hangs over the end of the range. Cap processing in all cases
322 // to end of document (in case of unclosed quote or comment at end).
323 while ((lineCurrent
<= docLines
) && ((lineCurrent
<= maxLines
) ||
324 prevQuote
|| prevComment
)) {
327 int lev
= indentCurrent
;
328 int lineNext
= lineCurrent
+ 1;
329 int indentNext
= indentCurrent
;
331 if (lineNext
<= docLines
) {
332 // Information about next line is only available if not at end of document
333 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
334 int style
= styler
.StyleAt(styler
.LineStart(lineNext
)) & 31;
335 quote
= foldQuotes
&& ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
));
337 const int quote_start
= (quote
&& !prevQuote
);
338 const int quote_continue
= (quote
&& prevQuote
);
339 const int comment
= foldComment
&& IsCommentLine(lineCurrent
, styler
);
340 const int comment_start
= (comment
&& !prevComment
&& (lineNext
<= docLines
) &&
341 IsCommentLine(lineNext
, styler
) &&
342 (lev
> SC_FOLDLEVELBASE
));
343 const int comment_continue
= (comment
&& prevComment
);
344 if ((!quote
|| !prevQuote
) && !comment
)
345 indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
347 indentNext
= indentCurrentLevel
;
348 if (indentNext
& SC_FOLDLEVELWHITEFLAG
)
349 indentNext
= SC_FOLDLEVELWHITEFLAG
| indentCurrentLevel
;
352 // Place fold point at start of triple quoted string
353 lev
|= SC_FOLDLEVELHEADERFLAG
;
354 } else if (quote_continue
|| prevQuote
) {
355 // Add level to rest of lines in the string
357 } else if (comment_start
) {
358 // Place fold point at start of a block of comments
359 lev
|= SC_FOLDLEVELHEADERFLAG
;
360 } else if (comment_continue
) {
361 // Add level to rest of lines in the block
365 // Skip past any blank lines for next indent level info; we skip also
366 // comments (all comments, not just those starting in column 0)
367 // which effectively folds them into surrounding code rather
368 // than screwing up folding.
371 (lineNext
< docLines
) &&
372 ((indentNext
& SC_FOLDLEVELWHITEFLAG
) ||
373 (lineNext
<= docLines
&& IsCommentLine(lineNext
, styler
)))) {
376 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
379 const int levelAfterComments
= indentNext
& SC_FOLDLEVELNUMBERMASK
;
380 const int levelBeforeComments
=
381 Platform::Maximum(indentCurrentLevel
,levelAfterComments
);
383 // Now set all the indent levels on the lines we skipped
384 // Do this from end to start. Once we encounter one line
385 // which is indented more than the line after the end of
386 // the comment-block, use the level of the block before
388 int skipLine
= lineNext
;
389 int skipLevel
= levelAfterComments
;
391 while (--skipLine
> lineCurrent
) {
392 int skipLineIndent
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
);
394 if ((skipLineIndent
& SC_FOLDLEVELNUMBERMASK
) > levelAfterComments
)
395 skipLevel
= levelBeforeComments
;
397 int whiteFlag
= skipLineIndent
& SC_FOLDLEVELWHITEFLAG
;
399 styler
.SetLevel(skipLine
, skipLevel
| whiteFlag
);
402 // Set fold header on non-quote/non-comment line
403 if (!quote
&& !comment
&& !(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) ) {
404 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) <
405 (indentNext
& SC_FOLDLEVELNUMBERMASK
))
406 lev
|= SC_FOLDLEVELHEADERFLAG
;
409 // Keep track of triple quote and block comment state of previous line
411 prevComment
= comment_start
|| comment_continue
;
413 // Set fold level for this line and move to next line
414 styler
.SetLevel(lineCurrent
, lev
);
415 indentCurrent
= indentNext
;
416 lineCurrent
= lineNext
;
419 // NOTE: Cannot set level of last line here because indentCurrent doesn't have
420 // header flag set; the loop above is crafted to take care of this case!
421 //styler.SetLevel(lineCurrent, indentCurrent);
424 static const char * const nimrodWordListDesc
[] = {
429 LexerModule
lmNimrod(SCLEX_NIMROD
, ColouriseNimrodDoc
, "nimrod", FoldNimrodDoc
,