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

« back to all changes in this revision

Viewing changes to scintilla/lexers/LexD.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
/** @file LexD.cxx
 
2
 ** Lexer for D.
 
3
 **
 
4
 ** Copyright (c) 2006 by Waldemar Augustyn <waldemar@wdmsys.com>
 
5
 ** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net>
 
6
 **/
 
7
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
 
8
// The License.txt file describes the conditions under which this software may be distributed.
 
9
 
 
10
#include <stdlib.h>
 
11
#include <string.h>
 
12
#include <stdio.h>
 
13
#include <stdarg.h>
 
14
#include <assert.h>
 
15
#include <ctype.h>
 
16
 
 
17
#ifdef _MSC_VER
 
18
#pragma warning(disable: 4786)
 
19
#endif
 
20
 
 
21
#include <string>
 
22
#include <map>
 
23
 
 
24
#include "ILexer.h"
 
25
#include "Scintilla.h"
 
26
#include "SciLexer.h"
 
27
 
 
28
#include "WordList.h"
 
29
#include "LexAccessor.h"
 
30
#include "StyleContext.h"
 
31
#include "CharacterSet.h"
 
32
#include "LexerModule.h"
 
33
#include "OptionSet.h"
 
34
 
 
35
#ifdef SCI_NAMESPACE
 
36
using namespace Scintilla;
 
37
#endif
 
38
 
 
39
/* Nested comments require keeping the value of the nesting level for every
 
40
   position in the document.  But since scintilla always styles line by line,
 
41
   we only need to store one value per line. The non-negative number indicates
 
42
   nesting level at the end of the line.
 
43
*/
 
44
 
 
45
// Underscore, letter, digit and universal alphas from C99 Appendix D.
 
46
 
 
47
static bool IsWordStart(int ch) {
 
48
        return (isascii(ch) && (isalpha(ch) || ch == '_')) || !isascii(ch);
 
49
}
 
50
 
 
51
static bool IsWord(int ch) {
 
52
        return (isascii(ch) && (isalnum(ch) || ch == '_')) || !isascii(ch);
 
53
}
 
54
 
 
55
static bool IsDoxygen(int ch) {
 
56
        if (isascii(ch) && islower(ch))
 
57
                return true;
 
58
        if (ch == '$' || ch == '@' || ch == '\\' ||
 
59
                ch == '&' || ch == '#' || ch == '<' || ch == '>' ||
 
60
                ch == '{' || ch == '}' || ch == '[' || ch == ']')
 
61
                return true;
 
62
        return false;
 
63
}
 
64
 
 
65
static bool IsStringSuffix(int ch) {
 
66
        return ch == 'c' || ch == 'w' || ch == 'd';
 
67
}
 
68
 
 
69
static bool IsStreamCommentStyle(int style) {
 
70
        return style == SCE_D_COMMENT ||
 
71
                style == SCE_D_COMMENTDOC ||
 
72
                style == SCE_D_COMMENTDOCKEYWORD ||
 
73
                style == SCE_D_COMMENTDOCKEYWORDERROR;
 
74
}
 
75
 
 
76
// An individual named option for use in an OptionSet
 
77
 
 
78
// Options used for LexerD
 
79
struct OptionsD {
 
80
        bool fold;
 
81
        bool foldSyntaxBased;
 
82
        bool foldComment;
 
83
        bool foldCommentMultiline;
 
84
        bool foldCommentExplicit;
 
85
        std::string foldExplicitStart;
 
86
        std::string foldExplicitEnd;
 
87
        bool foldExplicitAnywhere;
 
88
        bool foldCompact;
 
89
        int  foldAtElseInt;
 
90
        bool foldAtElse;
 
91
        OptionsD() {
 
92
                fold = false;
 
93
                foldSyntaxBased = true;
 
94
                foldComment = false;
 
95
                foldCommentMultiline = true;
 
96
                foldCommentExplicit = true;
 
97
                foldExplicitStart = "";
 
98
                foldExplicitEnd   = "";
 
99
                foldExplicitAnywhere = false;
 
100
                foldCompact = true;
 
101
                foldAtElseInt = -1;
 
102
                foldAtElse = false;
 
103
        }
 
104
};
 
