Improve API docs related to keybindings configuration file
[geany-mirror.git] / scintilla / lexers / LexPascal.cxx
blobb7213bb8714cbfeb81686dd5aa43f180c71d1338
1 // Scintilla source code edit control
2 /** @file LexPascal.cxx
3 ** Lexer for Pascal.
4 ** Written by Laurent le Tynevez
5 ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
6 ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
7 ** Completely rewritten by Marko Njezic <sf@maxempire.com> October 2008
8 **/
12 A few words about features of the new completely rewritten LexPascal...
14 Generally speaking LexPascal tries to support all available Delphi features (up
15 to Delphi XE4 at this time).
17 ~ HIGHLIGHTING:
19 If you enable "lexer.pascal.smart.highlighting" property, some keywords will
20 only be highlighted in appropriate context. As implemented those are keywords
21 related to property and DLL exports declarations (similar to how Delphi IDE
22 works).
24 For example, keywords "read" and "write" will only be highlighted if they are in
25 property declaration:
27 property MyProperty: boolean read FMyProperty write FMyProperty;
29 ~ FOLDING:
31 Folding is supported in the following cases:
33 - Folding of stream-like comments
34 - Folding of groups of consecutive line comments
35 - Folding of preprocessor blocks (the following preprocessor blocks are
36 supported: IF / IFEND; IFDEF, IFNDEF, IFOPT / ENDIF and REGION / ENDREGION
37 blocks), including nesting of preprocessor blocks up to 255 levels
38 - Folding of code blocks on appropriate keywords (the following code blocks are
39 supported: "begin, asm, record, try, case / end" blocks, class & object
40 declarations and interface declarations)
42 Remarks:
44 - Folding of code blocks tries to handle all special cases in which folding
45 should not occur. As implemented those are:
47 1. Structure "record case / end" (there's only one "end" statement and "case" is
48 ignored as fold point)
49 2. Forward class declarations ("type TMyClass = class;") and object method
50 declarations ("TNotifyEvent = procedure(Sender: TObject) of object;") are
51 ignored as fold points
52 3. Simplified complete class declarations ("type TMyClass = class(TObject);")
53 are ignored as fold points
54 4. Every other situation when class keyword doesn't actually start class
55 declaration ("class procedure", "class function", "class of", "class var",
56 "class property" and "class operator")
57 5. Forward (disp)interface declarations ("type IMyInterface = interface;") are
58 ignored as fold points
60 - Folding of code blocks inside preprocessor blocks is disabled (any comments
61 inside them will be folded fine) because there is no guarantee that complete
62 code block will be contained inside folded preprocessor block in which case
63 folded code block could end prematurely at the end of preprocessor block if
64 there is no closing statement inside. This was done in order to properly process
65 document that may contain something like this:
67 type
68 {$IFDEF UNICODE}
69 TMyClass = class(UnicodeAncestor)
70 {$ELSE}
71 TMyClass = class(AnsiAncestor)
72 {$ENDIF}
73 private
74 ...
75 public
76 ...
77 published
78 ...
79 end;
81 If class declarations were folded, then the second class declaration would end
82 at "$ENDIF" statement, first class statement would end at "end;" statement and
83 preprocessor "$IFDEF" block would go all the way to the end of document.
84 However, having in mind all this, if you want to enable folding of code blocks
85 inside preprocessor blocks, you can disable folding of preprocessor blocks by
86 changing "fold.preprocessor" property, in which case everything inside them
87 would be folded.
89 ~ KEYWORDS:
91 The list of keywords that can be used in pascal.properties file (up to Delphi
92 XE4):
94 - Keywords: absolute abstract and array as asm assembler automated begin case
95 cdecl class const constructor delayed deprecated destructor dispid dispinterface
96 div do downto dynamic else end except experimental export exports external far
97 file final finalization finally for forward function goto helper if
98 implementation in inherited initialization inline interface is label library
99 message mod near nil not object of on operator or out overload override packed
100 pascal platform private procedure program property protected public published
101 raise record reference register reintroduce repeat resourcestring safecall
102 sealed set shl shr static stdcall strict string then threadvar to try type unit
103 unsafe until uses var varargs virtual while winapi with xor
105 - Keywords related to the "smart highlithing" feature: add default implements
106 index name nodefault read readonly remove stored write writeonly
108 - Keywords related to Delphi packages (in addition to all above): package
109 contains requires
113 #include <stdlib.h>
114 #include <string.h>
115 #include <stdio.h>
116 #include <stdarg.h>
117 #include <assert.h>
118 #include <ctype.h>
120 #include "ILexer.h"
121 #include "Scintilla.h"
122 #include "SciLexer.h"
124 #include "WordList.h"
125 #include "LexAccessor.h"
126 #include "Accessor.h"
127 #include "StyleContext.h"
128 #include "CharacterSet.h"
129 #include "LexerModule.h"
131 #ifdef SCI_NAMESPACE
132 using namespace Scintilla;
133 #endif
135 static void GetRangeLowered(Sci_PositionU start,
136 Sci_PositionU end,
137 Accessor &styler,
138 char *s,
139 Sci_PositionU len) {
140 Sci_PositionU i = 0;
141 while ((i < end - start + 1) && (i < len-1)) {
142 s[i] = static_cast<char>(tolower(styler[start + i]));
143 i++;
145 s[i] = '\0';
148 static void GetForwardRangeLowered(Sci_PositionU start,
149 CharacterSet &charSet,
150 Accessor &styler,
151 char *s,
152 Sci_PositionU len) {
153 Sci_PositionU i = 0;
154 while ((i < len-1) && charSet.Contains(styler.SafeGetCharAt(start + i))) {
155 s[i] = static_cast<char>(tolower(styler.SafeGetCharAt(start + i)));
156 i++;
158 s[i] = '\0';
162 enum {
163 stateInAsm = 0x1000,
164 stateInProperty = 0x2000,
165 stateInExport = 0x4000,
166 stateFoldInPreprocessor = 0x0100,
167 stateFoldInRecord = 0x0200,
168 stateFoldInPreprocessorLevelMask = 0x00FF,
169 stateFoldMaskAll = 0x0FFF
172 static void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLineState, bool bSmartHighlighting) {
173 WordList& keywords = *keywordlists[0];
175 char s[100];
176 sc.GetCurrentLowered(s, sizeof(s));
177 if (keywords.InList(s)) {
178 if (curLineState & stateInAsm) {
179 if (strcmp(s, "end") == 0 && sc.GetRelative(-4) != '@') {
180 curLineState &= ~stateInAsm;
181 sc.ChangeState(SCE_PAS_WORD);
182 } else {
183 sc.ChangeState(SCE_PAS_ASM);
185 } else {
186 bool ignoreKeyword = false;
187 if (strcmp(s, "asm") == 0) {
188 curLineState |= stateInAsm;
189 } else if (bSmartHighlighting) {
190 if (strcmp(s, "property") == 0) {
191 curLineState |= stateInProperty;
192 } else if (strcmp(s, "exports") == 0) {
193 curLineState |= stateInExport;
194 } else if (!(curLineState & (stateInProperty | stateInExport)) && strcmp(s, "index") == 0) {
195 ignoreKeyword = true;
196 } else if (!(curLineState & stateInExport) && strcmp(s, "name") == 0) {
197 ignoreKeyword = true;
198 } else if (!(curLineState & stateInProperty) &&
199 (strcmp(s, "read") == 0 || strcmp(s, "write") == 0 ||
200 strcmp(s, "default") == 0 || strcmp(s, "nodefault") == 0 ||
201 strcmp(s, "stored") == 0 || strcmp(s, "implements") == 0 ||
202 strcmp(s, "readonly") == 0 || strcmp(s, "writeonly") == 0 ||
203 strcmp(s, "add") == 0 || strcmp(s, "remove") == 0)) {
204 ignoreKeyword = true;
207 if (!ignoreKeyword) {
208 sc.ChangeState(SCE_PAS_WORD);
211 } else if (curLineState & stateInAsm) {
212 sc.ChangeState(SCE_PAS_ASM);
214 sc.SetState(SCE_PAS_DEFAULT);
217 static void ColourisePascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
218 Accessor &styler) {
219 bool bSmartHighlighting = styler.GetPropertyInt("lexer.pascal.smart.highlighting", 1) != 0;
221 CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
222 CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
223 CharacterSet setNumber(CharacterSet::setDigits, ".-+eE");
224 CharacterSet setHexNumber(CharacterSet::setDigits, "abcdefABCDEF");
225 CharacterSet setOperator(CharacterSet::setNone, "#$&'()*+,-./:;<=>@[]^{}");
227 Sci_Position curLine = styler.GetLine(startPos);
228 int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
230 StyleContext sc(startPos, length, initStyle, styler);
232 for (; sc.More(); sc.Forward()) {
233 if (sc.atLineEnd) {
234 // Update the line state, so it can be seen by next line
235 curLine = styler.GetLine(sc.currentPos);
236 styler.SetLineState(curLine, curLineState);
239 // Determine if the current state should terminate.
240 switch (sc.state) {
241 case SCE_PAS_NUMBER:
242 if (!setNumber.Contains(sc.ch) || (sc.ch == '.' && sc.chNext == '.')) {
243 sc.SetState(SCE_PAS_DEFAULT);
244 } else if (sc.ch == '-' || sc.ch == '+') {
245 if (sc.chPrev != 'E' && sc.chPrev != 'e') {
246 sc.SetState(SCE_PAS_DEFAULT);
249 break;
250 case SCE_PAS_IDENTIFIER:
251 if (!setWord.Contains(sc.ch)) {
252 ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
254 break;
255 case SCE_PAS_HEXNUMBER:
256 if (!setHexNumber.Contains(sc.ch)) {
257 sc.SetState(SCE_PAS_DEFAULT);
259 break;
260 case SCE_PAS_COMMENT:
261 case SCE_PAS_PREPROCESSOR:
262 if (sc.ch == '}') {
263 sc.ForwardSetState(SCE_PAS_DEFAULT);
265 break;
266 case SCE_PAS_COMMENT2:
267 case SCE_PAS_PREPROCESSOR2:
268 if (sc.Match('*', ')')) {
269 sc.Forward();
270 sc.ForwardSetState(SCE_PAS_DEFAULT);
272 break;
273 case SCE_PAS_COMMENTLINE:
274 if (sc.atLineStart) {
275 sc.SetState(SCE_PAS_DEFAULT);
277 break;
278 case SCE_PAS_STRING:
279 if (sc.atLineEnd) {
280 sc.ChangeState(SCE_PAS_STRINGEOL);
281 } else if (sc.ch == '\'' && sc.chNext == '\'') {
282 sc.Forward();
283 } else if (sc.ch == '\'') {
284 sc.ForwardSetState(SCE_PAS_DEFAULT);
286 break;
287 case SCE_PAS_STRINGEOL:
288 if (sc.atLineStart) {
289 sc.SetState(SCE_PAS_DEFAULT);
291 break;
292 case SCE_PAS_CHARACTER:
293 if (!setHexNumber.Contains(sc.ch) && sc.ch != '$') {
294 sc.SetState(SCE_PAS_DEFAULT);
296 break;
297 case SCE_PAS_OPERATOR:
298 if (bSmartHighlighting && sc.chPrev == ';') {
299 curLineState &= ~(stateInProperty | stateInExport);
301 sc.SetState(SCE_PAS_DEFAULT);
302 break;
303 case SCE_PAS_ASM:
304 sc.SetState(SCE_PAS_DEFAULT);
305 break;
308 // Determine if a new state should be entered.
309 if (sc.state == SCE_PAS_DEFAULT) {
310 if (IsADigit(sc.ch) && !(curLineState & stateInAsm)) {
311 sc.SetState(SCE_PAS_NUMBER);
312 } else if (setWordStart.Contains(sc.ch)) {
313 sc.SetState(SCE_PAS_IDENTIFIER);
314 } else if (sc.ch == '$' && !(curLineState & stateInAsm)) {
315 sc.SetState(SCE_PAS_HEXNUMBER);
316 } else if (sc.Match('{', '$')) {
317 sc.SetState(SCE_PAS_PREPROCESSOR);
318 } else if (sc.ch == '{') {
319 sc.SetState(SCE_PAS_COMMENT);
320 } else if (sc.Match("(*$")) {
321 sc.SetState(SCE_PAS_PREPROCESSOR2);
322 } else if (sc.Match('(', '*')) {
323 sc.SetState(SCE_PAS_COMMENT2);
324 sc.Forward(); // Eat the * so it isn't used for the end of the comment
325 } else if (sc.Match('/', '/')) {
326 sc.SetState(SCE_PAS_COMMENTLINE);
327 } else if (sc.ch == '\'') {
328 sc.SetState(SCE_PAS_STRING);
329 } else if (sc.ch == '#') {
330 sc.SetState(SCE_PAS_CHARACTER);
331 } else if (setOperator.Contains(sc.ch) && !(curLineState & stateInAsm)) {
332 sc.SetState(SCE_PAS_OPERATOR);
333 } else if (curLineState & stateInAsm) {
334 sc.SetState(SCE_PAS_ASM);
339 if (sc.state == SCE_PAS_IDENTIFIER && setWord.Contains(sc.chPrev)) {
340 ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
343 sc.Complete();
346 static bool IsStreamCommentStyle(int style) {
347 return style == SCE_PAS_COMMENT || style == SCE_PAS_COMMENT2;
350 static bool IsCommentLine(Sci_Position line, Accessor &styler) {
351 Sci_Position pos = styler.LineStart(line);
352 Sci_Position eolPos = styler.LineStart(line + 1) - 1;
353 for (Sci_Position i = pos; i < eolPos; i++) {
354 char ch = styler[i];
355 char chNext = styler.SafeGetCharAt(i + 1);
356 int style = styler.StyleAt(i);
357 if (ch == '/' && chNext == '/' && style == SCE_PAS_COMMENTLINE) {
358 return true;
359 } else if (!IsASpaceOrTab(ch)) {
360 return false;
363 return false;
366 static unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) {
367 return lineFoldStateCurrent & stateFoldInPreprocessorLevelMask;
370 static void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) {
371 lineFoldStateCurrent &= ~stateFoldInPreprocessorLevelMask;
372 lineFoldStateCurrent |= nestLevel & stateFoldInPreprocessorLevelMask;
375 static void ClassifyPascalPreprocessorFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
376 Sci_PositionU startPos, Accessor &styler) {
377 CharacterSet setWord(CharacterSet::setAlpha);
379 char s[11]; // Size of the longest possible keyword + one additional character + null
380 GetForwardRangeLowered(startPos, setWord, styler, s, sizeof(s));
382 unsigned int nestLevel = GetFoldInPreprocessorLevelFlag(lineFoldStateCurrent);
384 if (strcmp(s, "if") == 0 ||
385 strcmp(s, "ifdef") == 0 ||
386 strcmp(s, "ifndef") == 0 ||
387 strcmp(s, "ifopt") == 0 ||
388 strcmp(s, "region") == 0) {
389 nestLevel++;
390 SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel);
391 lineFoldStateCurrent |= stateFoldInPreprocessor;
392 levelCurrent++;
393 } else if (strcmp(s, "endif") == 0 ||
394 strcmp(s, "ifend") == 0 ||
395 strcmp(s, "endregion") == 0) {
396 nestLevel--;
397 SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel);
398 if (nestLevel == 0) {
399 lineFoldStateCurrent &= ~stateFoldInPreprocessor;
401 levelCurrent--;
402 if (levelCurrent < SC_FOLDLEVELBASE) {
403 levelCurrent = SC_FOLDLEVELBASE;
408 static Sci_PositionU SkipWhiteSpace(Sci_PositionU currentPos, Sci_PositionU endPos,
409 Accessor &styler, bool includeChars = false) {
410 CharacterSet setWord(CharacterSet::setAlphaNum, "_");
411 Sci_PositionU j = currentPos + 1;
412 char ch = styler.SafeGetCharAt(j);
413 while ((j < endPos) && (IsASpaceOrTab(ch) || ch == '\r' || ch == '\n' ||
414 IsStreamCommentStyle(styler.StyleAt(j)) || (includeChars && setWord.Contains(ch)))) {
415 j++;
416 ch = styler.SafeGetCharAt(j);
418 return j;
421 static void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent,
422 Sci_Position startPos, Sci_PositionU endPos,
423 Sci_PositionU lastStart, Sci_PositionU currentPos, Accessor &styler) {
424 char s[100];
425 GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s));
427 if (strcmp(s, "record") == 0) {
428 lineFoldStateCurrent |= stateFoldInRecord;
429 levelCurrent++;
430 } else if (strcmp(s, "begin") == 0 ||
431 strcmp(s, "asm") == 0 ||
432 strcmp(s, "try") == 0 ||
433 (strcmp(s, "case") == 0 && !(lineFoldStateCurrent & stateFoldInRecord))) {
434 levelCurrent++;
435 } else if (strcmp(s, "class") == 0 || strcmp(s, "object") == 0) {
436 // "class" & "object" keywords require special handling...
437 bool ignoreKeyword = false;
438 Sci_PositionU j = SkipWhiteSpace(currentPos, endPos, styler);
439 if (j < endPos) {
440 CharacterSet setWordStart(CharacterSet::setAlpha, "_");
441 CharacterSet setWord(CharacterSet::setAlphaNum, "_");
443 if (styler.SafeGetCharAt(j) == ';') {
444 // Handle forward class declarations ("type TMyClass = class;")
445 // and object method declarations ("TNotifyEvent = procedure(Sender: TObject) of object;")
446 ignoreKeyword = true;
447 } else if (strcmp(s, "class") == 0) {
448 // "class" keyword has a few more special cases...
449 if (styler.SafeGetCharAt(j) == '(') {
450 // Handle simplified complete class declarations ("type TMyClass = class(TObject);")
451 j = SkipWhiteSpace(j, endPos, styler, true);
452 if (j < endPos && styler.SafeGetCharAt(j) == ')') {
453 j = SkipWhiteSpace(j, endPos, styler);
454 if (j < endPos && styler.SafeGetCharAt(j) == ';') {
455 ignoreKeyword = true;
458 } else if (setWordStart.Contains(styler.SafeGetCharAt(j))) {
459 char s2[11]; // Size of the longest possible keyword + one additional character + null
460 GetForwardRangeLowered(j, setWord, styler, s2, sizeof(s2));
462 if (strcmp(s2, "procedure") == 0 ||
463 strcmp(s2, "function") == 0 ||
464 strcmp(s2, "of") == 0 ||
465 strcmp(s2, "var") == 0 ||
466 strcmp(s2, "property") == 0 ||
467 strcmp(s2, "operator") == 0) {
468 ignoreKeyword = true;
473 if (!ignoreKeyword) {
474 levelCurrent++;
476 } else if (strcmp(s, "interface") == 0) {
477 // "interface" keyword requires special handling...
478 bool ignoreKeyword = true;
479 Sci_Position j = lastStart - 1;
480 char ch = styler.SafeGetCharAt(j);
481 while ((j >= startPos) && (IsASpaceOrTab(ch) || ch == '\r' || ch == '\n' ||
482 IsStreamCommentStyle(styler.StyleAt(j)))) {
483 j--;
484 ch = styler.SafeGetCharAt(j);
486 if (j >= startPos && styler.SafeGetCharAt(j) == '=') {
487 ignoreKeyword = false;
489 if (!ignoreKeyword) {
490 Sci_PositionU k = SkipWhiteSpace(currentPos, endPos, styler);
491 if (k < endPos && styler.SafeGetCharAt(k) == ';') {
492 // Handle forward interface declarations ("type IMyInterface = interface;")
493 ignoreKeyword = true;
496 if (!ignoreKeyword) {
497 levelCurrent++;
499 } else if (strcmp(s, "dispinterface") == 0) {
500 // "dispinterface" keyword requires special handling...
501 bool ignoreKeyword = false;
502 Sci_PositionU j = SkipWhiteSpace(currentPos, endPos, styler);
503 if (j < endPos && styler.SafeGetCharAt(j) == ';') {
504 // Handle forward dispinterface declarations ("type IMyInterface = dispinterface;")
505 ignoreKeyword = true;
507 if (!ignoreKeyword) {
508 levelCurrent++;
510 } else if (strcmp(s, "end") == 0) {
511 lineFoldStateCurrent &= ~stateFoldInRecord;
512 levelCurrent--;
513 if (levelCurrent < SC_FOLDLEVELBASE) {
514 levelCurrent = SC_FOLDLEVELBASE;
519 static void FoldPascalDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],
520 Accessor &styler) {
521 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
522 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
523 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
524 Sci_PositionU endPos = startPos + length;
525 int visibleChars = 0;
526 Sci_Position lineCurrent = styler.GetLine(startPos);
527 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
528 int levelCurrent = levelPrev;
529 int lineFoldStateCurrent = lineCurrent > 0 ? styler.GetLineState(lineCurrent - 1) & stateFoldMaskAll : 0;
530 char chNext = styler[startPos];
531 int styleNext = styler.StyleAt(startPos);
532 int style = initStyle;
534 Sci_Position lastStart = 0;
535 CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
537 for (Sci_PositionU i = startPos; i < endPos; i++) {
538 char ch = chNext;
539 chNext = styler.SafeGetCharAt(i + 1);
540 int stylePrev = style;
541 style = styleNext;
542 styleNext = styler.StyleAt(i + 1);
543 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
545 if (foldComment && IsStreamCommentStyle(style)) {
546 if (!IsStreamCommentStyle(stylePrev)) {
547 levelCurrent++;
548 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
549 // Comments don't end at end of line and the next character may be unstyled.
550 levelCurrent--;
553 if (foldComment && atEOL && IsCommentLine(lineCurrent, styler))
555 if (!IsCommentLine(lineCurrent - 1, styler)
556 && IsCommentLine(lineCurrent + 1, styler))
557 levelCurrent++;
558 else if (IsCommentLine(lineCurrent - 1, styler)
559 && !IsCommentLine(lineCurrent+1, styler))
560 levelCurrent--;
562 if (foldPreprocessor) {
563 if (style == SCE_PAS_PREPROCESSOR && ch == '{' && chNext == '$') {
564 ClassifyPascalPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 2, styler);
565 } else if (style == SCE_PAS_PREPROCESSOR2 && ch == '(' && chNext == '*'
566 && styler.SafeGetCharAt(i + 2) == '$') {
567 ClassifyPascalPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 3, styler);
571 if (stylePrev != SCE_PAS_WORD && style == SCE_PAS_WORD)
573 // Store last word start point.
574 lastStart = i;
576 if (stylePrev == SCE_PAS_WORD && !(lineFoldStateCurrent & stateFoldInPreprocessor)) {
577 if(setWord.Contains(ch) && !setWord.Contains(chNext)) {
578 ClassifyPascalWordFoldPoint(levelCurrent, lineFoldStateCurrent, startPos, endPos, lastStart, i, styler);
582 if (!IsASpace(ch))
583 visibleChars++;
585 if (atEOL) {
586 int lev = levelPrev;
587 if (visibleChars == 0 && foldCompact)
588 lev |= SC_FOLDLEVELWHITEFLAG;
589 if ((levelCurrent > levelPrev) && (visibleChars > 0))
590 lev |= SC_FOLDLEVELHEADERFLAG;
591 if (lev != styler.LevelAt(lineCurrent)) {
592 styler.SetLevel(lineCurrent, lev);
594 int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent;
595 styler.SetLineState(lineCurrent, newLineState);
596 lineCurrent++;
597 levelPrev = levelCurrent;
598 visibleChars = 0;
602 // If we didn't reach the EOL in previous loop, store line level and whitespace information.
603 // The rest will be filled in later...
604 int lev = levelPrev;
605 if (visibleChars == 0 && foldCompact)
606 lev |= SC_FOLDLEVELWHITEFLAG;
607 styler.SetLevel(lineCurrent, lev);
610 static const char * const pascalWordListDesc[] = {
611 "Keywords",
615 LexerModule lmPascal(SCLEX_PASCAL, ColourisePascalDoc, "pascal", FoldPascalDoc, pascalWordListDesc);