~ubuntu-branches/ubuntu/utopic/geany/utopic

« back to all changes in this revision

Viewing changes to scintilla/LexPascal.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 **/
9
 
 
10
 
/*
11
 
 
12
 
A few words about features of the new completely rewritten LexPascal...
13
 
 
14
 
Generally speaking LexPascal tries to support all available Delphi features (up 
15
 
to Delphi 2009 at this time), including .NET specific features.
16
 
 
17
 
~ HIGHLIGHTING:
18
 
 
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). 
23
 
 
24
 
For example, keywords "read" and "write" will only be highlighted if they are in 
25
 
property declaration:
26
 
 
27
 
property MyProperty: boolean read FMyProperty write FMyProperty; 
28
 
 
29
 
~ FOLDING:
30
 
 
31
 
Folding 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 
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)
41
 
 
42
 
Remarks:
43
 
 
44
 
- Folding of code blocks tries to handle all special cases in which folding 
45
 
should not occur. As implemented those are:
46
 
 
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
 
 
58
 
- Folding of code blocks inside preprocessor blocks is disabled (any comments 
59
 
inside them will be folded fine) because there is no guarantee that complete 
60
 
code block will be contained inside folded preprocessor block in which case 
61
 
folded code block could end prematurely at the end of preprocessor block if 
62
 
there is no closing statement inside. This was done in order to properly process 
63
 
document that may contain something like this:
64
 
 
65
 
type
66
 
{$IFDEF UNICODE}
67
 
  TMyClass = class(UnicodeAncestor)
68
 
{$ELSE}
69
 
  TMyClass = class(AnsiAncestor)
70
 
{$ENDIF}
71
 
  private
72
 
  ...
73
 
  public
74
 
  ...
75
 
  published
76
 
  ...
77
 
end;
78
 
 
79
 
If class declarations were folded, then the second class declaration would end 
80
 
at "$ENDIF" statement, first class statement would end at "end;" statement and 
81
 
preprocessor "$IFDEF" block would go all the way to the end of document. 
82
 
However, having in mind all this, if you want to enable folding of code blocks 
83
 
inside preprocessor blocks, you can disable folding of preprocessor blocks by 
84
 
changing "fold.preprocessor" property, in which case everything inside them 
85
 
would be folded.
86
 
 
87
 
~ KEYWORDS:
88
 
 
89
 
The list of keywords that can be used in pascal.properties file (up to Delphi 
90
 
2009):
91
 
 
92
 
- Keywords: absolute abstract and array as asm assembler automated begin case 
93
 
cdecl class const constructor deprecated destructor dispid dispinterface div do 
94
 
downto dynamic else end except export exports external far file final 
95
 
finalization finally for forward function goto if implementation in inherited 
96
 
initialization inline interface is label library message mod near nil not object 
97
 
of on or out overload override packed pascal platform private procedure program 
98
 
property protected public published raise record register reintroduce repeat 
99
 
resourcestring safecall sealed set shl shr static stdcall strict string then 
100
 
threadvar 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 
103
 
index name nodefault read readonly remove stored write writeonly
104
 
 
105
 
- Keywords related to Delphi packages (in addition to all above): package 
106
 
contains requires
107
 
 
108
 
*/
109
 
 
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"
123
 
#include "StyleContext.h"
124
 
#include "CharacterSet.h"
125
 
 
126
 
#ifdef SCI_NAMESPACE
127
 
using namespace Scintilla;
128
 
#endif
129
 
 
130
 
static void GetRangeLowered(unsigned int start,
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)) {
137
 
                s[i] = static_cast<char>(tolower(styler[start + i]));
138
 
                i++;
139
 
        }
140
 
        s[i] = '\0';
141
 
}
142
 
 
143
 
static 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';
154
 
 
155
 
}
156
 
 
157
 
enum {
158
 
        stateInAsm = 0x1000, 
159
 
        stateInProperty = 0x2000, 
160
 
        stateInExport = 0x4000, 
161
 
        stateFoldInPreprocessor = 0x0100, 
162
 
        stateFoldInRecord = 0x0200, 
163
 
        stateFoldInPreprocessorLevelMask = 0x00FF, 
164
 
        stateFoldMaskAll = 0x0FFF
165
 
};
166
 
 
167
 