105
 
 
106
static const char * const dWordLists[] = {
 
107
                        "Primary keywords and identifiers",
 
108
                        "Secondary keywords and identifiers",
 
109
                        "Documentation comment keywords",
 
110
                        "Type definitions and aliases",
 
111
                        "Keywords 5",
 
112
                        "Keywords 6",
 
113
                        "Keywords 7",
 
114
                        0,
 
115
                };
 
116
 
 
117
struct OptionSetD : public OptionSet<OptionsD> {
 
118
        OptionSetD() {
 
119
                DefineProperty("fold", &OptionsD::fold);
 
120
 
 
121
                DefineProperty("fold.d.syntax.based", &OptionsD::foldSyntaxBased,
 
122
                        "Set this property to 0 to disable syntax based folding.");
 
123
 
 
124
                DefineProperty("fold.comment", &OptionsD::foldComment);
 
125
 
 
126
                DefineProperty("fold.d.comment.multiline", &OptionsD::foldCommentMultiline,
 
127
                        "Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
 
128
 
 
129
                DefineProperty("fold.d.comment.explicit", &OptionsD::foldCommentExplicit,
 
130
                        "Set this property to 0 to disable folding explicit fold points when fold.comment=1.");
 
131
 
 
132
                DefineProperty("fold.d.explicit.start", &OptionsD::foldExplicitStart,
 
133
                        "The string to use for explicit fold start points, replacing the standard //{.");
 
134
 
 
135
                DefineProperty("fold.d.explicit.end", &OptionsD::foldExplicitEnd,
 
136
                        "The string to use for explicit fold end points, replacing the standard //}.");
 
137
 
 
138
                DefineProperty("fold.d.explicit.anywhere", &OptionsD::foldExplicitAnywhere,
 
139
                        "Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
 
140
 
 
141
                DefineProperty("fold.compact", &OptionsD::foldCompact);
 
142
 
 
143
                DefineProperty("lexer.d.fold.at.else", &OptionsD::foldAtElseInt,
 
144
                        "This option enables D folding on a \"} else {\" line of an if statement.");
 
145
 
 
146
                DefineProperty("fold.at.else", &OptionsD::foldAtElse);
 
147
 
 
148
                DefineWordListSets(dWordLists);
 
149
        }
 
150
};
 
151
 
 
152
class LexerD : public ILexer {
 
153
        bool caseSensitive;
 
154
        WordList keywords;
 
155
        WordList keywords2;
 
156
        WordList keywords3;
 
157
        WordList keywords4;
 
158
        WordList keywords5;
 
159
        WordList keywords6;
 
160
        WordList keywords7;
 
161
        OptionsD options;
 
162
        OptionSetD osD;
 
163
public:
 
164
        LexerD(bool caseSensitive_) :
 
165
                caseSensitive(caseSensitive_) {
 
166
        }
 
167
        ~LexerD() {
 
168
        }
 
169
        void SCI_METHOD Release() {
 
170
                delete this;
 
171
        }
 
172
        int SCI_METHOD Version() const {
 
173
                return lvOriginal;
 
174
        }
 
175
        const char * SCI_METHOD PropertyNames() {
 
176
                return osD.PropertyNames();
 
177
        }
 
178
        int SCI_METHOD PropertyType(const char *name) {
 
179
                return osD.PropertyType(name);
 
180
        }
 
181
        const char * SCI_METHOD DescribeProperty(const char *name) {
 
182
                return osD.DescribeProperty(name);
 
183
        }
 
184
        int SCI_METHOD PropertySet(const char *key, const char *val);
 
185
        const char * SCI_METHOD DescribeWordListSets() {
 
186
                return osD.DescribeWordListSets();
 
187
        }
 
188
        int SCI_METHOD WordListSet(int n, const char *wl);
 
189
        void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
 
190
        void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
 
191
 
 
192
        void * SCI_METHOD PrivateCall(int, void *) {
 
193
                return 0;
 
194
        }
 
195
 
 
196
        static ILexer *LexerFactoryD() {
 
197
                return new LexerD(true);
 
198
        }
 
199
        static ILexer *LexerFactoryDInsensitive() {
 
200
                return new LexerD(false);
 
201
        }
 
202
};
 
203
 
 
204
int SCI_METHOD LexerD::PropertySet(const char *key, const char *val) {
 
205
        if (osD.PropertySet(&options, key, val)) {
 
206
                return 0;
 
207
        }
 
208
        return -1;
 
209
}
 
210
 
 
211
int SCI_METHOD LexerD::WordListSet(int n, const char *wl) {
 
212
        WordList *wordListN = 0;
 
213
        switch (n) {
 
214
        case 0:
 
215
                wordListN = &keywords;
 
216
                break;
 
217
        case 1:
 
218
                wordListN = &keywords2;
 
219
                break;
 
220
        case 2:
 
221
                wordListN = &keywords3;
 
222
                break;
 
223
        case 3:
 
224
                wordListN = &keywords4;
 
225
                break;
 
226
        case 4:
 
227
                wordListN = &keywords5;
 
228
                break;
 
229
        case 5:
 
230
                wordListN = &keywords6;
 
231
                break;
 
232
        case 6:
 
233
                wordListN = &keywords7;
 
234
                break;
 
235
        }
 
236
        int firstModification = -1;
 
237
        if (wordListN) {
 
238
                WordList wlNew;
 
239
                wlNew.Set(wl);
 
240
                if (*wordListN != wlNew) {
 
241
                        wordListN->Set(wl);
 
242
                        firstModification = 0;
 
243
                }
 
244
        }
 
245
        return firstModification;
 
246
}
 
247
 
 
248
void SCI_METHOD LexerD::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
 
249
        LexAccessor styler(pAccess);
 
250
 
 
251
        int styleBeforeDCKeyword = SCE_D_DEFAULT;
 
252
 
 
253
        StyleContext sc(startPos, length, initStyle, styler);
 
254
 
 
255
        int curLine = styler.GetLine(startPos);
 
256
        int curNcLevel = curLine > 0? styler.GetLineState(curLine-1): 0;
 
257
        bool numFloat = false; // Float literals have '+' and '-' signs
 
258
        bool numHex = false;
 
259
 
 
260
        for (; sc.More(); sc.Forward()) {
 
261
 
 
262
                if (sc.atLineStart) {
 
263
                        curLine = styler.GetLine(sc.currentPos);
 
264
                        styler.SetLineState(curLine, curNcLevel);
 
265
                }
 
266
 
 
267
                // Determine if the current state should terminate.
 
268
                switch (sc.state) {
 
269
                        case SCE_D_OPERATOR:
 
270
                                sc.SetState(SCE_D_DEFAULT);
 
271
                                break;
 
272
                        case SCE_D_NUMBER:
 
273
                                // We accept almost anything because of hex. and number suffixes
 
274
                                if (isascii(sc.ch) && (isalnum(sc.ch) || sc.ch == '_')) {
 
275
                                        continue;
 
276
                                } else if (sc.ch == '.' && sc.chNext != '.' && !numFloat) {
 
277
                                        // Don't parse 0..2 as number.
 
278
                                        numFloat=true;
 
279
                                        continue;
 
280
                                } else if ( ( sc.ch == '-' || sc.ch == '+' ) && (               /*sign and*/
 
281
                                        ( !numHex && ( sc.chPrev == 'e' || sc.chPrev == 'E' ) ) || /*decimal or*/
 
282
                                        ( sc.chPrev == 'p' || sc.chPrev == 'P' ) ) ) {          /*hex*/
 
283
                                        // Parse exponent sign in float literals: 2e+10 0x2e+10
 
284
                                        continue;
 
285
                                } else {
 
286
                                        sc.SetState(SCE_D_DEFAULT);
 
287
                                }
 
288
                                break;
 
289
                        case SCE_D_IDENTIFIER:
 
290
                                if (!IsWord(sc.ch)) {
 
291
                                        char s[1000];
 
292
                                        if (caseSensitive) {
 
293
                                                sc.GetCurrent(s, sizeof(s));
 
294
                                        } else {
 
295
                                                sc.GetCurrentLowered(s, sizeof(s));
 
296
                                        }
 
297
                                        if (keywords.InList(s)) {
 
298
                                                sc.ChangeState(SCE_D_WORD);
 
299
                                        } else if (keywords2.InList(s)) {
 
300
                                                sc.ChangeState(SCE_D_WORD2);
 
301
                                        } else if (keywords4.InList(s)) {
 
302
                                                sc.ChangeState(SCE_D_TYPEDEF);
 
303
                                        } else if (keywords5.InList(s)) {
 
304
                                                sc.ChangeState(SCE_D_WORD5);
 
305
                                        } else if (keywords6.InList(s)) {
 
306
                                                sc.ChangeState(SCE_D_WORD6);
 
307
                                        } else if (keywords7.InList(s)) {
 
308
                                                sc.ChangeState(SCE_D_WORD7);
 
309
                                        }
 
310
                                        sc.SetState(SCE_D_DEFAULT);
 
311
                                }
 
312
                                break;
 
313
                        case SCE_D_COMMENT:
 
314
                                if (sc.Match('*', '/')) {
 
315
                                        sc.Forward();
 
316
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
317
                                }
 
318
                                break;
 
319
                        case SCE_D_COMMENTDOC:
 
320
                                if (sc.Match('*', '/')) {
 
321
                                        sc.Forward();
 
322
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
323
                                } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
 
324
                                        // Verify that we have the conditions to mark a comment-doc-keyword
 
325
                                        if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
 
326
                                                styleBeforeDCKeyword = SCE_D_COMMENTDOC;
 
327
                                                sc.SetState(SCE_D_COMMENTDOCKEYWORD);
 
328
                                        }
 
329
                                }
 
330
                                break;
 
331
                        case SCE_D_COMMENTLINE:
 
332
                                if (sc.atLineStart) {
 
333
                                        sc.SetState(SCE_D_DEFAULT);
 
334
                                }
 
335
                                break;
 
336
                        case SCE_D_COMMENTLINEDOC:
 
337
                                if (sc.atLineStart) {
 
338
                                        sc.SetState(SCE_D_DEFAULT);
 
339
                                } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
 
340
                                        // Verify that we have the conditions to mark a comment-doc-keyword
 
341
                                        if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
 
342
                                                styleBeforeDCKeyword = SCE_D_COMMENTLINEDOC;
 
343
                                                sc.SetState(SCE_D_COMMENTDOCKEYWORD);
 
344
                                        }
 
345
                                }
 
