1 // Scintilla source code edit control
2 /** @file LexPascal.cxx
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
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).
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
24 For example, keywords "read" and "write" will only be highlighted if they are in
27 property MyProperty: boolean read FMyProperty write FMyProperty;
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)
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:
69 TMyClass = class(UnicodeAncestor)
71 TMyClass = class(AnsiAncestor)
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
91 The list of keywords that can be used in pascal.properties file (up to Delphi
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
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 using namespace Scintilla
;
133 static void GetRangeLowered(Sci_PositionU start
,
139 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
140 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
146 static void GetForwardRangeLowered(Sci_PositionU start
,
147 CharacterSet
&charSet
,
152 while ((i
< len
-1) && charSet
.Contains(styler
.SafeGetCharAt(start
+ i
))) {
153 s
[i
] = static_cast<char>(tolower(styler
.SafeGetCharAt(start
+ i
)));
162 stateInProperty
= 0x2000,
163 stateInExport
= 0x4000,
164 stateFoldInPreprocessor
= 0x0100,
165 stateFoldInRecord
= 0x0200,
166 stateFoldInPreprocessorLevelMask
= 0x00FF,
167 stateFoldMaskAll
= 0x0FFF
170 static void ClassifyPascalWord(WordList
*keywordlists
[], StyleContext
&sc
, int &curLineState
, bool bSmartHighlighting
) {
171 WordList
& keywords
= *keywordlists
[0];
174 sc
.GetCurrentLowered(s
, sizeof(s
));
175 if (keywords
.InList(s
)) {
176 if (curLineState
& stateInAsm
) {
177 if (strcmp(s
, "end") == 0 && sc
.GetRelative(-4) != '@') {
178 curLineState
&= ~stateInAsm
;
179 sc
.ChangeState(SCE_PAS_WORD
);
181 sc
.ChangeState(SCE_PAS_ASM
);
184 bool ignoreKeyword
= false;
185 if (strcmp(s
, "asm") == 0) {
186 curLineState
|= stateInAsm
;
187 } else if (bSmartHighlighting
) {
188 if (strcmp(s
, "property") == 0) {
189 curLineState
|= stateInProperty
;
190 } else if (strcmp(s
, "exports") == 0) {
191 curLineState
|= stateInExport
;
192 } else if (!(curLineState
& (stateInProperty
| stateInExport
)) && strcmp(s
, "index") == 0) {
193 ignoreKeyword
= true;
194 } else if (!(curLineState
& stateInExport
) && strcmp(s
, "name") == 0) {
195 ignoreKeyword
= true;
196 } else if (!(curLineState
& stateInProperty
) &&
197 (strcmp(s
, "read") == 0 || strcmp(s
, "write") == 0 ||
198 strcmp(s
, "default") == 0 || strcmp(s
, "nodefault") == 0 ||
199 strcmp(s
, "stored") == 0 || strcmp(s
, "implements") == 0 ||
200 strcmp(s
, "readonly") == 0 || strcmp(s
, "writeonly") == 0 ||
201 strcmp(s
, "add") == 0 || strcmp(s
, "remove") == 0)) {
202 ignoreKeyword
= true;
205 if (!ignoreKeyword
) {
206 sc
.ChangeState(SCE_PAS_WORD
);
209 } else if (curLineState
& stateInAsm
) {
210 sc
.ChangeState(SCE_PAS_ASM
);
212 sc
.SetState(SCE_PAS_DEFAULT
);
215 static void ColourisePascalDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*keywordlists
[],
217 bool bSmartHighlighting
= styler
.GetPropertyInt("lexer.pascal.smart.highlighting", 1) != 0;
219 CharacterSet
setWordStart(CharacterSet::setAlpha
, "_", 0x80, true);
220 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_", 0x80, true);
221 CharacterSet
setNumber(CharacterSet::setDigits
, ".-+eE");
222 CharacterSet
setHexNumber(CharacterSet::setDigits
, "abcdefABCDEF");
223 CharacterSet
setOperator(CharacterSet::setNone
, "#$&'()*+,-./:;<=>@[]^{}");
225 Sci_Position curLine
= styler
.GetLine(startPos
);
226 int curLineState
= curLine
> 0 ? styler
.GetLineState(curLine
- 1) : 0;
228 StyleContext
sc(startPos
, length
, initStyle
, styler
);
230 for (; sc
.More(); sc
.Forward()) {
232 // Update the line state, so it can be seen by next line
233 curLine
= styler
.GetLine(sc
.currentPos
);
234 styler
.SetLineState(curLine
, curLineState
);
237 // Determine if the current state should terminate.
240 if (!setNumber
.Contains(sc
.ch
) || (sc
.ch
== '.' && sc
.chNext
== '.')) {
241 sc
.SetState(SCE_PAS_DEFAULT
);
242 } else if (sc
.ch
== '-' || sc
.ch
== '+') {
243 if (sc
.chPrev
!= 'E' && sc
.chPrev
!= 'e') {
244 sc
.SetState(SCE_PAS_DEFAULT
);
248 case SCE_PAS_IDENTIFIER
:
249 if (!setWord
.Contains(sc
.ch
)) {
250 ClassifyPascalWord(keywordlists
, sc
, curLineState
, bSmartHighlighting
);
253 case SCE_PAS_HEXNUMBER
:
254 if (!setHexNumber
.Contains(sc
.ch
)) {
255 sc
.SetState(SCE_PAS_DEFAULT
);
258 case SCE_PAS_COMMENT
:
259 case SCE_PAS_PREPROCESSOR
:
261 sc
.ForwardSetState(SCE_PAS_DEFAULT
);
264 case SCE_PAS_COMMENT2
:
265 case SCE_PAS_PREPROCESSOR2
:
266 if (sc
.Match('*', ')')) {
268 sc
.ForwardSetState(SCE_PAS_DEFAULT
);
271 case SCE_PAS_COMMENTLINE
:
272 if (sc
.atLineStart
) {
273 sc
.SetState(SCE_PAS_DEFAULT
);
278 sc
.ChangeState(SCE_PAS_STRINGEOL
);
279 } else if (sc
.ch
== '\'' && sc
.chNext
== '\'') {
281 } else if (sc
.ch
== '\'') {
282 sc
.ForwardSetState(SCE_PAS_DEFAULT
);
285 case SCE_PAS_STRINGEOL
:
286 if (sc
.atLineStart
) {
287 sc
.SetState(SCE_PAS_DEFAULT
);
290 case SCE_PAS_CHARACTER
:
291 if (!setHexNumber
.Contains(sc
.ch
) && sc
.ch
!= '$') {
292 sc
.SetState(SCE_PAS_DEFAULT
);
295 case SCE_PAS_OPERATOR
:
296 if (bSmartHighlighting
&& sc
.chPrev
== ';') {
297 curLineState
&= ~(stateInProperty
| stateInExport
);
299 sc
.SetState(SCE_PAS_DEFAULT
);
302 sc
.SetState(SCE_PAS_DEFAULT
);
306 // Determine if a new state should be entered.
307 if (sc
.state
== SCE_PAS_DEFAULT
) {
308 if (IsADigit(sc
.ch
) && !(curLineState
& stateInAsm
)) {
309 sc
.SetState(SCE_PAS_NUMBER
);
310 } else if (setWordStart
.Contains(sc
.ch
)) {
311 sc
.SetState(SCE_PAS_IDENTIFIER
);
312 } else if (sc
.ch
== '$' && !(curLineState
& stateInAsm
)) {
313 sc
.SetState(SCE_PAS_HEXNUMBER
);
314 } else if (sc
.Match('{', '$')) {
315 sc
.SetState(SCE_PAS_PREPROCESSOR
);
316 } else if (sc
.ch
== '{') {
317 sc
.SetState(SCE_PAS_COMMENT
);
318 } else if (sc
.Match("(*$")) {
319 sc
.SetState(SCE_PAS_PREPROCESSOR2
);
320 } else if (sc
.Match('(', '*')) {
321 sc
.SetState(SCE_PAS_COMMENT2
);
322 sc
.Forward(); // Eat the * so it isn't used for the end of the comment
323 } else if (sc
.Match('/', '/')) {
324 sc
.SetState(SCE_PAS_COMMENTLINE
);
325 } else if (sc
.ch
== '\'') {
326 sc
.SetState(SCE_PAS_STRING
);
327 } else if (sc
.ch
== '#') {
328 sc
.SetState(SCE_PAS_CHARACTER
);
329 } else if (setOperator
.Contains(sc
.ch
) && !(curLineState
& stateInAsm
)) {
330 sc
.SetState(SCE_PAS_OPERATOR
);
331 } else if (curLineState
& stateInAsm
) {
332 sc
.SetState(SCE_PAS_ASM
);
337 if (sc
.state
== SCE_PAS_IDENTIFIER
&& setWord
.Contains(sc
.chPrev
)) {
338 ClassifyPascalWord(keywordlists
, sc
, curLineState
, bSmartHighlighting
);
344 static bool IsStreamCommentStyle(int style
) {
345 return style
== SCE_PAS_COMMENT
|| style
== SCE_PAS_COMMENT2
;
348 static bool IsCommentLine(Sci_Position line
, Accessor
&styler
) {
349 Sci_Position pos
= styler
.LineStart(line
);
350 Sci_Position eolPos
= styler
.LineStart(line
+ 1) - 1;
351 for (Sci_Position i
= pos
; i
< eolPos
; i
++) {
353 char chNext
= styler
.SafeGetCharAt(i
+ 1);
354 int style
= styler
.StyleAt(i
);
355 if (ch
== '/' && chNext
== '/' && style
== SCE_PAS_COMMENTLINE
) {
357 } else if (!IsASpaceOrTab(ch
)) {
364 static unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent
) {
365 return lineFoldStateCurrent
& stateFoldInPreprocessorLevelMask
;
368 static void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent
, unsigned int nestLevel
) {
369 lineFoldStateCurrent
&= ~stateFoldInPreprocessorLevelMask
;
370 lineFoldStateCurrent
|= nestLevel
& stateFoldInPreprocessorLevelMask
;
373 static void ClassifyPascalPreprocessorFoldPoint(int &levelCurrent
, int &lineFoldStateCurrent
,
374 Sci_PositionU startPos
, Accessor
&styler
) {
375 CharacterSet
setWord(CharacterSet::setAlpha
);
377 char s
[11]; // Size of the longest possible keyword + one additional character + null
378 GetForwardRangeLowered(startPos
, setWord
, styler
, s
, sizeof(s
));
380 unsigned int nestLevel
= GetFoldInPreprocessorLevelFlag(lineFoldStateCurrent
);
382 if (strcmp(s
, "if") == 0 ||
383 strcmp(s
, "ifdef") == 0 ||
384 strcmp(s
, "ifndef") == 0 ||
385 strcmp(s
, "ifopt") == 0 ||
386 strcmp(s
, "region") == 0) {
388 SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent
, nestLevel
);
389 lineFoldStateCurrent
|= stateFoldInPreprocessor
;
391 } else if (strcmp(s
, "endif") == 0 ||
392 strcmp(s
, "ifend") == 0 ||
393 strcmp(s
, "endregion") == 0) {
395 SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent
, nestLevel
);
396 if (nestLevel
== 0) {
397 lineFoldStateCurrent
&= ~stateFoldInPreprocessor
;
400 if (levelCurrent
< SC_FOLDLEVELBASE
) {
401 levelCurrent
= SC_FOLDLEVELBASE
;
406 static Sci_PositionU
SkipWhiteSpace(Sci_PositionU currentPos
, Sci_PositionU endPos
,
407 Accessor
&styler
, bool includeChars
= false) {
408 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_");
409 Sci_PositionU j
= currentPos
+ 1;
410 char ch
= styler
.SafeGetCharAt(j
);
411 while ((j
< endPos
) && (IsASpaceOrTab(ch
) || ch
== '\r' || ch
== '\n' ||
412 IsStreamCommentStyle(styler
.StyleAt(j
)) || (includeChars
&& setWord
.Contains(ch
)))) {
414 ch
= styler
.SafeGetCharAt(j
);
419 static void ClassifyPascalWordFoldPoint(int &levelCurrent
, int &lineFoldStateCurrent
,
420 Sci_Position startPos
, Sci_PositionU endPos
,
421 Sci_PositionU lastStart
, Sci_PositionU currentPos
, Accessor
&styler
) {
423 GetRangeLowered(lastStart
, currentPos
, styler
, s
, sizeof(s
));
425 if (strcmp(s
, "record") == 0) {
426 lineFoldStateCurrent
|= stateFoldInRecord
;
428 } else if (strcmp(s
, "begin") == 0 ||
429 strcmp(s
, "asm") == 0 ||
430 strcmp(s
, "try") == 0 ||
431 (strcmp(s
, "case") == 0 && !(lineFoldStateCurrent
& stateFoldInRecord
))) {
433 } else if (strcmp(s
, "class") == 0 || strcmp(s
, "object") == 0) {
434 // "class" & "object" keywords require special handling...
435 bool ignoreKeyword
= false;
436 Sci_PositionU j
= SkipWhiteSpace(currentPos
, endPos
, styler
);
438 CharacterSet
setWordStart(CharacterSet::setAlpha
, "_");
439 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_");
441 if (styler
.SafeGetCharAt(j
) == ';') {
442 // Handle forward class declarations ("type TMyClass = class;")
443 // and object method declarations ("TNotifyEvent = procedure(Sender: TObject) of object;")
444 ignoreKeyword
= true;
445 } else if (strcmp(s
, "class") == 0) {
446 // "class" keyword has a few more special cases...
447 if (styler
.SafeGetCharAt(j
) == '(') {
448 // Handle simplified complete class declarations ("type TMyClass = class(TObject);")
449 j
= SkipWhiteSpace(j
, endPos
, styler
, true);
450 if (j
< endPos
&& styler
.SafeGetCharAt(j
) == ')') {
451 j
= SkipWhiteSpace(j
, endPos
, styler
);
452 if (j
< endPos
&& styler
.SafeGetCharAt(j
) == ';') {
453 ignoreKeyword
= true;
456 } else if (setWordStart
.Contains(styler
.SafeGetCharAt(j
))) {
457 char s2
[11]; // Size of the longest possible keyword + one additional character + null
458 GetForwardRangeLowered(j
, setWord
, styler
, s2
, sizeof(s2
));
460 if (strcmp(s2
, "procedure") == 0 ||
461 strcmp(s2
, "function") == 0 ||
462 strcmp(s2
, "of") == 0 ||
463 strcmp(s2
, "var") == 0 ||
464 strcmp(s2
, "property") == 0 ||
465 strcmp(s2
, "operator") == 0) {
466 ignoreKeyword
= true;
471 if (!ignoreKeyword
) {
474 } else if (strcmp(s
, "interface") == 0) {
475 // "interface" keyword requires special handling...
476 bool ignoreKeyword
= true;
477 Sci_Position j
= lastStart
- 1;
478 char ch
= styler
.SafeGetCharAt(j
);
479 while ((j
>= startPos
) && (IsASpaceOrTab(ch
) || ch
== '\r' || ch
== '\n' ||
480 IsStreamCommentStyle(styler
.StyleAt(j
)))) {
482 ch
= styler
.SafeGetCharAt(j
);
484 if (j
>= startPos
&& styler
.SafeGetCharAt(j
) == '=') {
485 ignoreKeyword
= false;
487 if (!ignoreKeyword
) {
488 Sci_PositionU k
= SkipWhiteSpace(currentPos
, endPos
, styler
);
489 if (k
< endPos
&& styler
.SafeGetCharAt(k
) == ';') {
490 // Handle forward interface declarations ("type IMyInterface = interface;")
491 ignoreKeyword
= true;
494 if (!ignoreKeyword
) {
497 } else if (strcmp(s
, "dispinterface") == 0) {
498 // "dispinterface" keyword requires special handling...
499 bool ignoreKeyword
= false;
500 Sci_PositionU j
= SkipWhiteSpace(currentPos
, endPos
, styler
);
501 if (j
< endPos
&& styler
.SafeGetCharAt(j
) == ';') {
502 // Handle forward dispinterface declarations ("type IMyInterface = dispinterface;")
503 ignoreKeyword
= true;
505 if (!ignoreKeyword
) {
508 } else if (strcmp(s
, "end") == 0) {
509 lineFoldStateCurrent
&= ~stateFoldInRecord
;
511 if (levelCurrent
< SC_FOLDLEVELBASE
) {
512 levelCurrent
= SC_FOLDLEVELBASE
;
517 static void FoldPascalDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*[],
519 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
520 bool foldPreprocessor
= styler
.GetPropertyInt("fold.preprocessor") != 0;
521 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
522 Sci_PositionU endPos
= startPos
+ length
;
523 int visibleChars
= 0;
524 Sci_Position lineCurrent
= styler
.GetLine(startPos
);
525 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
526 int levelCurrent
= levelPrev
;
527 int lineFoldStateCurrent
= lineCurrent
> 0 ? styler
.GetLineState(lineCurrent
- 1) & stateFoldMaskAll
: 0;
528 char chNext
= styler
[startPos
];
529 int styleNext
= styler
.StyleAt(startPos
);
530 int style
= initStyle
;
532 Sci_Position lastStart
= 0;
533 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_", 0x80, true);
535 for (Sci_PositionU i
= startPos
; i
< endPos
; i
++) {
537 chNext
= styler
.SafeGetCharAt(i
+ 1);
538 int stylePrev
= style
;
540 styleNext
= styler
.StyleAt(i
+ 1);
541 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
543 if (foldComment
&& IsStreamCommentStyle(style
)) {
544 if (!IsStreamCommentStyle(stylePrev
)) {
546 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
547 // Comments don't end at end of line and the next character may be unstyled.
551 if (foldComment
&& atEOL
&& IsCommentLine(lineCurrent
, styler
))
553 if (!IsCommentLine(lineCurrent
- 1, styler
)
554 && IsCommentLine(lineCurrent
+ 1, styler
))
556 else if (IsCommentLine(lineCurrent
- 1, styler
)
557 && !IsCommentLine(lineCurrent
+1, styler
))
560 if (foldPreprocessor
) {
561 if (style
== SCE_PAS_PREPROCESSOR
&& ch
== '{' && chNext
== '$') {
562 ClassifyPascalPreprocessorFoldPoint(levelCurrent
, lineFoldStateCurrent
, i
+ 2, styler
);
563 } else if (style
== SCE_PAS_PREPROCESSOR2
&& ch
== '(' && chNext
== '*'
564 && styler
.SafeGetCharAt(i
+ 2) == '$') {
565 ClassifyPascalPreprocessorFoldPoint(levelCurrent
, lineFoldStateCurrent
, i
+ 3, styler
);
569 if (stylePrev
!= SCE_PAS_WORD
&& style
== SCE_PAS_WORD
)
571 // Store last word start point.
574 if (stylePrev
== SCE_PAS_WORD
&& !(lineFoldStateCurrent
& stateFoldInPreprocessor
)) {
575 if(setWord
.Contains(ch
) && !setWord
.Contains(chNext
)) {
576 ClassifyPascalWordFoldPoint(levelCurrent
, lineFoldStateCurrent
, startPos
, endPos
, lastStart
, i
, styler
);
585 if (visibleChars
== 0 && foldCompact
)
586 lev
|= SC_FOLDLEVELWHITEFLAG
;
587 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
588 lev
|= SC_FOLDLEVELHEADERFLAG
;
589 if (lev
!= styler
.LevelAt(lineCurrent
)) {
590 styler
.SetLevel(lineCurrent
, lev
);
592 int newLineState
= (styler
.GetLineState(lineCurrent
) & ~stateFoldMaskAll
) | lineFoldStateCurrent
;
593 styler
.SetLineState(lineCurrent
, newLineState
);
595 levelPrev
= levelCurrent
;
600 // If we didn't reach the EOL in previous loop, store line level and whitespace information.
601 // The rest will be filled in later...
603 if (visibleChars
== 0 && foldCompact
)
604 lev
|= SC_FOLDLEVELWHITEFLAG
;
605 styler
.SetLevel(lineCurrent
, lev
);
608 static const char * const pascalWordListDesc
[] = {
613 LexerModule
lmPascal(SCLEX_PASCAL
, ColourisePascalDoc
, "pascal", FoldPascalDoc
, pascalWordListDesc
);