]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/lexers/LexCoffeeScript.cxx
Add missing WXK constants for the control keys
[wxWidgets.git] / src / stc / scintilla / lexers / LexCoffeeScript.cxx
CommitLineData
65ec6247 1// Scintilla source code edit control
1dcf666d
RD
2/** @file LexCoffeeScript.cxx
3 ** Lexer for CoffeeScript.
65ec6247 4 **/
1dcf666d
RD
5// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6// Based on the Scintilla C++ Lexer
7// Written by Eric Promislow <ericp@activestate.com> in 2011 for the Komodo IDE
f6bcfd97
BP
8// The License.txt file describes the conditions under which this software may be distributed.
9
65ec6247
RD
10#include <stdlib.h>
11#include <string.h>
65ec6247
RD
12#include <stdio.h>
13#include <stdarg.h>
1dcf666d
RD
14#include <assert.h>
15#include <ctype.h>
f6bcfd97
BP
16
17#include "Platform.h"
1dcf666d
RD
18#include "ILexer.h"
19#include "Scintilla.h"
20#include "SciLexer.h"
f6bcfd97 21
1dcf666d
RD
22#include "WordList.h"
23#include "LexAccessor.h"
f6bcfd97 24#include "Accessor.h"
b8b0e402 25#include "StyleContext.h"
7e0c58e9 26#include "CharacterSet.h"
1dcf666d 27#include "LexerModule.h"
f6bcfd97 28
7e0c58e9
RD
29#ifdef SCI_NAMESPACE
30using namespace Scintilla;
31#endif
65ec6247 32
1e9bafca 33static bool IsSpaceEquiv(int state) {
1dcf666d
RD
34 return (state <= SCE_C_COMMENTDOC
35 // including SCE_C_DEFAULT, SCE_C_COMMENT, SCE_C_COMMENTLINE
36 || state == SCE_C_COMMENTLINEDOC
37 || state == SCE_C_COMMENTDOCKEYWORD
38 || state == SCE_C_COMMENTDOCKEYWORDERROR
39 || state == SCE_COFFEESCRIPT_COMMENTBLOCK
40 || state == SCE_COFFEESCRIPT_VERBOSE_REGEX
41 || state == SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT
42 || state == SCE_C_WORD
43 || state == SCE_C_REGEX);
b8b0e402 44}
65ec6247 45
7e0c58e9
RD
46// Preconditions: sc.currentPos points to a character after '+' or '-'.
47// The test for pos reaching 0 should be redundant,
48// and is in only for safety measures.
49// Limitation: this code will give the incorrect answer for code like
50// a = b+++/ptn/...
51// Putting a space between the '++' post-inc operator and the '+' binary op
52// fixes this, and is highly recommended for readability anyway.
53static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) {
54 int pos = (int) sc.currentPos;
55 while (--pos > 0) {
56 char ch = styler[pos];
57 if (ch == '+' || ch == '-') {
58 return styler[pos - 1] == ch;
59 }
60 }
61 return false;
62}
63
1dcf666d
RD
64static bool followsReturnKeyword(StyleContext &sc, Accessor &styler) {
65 // Don't look at styles, so no need to flush.
66 int pos = (int) sc.currentPos;
67 int currentLine = styler.GetLine(pos);
68 int lineStartPos = styler.LineStart(currentLine);
69 char ch;
70 while (--pos > lineStartPos) {
71 ch = styler.SafeGetCharAt(pos);
72 if (ch != ' ' && ch != '\t') {
73 break;
74 }
75 }
76 const char *retBack = "nruter";
77 const char *s = retBack;
78 while (*s
79 && pos >= lineStartPos
80 && styler.SafeGetCharAt(pos) == *s) {
81 s++;
82 pos--;
83 }
84 return !*s;
85}
86
87static void ColouriseCoffeeScriptDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
88 Accessor &styler) {
f6bcfd97 89
f6bcfd97 90 WordList &keywords = *keywordlists[0];
65ec6247 91 WordList &keywords2 = *keywordlists[1];
b8b0e402 92 WordList &keywords3 = *keywordlists[2];
e14d10b0 93 WordList &keywords4 = *keywordlists[3];
65ec6247 94
9e96e16f 95 // property styling.within.preprocessor
1dcf666d
RD
96 // For C++ code, determines whether all preprocessor code is styled in the preprocessor style (0, the default)
97 // or only from the initial # to the end of the command word(1).
1a2fb4cd 98 bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;
f6bcfd97 99
7e0c58e9
RD
100 CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-");
101 CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
102
9e96e16f 103 CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
7e0c58e9
RD
104
105 CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
106 CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
9e96e16f
RD
107
108 // property lexer.cpp.allow.dollars
1dcf666d 109 // Set to 0 to disallow the '$' character in identifiers with the cpp lexer.
7e0c58e9
RD
110 if (styler.GetPropertyInt("lexer.cpp.allow.dollars", 1) != 0) {
111 setWordStart.Add('$');
112 setWord.Add('$');
113 }
114
65ec6247 115 int chPrevNonWhite = ' ';
d134f170 116 int visibleChars = 0;
f6bcfd97 117 bool lastWordWasUUID = false;
1e9bafca
RD
118 int styleBeforeDCKeyword = SCE_C_DEFAULT;
119 bool continuationLine = false;
9e96e16f 120 bool isIncludePreprocessor = false;
1e9bafca
RD
121
122 if (initStyle == SCE_C_PREPROCESSOR) {
123 // Set continuationLine if last character of previous line is '\'
124 int lineCurrent = styler.GetLine(startPos);
125 if (lineCurrent > 0) {
126 int chBack = styler.SafeGetCharAt(startPos-1, 0);
127 int chBack2 = styler.SafeGetCharAt(startPos-2, 0);
128 int lineEndChar = '!';
129 if (chBack2 == '\r' && chBack == '\n') {
130 lineEndChar = styler.SafeGetCharAt(startPos-3, 0);
131 } else if (chBack == '\n' || chBack == '\r') {
132 lineEndChar = chBack2;
133 }
134 continuationLine = lineEndChar == '\\';
135 }
136 }
137
138 // look back to set chPrevNonWhite properly for better regex colouring
1dcf666d 139 int endPos = startPos + length;
1e9bafca 140 if (startPos > 0) {
1dcf666d
RD
141 unsigned int back = startPos;
142 styler.Flush();
143 while (back > 0 && IsSpaceEquiv(styler.StyleAt(--back)))
1e9bafca
RD
144 ;
145 if (styler.StyleAt(back) == SCE_C_OPERATOR) {
146 chPrevNonWhite = styler.SafeGetCharAt(back);
147 }
1dcf666d
RD
148 if (startPos != back) {
149 initStyle = styler.StyleAt(back);
150 }
151 startPos = back;
1e9bafca 152 }
f6bcfd97 153
1dcf666d 154 StyleContext sc(startPos, endPos - startPos, initStyle, styler);
f6bcfd97 155
b8b0e402 156 for (; sc.More(); sc.Forward()) {
9e730a78 157
1e9bafca 158 if (sc.atLineStart) {
1e9bafca
RD
159 // Reset states to begining of colourise so no surprises
160 // if different sets of lines lexed.
161 visibleChars = 0;
162 lastWordWasUUID = false;
9e96e16f 163 isIncludePreprocessor = false;
a834585d
RD
164 }
165
b8b0e402
RD
166 // Handle line continuation generically.
167 if (sc.ch == '\\') {
a834585d 168 if (sc.chNext == '\n' || sc.chNext == '\r') {
b8b0e402 169 sc.Forward();
a834585d
RD
170 if (sc.ch == '\r' && sc.chNext == '\n') {
171 sc.Forward();
172 }
1e9bafca 173 continuationLine = true;
b8b0e402 174 continue;
f6bcfd97 175 }
b8b0e402
RD
176 }
177
178 // Determine if the current state should terminate.
1e9bafca
RD
179 switch (sc.state) {
180 case SCE_C_OPERATOR:
b8b0e402 181 sc.SetState(SCE_C_DEFAULT);
1e9bafca
RD
182 break;
183 case SCE_C_NUMBER:
184 // We accept almost anything because of hex. and number suffixes
7e0c58e9 185 if (!setWord.Contains(sc.ch)) {
b8b0e402 186 sc.SetState(SCE_C_DEFAULT);
f6bcfd97 187 }
1e9bafca
RD
188 break;
189 case SCE_C_IDENTIFIER:
1dcf666d 190 if (!setWord.Contains(sc.ch) || (sc.ch == '.') || (sc.ch == '$')) {
1e9bafca 191 char s[1000];
1dcf666d 192 sc.GetCurrent(s, sizeof(s));
1e9bafca
RD
193 if (keywords.InList(s)) {
194 lastWordWasUUID = strcmp(s, "uuid") == 0;
195 sc.ChangeState(SCE_C_WORD);
196 } else if (keywords2.InList(s)) {
197 sc.ChangeState(SCE_C_WORD2);
198 } else if (keywords4.InList(s)) {
199 sc.ChangeState(SCE_C_GLOBALCLASS);
200 }
b8b0e402 201 sc.SetState(SCE_C_DEFAULT);
f6bcfd97 202 }
1e9bafca
RD
203 break;
204 case SCE_C_PREPROCESSOR:
205 if (sc.atLineStart && !continuationLine) {
206 sc.SetState(SCE_C_DEFAULT);
207 } else if (stylingWithinPreprocessor) {
208 if (IsASpace(sc.ch)) {
209 sc.SetState(SCE_C_DEFAULT);
210 }
9e730a78 211 } else {
1e9bafca
RD
212 if (sc.Match('/', '*') || sc.Match('/', '/')) {
213 sc.SetState(SCE_C_DEFAULT);
214 }
b8b0e402 215 }
1e9bafca
RD
216 break;
217 case SCE_C_COMMENT:
218 if (sc.Match('*', '/')) {
b8b0e402 219 sc.Forward();
1e9bafca 220 sc.ForwardSetState(SCE_C_DEFAULT);
f6bcfd97 221 }
1e9bafca
RD
222 break;
223 case SCE_C_COMMENTDOC:
224 if (sc.Match('*', '/')) {
b8b0e402 225 sc.Forward();
1e9bafca
RD
226 sc.ForwardSetState(SCE_C_DEFAULT);
227 } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
228 // Verify that we have the conditions to mark a comment-doc-keyword
229 if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
230 styleBeforeDCKeyword = SCE_C_COMMENTDOC;
231 sc.SetState(SCE_C_COMMENTDOCKEYWORD);
232 }
f6bcfd97 233 }
1e9bafca
RD
234 break;
235 case SCE_C_COMMENTLINE:
236 if (sc.atLineStart) {
237 sc.SetState(SCE_C_DEFAULT);
d134f170 238 }
1e9bafca
RD
239 break;
240 case SCE_C_COMMENTLINEDOC:
241 if (sc.atLineStart) {
242 sc.SetState(SCE_C_DEFAULT);
243 } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
244 // Verify that we have the conditions to mark a comment-doc-keyword
245 if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
246 styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC;
247 sc.SetState(SCE_C_COMMENTDOCKEYWORD);
248 }
249 }
250 break;
251 case SCE_C_COMMENTDOCKEYWORD:
252 if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) {
253 sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
b8b0e402 254 sc.Forward();
b8b0e402 255 sc.ForwardSetState(SCE_C_DEFAULT);
7e0c58e9 256 } else if (!setDoxygen.Contains(sc.ch)) {
1e9bafca 257 char s[100];
1dcf666d 258 sc.GetCurrent(s, sizeof(s));
7e0c58e9 259 if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
1e9bafca
RD
260 sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
261 }
262 sc.SetState(styleBeforeDCKeyword);
263 }
264 break;
265 case SCE_C_STRING:
1dcf666d 266 if (isIncludePreprocessor) {
9e96e16f
RD
267 if (sc.ch == '>') {
268 sc.ForwardSetState(SCE_C_DEFAULT);
269 isIncludePreprocessor = false;
270 }
1e9bafca
RD
271 } else if (sc.ch == '\\') {
272 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
273 sc.Forward();
274 }
275 } else if (sc.ch == '\"') {
276 sc.ForwardSetState(SCE_C_DEFAULT);
277 }
278 break;
279 case SCE_C_CHARACTER:
1dcf666d 280 if (sc.ch == '\\') {
1e9bafca
RD
281 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
282 sc.Forward();
283 }
284 } else if (sc.ch == '\'') {
285 sc.ForwardSetState(SCE_C_DEFAULT);
286 }
287 break;
288 case SCE_C_REGEX:
289 if (sc.atLineStart) {
290 sc.SetState(SCE_C_DEFAULT);
291 } else if (sc.ch == '/') {
292 sc.Forward();
293 while ((sc.ch < 0x80) && islower(sc.ch))
294 sc.Forward(); // gobble regex flags
295 sc.SetState(SCE_C_DEFAULT);
296 } else if (sc.ch == '\\') {
297 // Gobble up the quoted character
298 if (sc.chNext == '\\' || sc.chNext == '/') {
299 sc.Forward();
300 }
301 }
302 break;
303 case SCE_C_STRINGEOL:
304 if (sc.atLineStart) {
305 sc.SetState(SCE_C_DEFAULT);
306 }
307 break;
308 case SCE_C_VERBATIM:
309 if (sc.ch == '\"') {
310 if (sc.chNext == '\"') {
311 sc.Forward();
312 } else {
313 sc.ForwardSetState(SCE_C_DEFAULT);
314 }
315 }
316 break;
317 case SCE_C_UUID:
318 if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
319 sc.SetState(SCE_C_DEFAULT);
d134f170 320 }
1dcf666d
RD
321 break;
322 case SCE_COFFEESCRIPT_COMMENTBLOCK:
323 if (sc.Match("###")) {
324 sc.ChangeState(SCE_C_COMMENT);
325 sc.Forward();
326 sc.Forward();
327 sc.ForwardSetState(SCE_C_DEFAULT);
328 } else if (sc.ch == '\\') {
329 sc.Forward();
330 }
331 break;
332 case SCE_COFFEESCRIPT_VERBOSE_REGEX:
333 if (sc.Match("///")) {
334 sc.Forward();
335 sc.Forward();
336 sc.ChangeState(SCE_C_REGEX);
337 sc.ForwardSetState(SCE_C_DEFAULT);
338 } else if (sc.Match('#')) {
339 sc.ChangeState(SCE_C_REGEX);
340 sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT);
341 } else if (sc.ch == '\\') {
342 sc.Forward();
343 }
344 break;
345 case SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT:
346 if (sc.atLineStart) {
347 sc.ChangeState(SCE_C_COMMENT);
348 sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX);
349 }
350 break;
65ec6247
RD
351 }
352
b8b0e402
RD
353 // Determine if a new state should be entered.
354 if (sc.state == SCE_C_DEFAULT) {
355 if (sc.Match('@', '\"')) {
356 sc.SetState(SCE_C_VERBATIM);
357 sc.Forward();
358 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
65ec6247 359 if (lastWordWasUUID) {
b8b0e402 360 sc.SetState(SCE_C_UUID);
65ec6247
RD
361 lastWordWasUUID = false;
362 } else {
b8b0e402 363 sc.SetState(SCE_C_NUMBER);
f6bcfd97 364 }
1dcf666d 365 } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@') || (sc.ch == '$')) {
65ec6247 366 if (lastWordWasUUID) {
b8b0e402 367 sc.SetState(SCE_C_UUID);
65ec6247
RD
368 lastWordWasUUID = false;
369 } else {
b8b0e402 370 sc.SetState(SCE_C_IDENTIFIER);
f6bcfd97 371 }
b8b0e402
RD
372 } else if (sc.Match('/', '*')) {
373 if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
b8b0e402
RD
374 sc.SetState(SCE_C_COMMENTDOC);
375 } else {
376 sc.SetState(SCE_C_COMMENT);
377 }
378 sc.Forward(); // Eat the * so it isn't used for the end of the comment
1dcf666d
RD
379 } else if (sc.Match("///")) {
380 sc.SetState(SCE_COFFEESCRIPT_VERBOSE_REGEX);
381 } else if (sc.ch == '/'
382 && (setOKBeforeRE.Contains(chPrevNonWhite)
383 || followsReturnKeyword(sc, styler))
384 && (!setCouldBePostOp.Contains(chPrevNonWhite)
385 || !FollowsPostfixOperator(sc, styler))) {
1e9bafca 386 sc.SetState(SCE_C_REGEX); // JavaScript's RegEx
b8b0e402
RD
387 } else if (sc.ch == '\"') {
388 sc.SetState(SCE_C_STRING);
9e96e16f
RD
389 isIncludePreprocessor = false; // ensure that '>' won't end the string
390 } else if (isIncludePreprocessor && sc.ch == '<') {
391 sc.SetState(SCE_C_STRING);
b8b0e402
RD
392 } else if (sc.ch == '\'') {
393 sc.SetState(SCE_C_CHARACTER);
1dcf666d
RD
394 } else if (sc.ch == '#') {
395 if (sc.Match("###")) {
396 sc.SetState(SCE_COFFEESCRIPT_COMMENTBLOCK);
397 } else {
398 sc.SetState(SCE_C_COMMENTLINE);
399 }
b8b0e402
RD
400 } else if (isoperator(static_cast<char>(sc.ch))) {
401 sc.SetState(SCE_C_OPERATOR);
f6bcfd97 402 }
f6bcfd97 403 }
9e730a78 404
1e9bafca 405 if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
b8b0e402 406 chPrevNonWhite = sc.ch;
65ec6247
RD
407 visibleChars++;
408 }
1e9bafca 409 continuationLine = false;
f6bcfd97 410 }
1dcf666d
RD
411 // Change temporary coffeescript states into standard C ones.
412 switch (sc.state) {
413 case SCE_COFFEESCRIPT_COMMENTBLOCK:
414 sc.ChangeState(SCE_C_COMMENT);
415 break;
416 case SCE_COFFEESCRIPT_VERBOSE_REGEX:
417 sc.ChangeState(SCE_C_REGEX);
418 break;
419 case SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT:
420 sc.ChangeState(SCE_C_COMMENTLINE);
421 break;
422 }
b8b0e402 423 sc.Complete();
65ec6247 424}
f6bcfd97 425
1dcf666d
RD
426static bool IsCommentLine(int line, Accessor &styler) {
427 int pos = styler.LineStart(line);
428 int eol_pos = styler.LineStart(line + 1) - 1;
429 for (int i = pos; i < eol_pos; i++) {
430 char ch = styler[i];
431 if (ch == '#')
432 return true;
433 else if (ch == '/'
434 && i < eol_pos - 1
435 && styler[i + 1] == '*')
436 return true;
437 else if (ch != ' ' && ch != '\t')
438 return false;
439 }
440 return false;
a834585d
RD
441}
442
1dcf666d
RD
443static void FoldCoffeeScriptDoc(unsigned int startPos, int length, int,
444 WordList *[], Accessor &styler) {
445 // A simplified version of FoldPyDoc
446 const int maxPos = startPos + length;
447 const int maxLines = styler.GetLine(maxPos - 1); // Requested last line
448 const int docLines = styler.GetLine(styler.Length() - 1); // Available last line
9e96e16f 449
1dcf666d
RD
450 // property fold.coffeescript.comment
451 const bool foldComment = styler.GetPropertyInt("fold.coffeescript.comment") != 0;
9e96e16f 452
1dcf666d 453 const bool foldCompact = styler.GetPropertyInt("fold.compact") != 0;
9e96e16f 454
1dcf666d
RD
455 // Backtrack to previous non-blank line so we can determine indent level
456 // for any white space lines
457 // and so we can fix any preceding fold level (which is why we go back
458 // at least one line in all cases)
459 int spaceFlags = 0;
65ec6247 460 int lineCurrent = styler.GetLine(startPos);
1dcf666d
RD
461 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
462 while (lineCurrent > 0) {
463 lineCurrent--;
464 indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
465 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)
466 && !IsCommentLine(lineCurrent, styler))
467 break;
468 }
469 int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
470
471 // Set up initial loop state
472 int prevComment = 0;
473 if (lineCurrent >= 1)
474 prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);
475
476 // Process all characters to end of requested range
477 // or comment that hangs over the end of the range. Cap processing in all cases
478 // to end of document (in case of comment at end).
479 while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevComment)) {
480
481 // Gather info
482 int lev = indentCurrent;
483 int lineNext = lineCurrent + 1;
484 int indentNext = indentCurrent;
485 if (lineNext <= docLines) {
486 // Information about next line is only available if not at end of document
487 indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
65ec6247 488 }
1dcf666d
RD
489 const int comment = foldComment && IsCommentLine(lineCurrent, styler);
490 const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&
491 IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE));
492 const int comment_continue = (comment && prevComment);
493 if (!comment)
494 indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
495 if (indentNext & SC_FOLDLEVELWHITEFLAG)
496 indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
497
498 if (comment_start) {
499 // Place fold point at start of a block of comments
500 lev |= SC_FOLDLEVELHEADERFLAG;
501 } else if (comment_continue) {
502 // Add level to rest of lines in the block
503 lev = lev + 1;
a834585d 504 }
1dcf666d
RD
505
506 // Skip past any blank lines for next indent level info; we skip also
507 // comments (all comments, not just those starting in column 0)
508 // which effectively folds them into surrounding code rather
509 // than screwing up folding.
510
511 while ((lineNext < docLines) &&
512 ((indentNext & SC_FOLDLEVELWHITEFLAG) ||
513 (lineNext <= docLines && IsCommentLine(lineNext, styler)))) {
514
515 lineNext++;
516 indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
a834585d 517 }
1dcf666d
RD
518
519 const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK;
520 const int levelBeforeComments = Platform::Maximum(indentCurrentLevel,levelAfterComments);
521
522 // Now set all the indent levels on the lines we skipped
523 // Do this from end to start. Once we encounter one line
524 // which is indented more than the line after the end of
525 // the comment-block, use the level of the block before
526
527 int skipLine = lineNext;
528 int skipLevel = levelAfterComments;
529
530 while (--skipLine > lineCurrent) {
531 int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL);
532
533 if (foldCompact) {
534 if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)
535 skipLevel = levelBeforeComments;
536
537 int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
538
539 styler.SetLevel(skipLine, skipLevel | whiteFlag);
540 } else {
541 if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments &&
542 !(skipLineIndent & SC_FOLDLEVELWHITEFLAG) &&
543 !IsCommentLine(skipLine, styler))
544 skipLevel = levelBeforeComments;
545
546 styler.SetLevel(skipLine, skipLevel);
65ec6247
RD
547 }
548 }
1dcf666d
RD
549
550 // Set fold header on non-comment line
551 if (!comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
552 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
65ec6247 553 lev |= SC_FOLDLEVELHEADERFLAG;
65ec6247 554 }
f6bcfd97 555
1dcf666d
RD
556 // Keep track of block comment state of previous line
557 prevComment = comment_start || comment_continue;
9e730a78 558
1dcf666d
RD
559 // Set fold level for this line and move to next line
560 styler.SetLevel(lineCurrent, lev);
561 indentCurrent = indentNext;
562 lineCurrent = lineNext;
563 }
9e730a78
RD
564}
565
1dcf666d
RD
566static const char *const csWordLists[] = {
567 "Keywords",
568 0,
569};
9e730a78 570
1dcf666d 571LexerModule lmCoffeeScript(SCLEX_COFFEESCRIPT, ColouriseCoffeeScriptDoc, "coffeescript", FoldCoffeeScriptDoc, csWordLists);