346
                                break;
 
347
                        case SCE_D_COMMENTDOCKEYWORD:
 
348
                                if ((styleBeforeDCKeyword == SCE_D_COMMENTDOC) && sc.Match('*', '/')) {
 
349
                                        sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
 
350
                                        sc.Forward();
 
351
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
352
                                } else if (!IsDoxygen(sc.ch)) {
 
353
                                        char s[100];
 
354
                                        if (caseSensitive) {
 
355
                                                sc.GetCurrent(s, sizeof(s));
 
356
                                        } else {
 
357
                                                sc.GetCurrentLowered(s, sizeof(s));
 
358
                                        }
 
359
                                        if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
 
360
                                                sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
 
361
                                        }
 
362
                                        sc.SetState(styleBeforeDCKeyword);
 
363
                                }
 
364
                                break;
 
365
                        case SCE_D_COMMENTNESTED:
 
366
                                if (sc.Match('+', '/')) {
 
367
                                        if (curNcLevel > 0)
 
368
                                                curNcLevel -= 1;
 
369
                                        curLine = styler.GetLine(sc.currentPos);
 
370
                                        styler.SetLineState(curLine, curNcLevel);
 
371
                                        sc.Forward();
 
372
                                        if (curNcLevel == 0) {
 
373
                                                sc.ForwardSetState(SCE_D_DEFAULT);
 
374
                                        }
 
375
                                } else if (sc.Match('/','+')) {
 
376
                                        curNcLevel += 1;
 
377
                                        curLine = styler.GetLine(sc.currentPos);
 
378
                                        styler.SetLineState(curLine, curNcLevel);
 
379
                                        sc.Forward();
 
380
                                }
 
