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