static void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLineState, bool bSmartHighlighting) {
168
 
        WordList& keywords = *keywordlists[0];
169
 
 
170
 
        char s[100];
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);
208
 
        }
209
 
        sc.SetState(SCE_PAS_DEFAULT);
210
 
}
211
 
 
212
 
static 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);
232
 
                }
233
 
 
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
 
                                        }
243
 
                                }
244
 
                                break;
245
 
                        case SCE_PAS_IDENTIFIER:
246
 
                                if (!setWord.Contains(sc.ch)) {
247
 
                                        ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
248
 
                                }
249
 
                                break;
250
 
                        case SCE_PAS_HEXNUMBER:
251
 
                                if (!setHexNumber.Contains(sc.ch)) {
252
 
                                        sc.SetState(SCE_PAS_DEFAULT);
253
 
                                }
254
 
                                break;
255
 
                        case SCE_PAS_COMMENT:
256
 
                        case SCE_PAS_PREPROCESSOR:
257
 
                                if (sc.ch == '}') {
258
 
                                        sc.ForwardSetState(SCE_PAS_DEFAULT);
259
 
                                }
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;
301
 
                }
302
 
 
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
 
                        }
331
 
                }
332
 
        }
333
 
 
334
 
        if (sc.state == SCE_PAS_IDENTIFIER && setWord.Contains(sc.chPrev)) {
335
 
                ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting);
336
 
        }
337
 
 
338
 
        sc.Complete();
339
 
}
340
 
 
341
 
static bool IsStreamCommentStyle(int style) {
342
 
        return style == SCE_PAS_COMMENT || style == SCE_PAS_COMMENT2;
343
 
}
344
 
 
345
 
static 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
 
                }
357
 
        }
358
 
        return false;
359
 
}
360
 
 
361
 
static unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) {
362
 
        return lineFoldStateCurrent & stateFoldInPreprocessorLevelMask;
363
 
}
364
 
 
365
 
static void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) {
366
 
        lineFoldStateCurrent &= ~stateFoldInPreprocessorLevelMask;
367
 
        lineFoldStateCurrent |= nestLevel & stateFoldInPreprocessorLevelMask;
368
 
}
369
 
 
370
 
static 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;
395
 
                }
396
 
                levelCurrent--;
397
 
                if (levelCurrent < SC_FOLDLEVELBASE) {
398
 
                        levelCurrent = SC_FOLDLEVELBASE;
399
 
                }
400
 
        }
401
 
}
402
 
 
403
 
static 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
 
}
415
 
 
416
 
static 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
 
                                                }
452
 
                                        }
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;
464
 
                                        }
465
 
                                }
466
 
                        }
467
 
                }
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
 
                }
493
 
        }
494
 
}
495
 
 
496
 
static void FoldPascalDoc(unsigned int startPos, int length, int initStyle, WordList *[],
497
 
                Accessor &styler) {
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;
506
 
        int lineFoldStateCurrent = lineCurrent > 0 ? styler.GetLineState(lineCurrent - 1) & stateFoldMaskAll : 0;
507
 
        char chNext = styler[startPos];
508
 
        int styleNext = styler.StyleAt(startPos);
509
 
        int style = initStyle;
510
 
 
511
 
        int lastStart = 0;
512
 
        CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
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
 
 
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))
531
 
                {
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--;
538
 
                }
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);
545
 
                        }
546
 
                }
547
 
 
548
 
                if (stylePrev != SCE_PAS_WORD && style == SCE_PAS_WORD)
549
 
                {
550
 
                        // Store last word start point.
551
 
                        lastStart = i;
552
 
                }
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);
556
 
                        }
557
 
                }
558
 
 
559
 
                if (!IsASpace(ch))
560
 
                        visibleChars++;
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
 
                        }
571
 
                        int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent;
572
 
                        styler.SetLineState(lineCurrent, newLineState);
573
 
                        lineCurrent++;
574
 
                        levelPrev = levelCurrent;
575
 
                        visibleChars = 0;
576
 
                }
577
 
        }
578
 
 
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);
585
 
}
586
 
 
587
 
static const char * const pascalWordListDesc[] = {
588
 
        "Keywords",
589
 
        0
590
 
};
591
 
 
592
 
LexerModule lmPascal(SCLEX_PASCAL, ColourisePascalDoc, "pascal", FoldPascalDoc, pascalWordListDesc);