381
                                break;
 
382
                        case SCE_D_STRING:
 
383
                                if (sc.ch == '\\') {
 
384
                                        if (sc.chNext == '"' || sc.chNext == '\\') {
 
385
                                                sc.Forward();
 
386
                                        }
 
387
                                } else if (sc.ch == '"') {
 
388
                                        if(IsStringSuffix(sc.chNext))
 
389
                                                sc.Forward();
 
390
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
391
                                }
 
392
                                break;
 
393
                        case SCE_D_CHARACTER:
 
394
                                if (sc.atLineEnd) {
 
395
                                        sc.ChangeState(SCE_D_STRINGEOL);
 
396
                                } else if (sc.ch == '\\') {
 
397
                                        if (sc.chNext == '\'' || sc.chNext == '\\') {
 
398
                                                sc.Forward();
 
399
                                        }
 
400
                                } else if (sc.ch == '\'') {
 
401
                                        // Char has no suffixes
 
402
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
403
                                }
 
404
                                break;
 
405
                        case SCE_D_STRINGEOL:
 
406
                                if (sc.atLineStart) {
 
407
                                        sc.SetState(SCE_D_DEFAULT);
 
408
                                }
 
409
                                break;
 
410
                        case SCE_D_STRINGB:
 
411
                                if (sc.ch == '`') {
 
412
                                        if(IsStringSuffix(sc.chNext))
 
413
                                                sc.Forward();
 
414
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
415
                                }
 
416
                                break;
 
417
                        case SCE_D_STRINGR:
 
418
                                if (sc.ch == '"') {
 
419
                                        if(IsStringSuffix(sc.chNext))
 
420
                                                sc.Forward();
 
421
                                        sc.ForwardSetState(SCE_D_DEFAULT);
 
422
                                }
 
423
                                break;
 
424
                }
 
425
 
 
426
                // Determine if a new state should be entered.
 
427
                if (sc.state == SCE_D_DEFAULT) {
 
428
                        if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
 
429
                                sc.SetState(SCE_D_NUMBER);
 
430
                                numFloat = sc.ch == '.';
 
431
                                // Remember hex literal
 
432
                                numHex = sc.ch == '0' && ( sc.chNext == 'x' || sc.chNext == 'X' );
 
433
                        } else if ( (sc.ch == 'r' || sc.ch == 'x' || sc.ch == 'q')
 
434
                                && sc.chNext == '"' ) {
 
435
                                // Limited support for hex and delimited strings: parse as r""
 
436
                                sc.SetState(SCE_D_STRINGR);
 
437
                                sc.Forward();
 
438
                        } else if (IsWordStart(sc.ch) || sc.ch == '$') {
 
439
                                sc.SetState(SCE_D_IDENTIFIER);
 
440
                        } else if (sc.Match('/','+')) {
 
441
                                curNcLevel += 1;
 
442
                                curLine = styler.GetLine(sc.currentPos);
 
443
                                styler.SetLineState(curLine, curNcLevel);
 
444
                                sc.SetState(SCE_D_COMMENTNESTED);
 
445
                                sc.Forward();
 
446
                        } else if (sc.Match('/', '*')) {
 
447
                                if (sc.Match("/**") || sc.Match("/*!")) {   // Support of Qt/Doxygen doc. style
 
448
                                        sc.SetState(SCE_D_COMMENTDOC);
 
449
                                } else {
 
450
                                        sc.SetState(SCE_D_COMMENT);
 
451
                                }
 
452
                                sc.Forward();   // Eat the * so it isn't used for the end of the comment
 
453
                        } else if (sc.Match('/', '/')) {
 
454
                                if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
 
455
                                        // Support of Qt/Doxygen doc. style
 
456
                                        sc.SetState(SCE_D_COMMENTLINEDOC);
 
457
                                else
 
458
                                        sc.SetState(SCE_D_COMMENTLINE);
 
459
                        } else if (sc.ch == '"') {
 
460
                                sc.SetState(SCE_D_STRING);
 
461
                        } else if (sc.ch == '\'') {
 
462
                                sc.SetState(SCE_D_CHARACTER);
 
463
                        } else if (sc.ch == '`') {
 
464
                                sc.SetState(SCE_D_STRINGB);
 
465
                        } else if (isoperator(static_cast<char>(sc.ch))) {
 
466
                                sc.SetState(SCE_D_OPERATOR);
 
467
                                if (sc.ch == '.' && sc.chNext == '.') sc.Forward(); // Range operator
 
468
                        }
 
469
                }
 
470
        }
 
471
        sc.Complete();
 
472
}
 
473
 
 
474
// Store both the current line's fold level and the next lines in the
 
475
// level store to make it easy to pick up with each increment
 
476
// and to make it possible to fiddle the current level for "} else {".
 
477
 
 
478
void SCI_METHOD LexerD::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
 
479
 
 
480
        if (!options.fold)
 
481
                return;
 
482
 
 
483
        LexAccessor styler(pAccess);
 
484
 
 
485
        unsigned int endPos = startPos + length;
 
486
        int visibleChars = 0;
 
487
        int lineCurrent = styler.GetLine(startPos);
 
488
        int levelCurrent = SC_FOLDLEVELBASE;
 
489
        if (lineCurrent > 0)
 
490
                levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
 
491
        int levelMinCurrent = levelCurrent;
 
492
        int levelNext = levelCurrent;
 
493
        char chNext = styler[startPos];
 
494
        int styleNext = styler.StyleAt(startPos);
 
495
        int style = initStyle;
 
496
        bool foldAtElse = options.foldAtElseInt >= 0 ? options.foldAtElseInt != 0 : options.foldAtElse;
 
497
        const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
 
498
        for (unsigned int i = startPos; i < endPos; i++) {
 
499
                char ch = chNext;
 
500
                chNext = styler.SafeGetCharAt(i + 1);
 
501
                int stylePrev = style;
 
502
                style = styleNext;
 
503
                styleNext = styler.StyleAt(i + 1);
 
504
                bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
 
505
                if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) {
 
506
                        if (!IsStreamCommentStyle(stylePrev)) {
 
507
                                levelNext++;
 
508
                        } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
 
509
                                // Comments don't end at end of line and the next character may be unstyled.
 
510
                                levelNext--;
 
511
                        }
 
512
                }
 
513
                if (options.foldComment && options.foldCommentExplicit && ((style == SCE_D_COMMENTLINE) || options.foldExplicitAnywhere)) {
 
514
                        if (userDefinedFoldMarkers) {
 
515
                                if (styler.Match(i, options.foldExplicitStart.c_str())) {
 
516
                                        levelNext++;
 
517
                                } else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
 
518
                                        levelNext--;
 
519
                                }
 
520
                        } else {
 
521
                                if ((ch == '/') && (chNext == '/')) {
 
522
                                        char chNext2 = styler.SafeGetCharAt(i + 2);
 
523
                                        if (chNext2 == '{') {
 
524
                                                levelNext++;
 
525
                                        } else if (chNext2 == '}') {
 
526
                                                levelNext--;
 
527
                                        }
 
528
                                }
 
529
                        }
 
530
                }
 
531
                if (options.foldSyntaxBased && (style == SCE_D_OPERATOR)) {
 
532
                        if (ch == '{') {
 
533
                                // Measure the minimum before a '{' to allow
 
534
                                // folding on "} else {"
 
535
                                if (levelMinCurrent > levelNext) {
 
536
                                        levelMinCurrent = levelNext;
 
537
                                }
 
538
                                levelNext++;
 
539
                        } else if (ch == '}') {
 
540
                                levelNext--;
 
541
                        }
 
542
                }
 
543
                if (atEOL || (i == endPos-1)) {
 
544
                        if (options.foldComment && options.foldCommentMultiline) {  // Handle nested comments
 
545
                                int nc;
 
546
                                nc =  styler.GetLineState(lineCurrent);
 
547
                                nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0;
 
548
                                levelNext += nc;
 
549
                        }
 
550
                        int levelUse = levelCurrent;
 
551
                        if (options.foldSyntaxBased && foldAtElse) {
 
552
                                levelUse = levelMinCurrent;
 
553
                        }
 
554
                        int lev = levelUse | levelNext << 16;
 
555
                        if (visibleChars == 0 && options.foldCompact)
 
556
                                lev |= SC_FOLDLEVELWHITEFLAG;
 
557
                        if (levelUse < levelNext)
 
558
                                lev |= SC_FOLDLEVELHEADERFLAG;
 
559
                        if (lev != styler.LevelAt(lineCurrent)) {
 
560
                                styler.SetLevel(lineCurrent, lev);
 
561
                        }
 
562
                        lineCurrent++;
 
563
                        levelCurrent = levelNext;
 
564
                        levelMinCurrent = levelCurrent;
 
565
                        visibleChars = 0;
 
566
                }
 
567
                if (!IsASpace(ch))
 
568
                        visibleChars++;
 
569
        }
 
570
}
 
571
 
 
572
LexerModule lmD(SCLEX_D, LexerD::LexerFactoryD, "d", dWordLists);