4
** Copyright (c) 2006 by Waldemar Augustyn <waldemar@wdmsys.com>
6
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
7
// The License.txt file describes the conditions under which this software may be distributed.
19
#include "StyleContext.h"
21
#include "Scintilla.h"
25
using namespace Scintilla;
28
/* Nested comments require keeping the value of the nesting level for every
29
position in the document. But since scintilla always styles line by line,
30
we only need to store one value per line. The non-negative number indicates
31
nesting level at the end of the line.
34
// Underscore, letter, digit and universal alphas from C99 Appendix D.
36
static bool IsWordStart(int ch) {
37
return (isascii(ch) && (isalpha(ch) || ch == '_')) || !isascii(ch);
40
static bool IsWord(int ch) {
41
return (isascii(ch) && (isalnum(ch) || ch == '_')) || !isascii(ch);
44
static bool IsDoxygen(int ch) {
45
if (isascii(ch) && islower(ch))
47
if (ch == '$' || ch == '@' || ch == '\\' ||
48
ch == '&' || ch == '#' || ch == '<' || ch == '>' ||
49
ch == '{' || ch == '}' || ch == '[' || ch == ']')
54
static bool IsStringSuffix(int ch) {
55
return ch == 'c' || ch == 'w' || ch == 'd';
59
static void ColouriseDoc(unsigned int startPos, int length, int initStyle,
60
WordList *keywordlists[], Accessor &styler, bool caseSensitive) {
62
WordList &keywords = *keywordlists[0];
63
WordList &keywords2 = *keywordlists[1];
64
WordList &keywords3 = *keywordlists[2]; //doxygen
65
WordList &keywords4 = *keywordlists[3];
66
WordList &keywords5 = *keywordlists[4];
67
WordList &keywords6 = *keywordlists[5];
68
WordList &keywords7 = *keywordlists[6];
70
int styleBeforeDCKeyword = SCE_D_DEFAULT;
72
StyleContext sc(startPos, length, initStyle, styler);
74
int curLine = styler.GetLine(startPos);
75
int curNcLevel = curLine > 0? styler.GetLineState(curLine-1): 0;
76
bool numFloat = false; // Float literals have '+' and '-' signs
79
for (; sc.More(); sc.Forward()) {
82
curLine = styler.GetLine(sc.currentPos);
83
styler.SetLineState(curLine, curNcLevel);
86
// Determine if the current state should terminate.
89
sc.SetState(SCE_D_DEFAULT);
92
// We accept almost anything because of hex. and number suffixes
93
if (isascii(sc.ch) && (isalnum(sc.ch) || sc.ch == '_')) {
95
} else if (sc.ch == '.' && sc.chNext != '.' && !numFloat) {
96
// Don't parse 0..2 as number.
99
} else if ( ( sc.ch == '-' || sc.ch == '+' ) && ( /*sign and*/
100
( !numHex && ( sc.chPrev == 'e' || sc.chPrev == 'E' ) ) || /*decimal or*/
101
( sc.chPrev == 'p' || sc.chPrev == 'P' ) ) ) { /*hex*/
102
// Parse exponent sign in float literals: 2e+10 0x2e+10
105
sc.SetState(SCE_D_DEFAULT);
108
case SCE_D_IDENTIFIER:
109
if (!IsWord(sc.ch)) {
112
sc.GetCurrent(s, sizeof(s));
114
sc.GetCurrentLowered(s, sizeof(s));
116
if (keywords.InList(s)) {
117
sc.ChangeState(SCE_D_WORD);
118
} else if (keywords2.InList(s)) {
119
sc.ChangeState(SCE_D_WORD2);
120
} else if (keywords4.InList(s)) {
121
sc.ChangeState(SCE_D_TYPEDEF);
122
} else if (keywords5.InList(s)) {
123
sc.ChangeState(SCE_D_WORD5);
124
} else if (keywords6.InList(s)) {
125
sc.ChangeState(SCE_D_WORD6);
126
} else if (keywords7.InList(s)) {
127
sc.ChangeState(SCE_D_WORD7);
129
sc.SetState(SCE_D_DEFAULT);
133
if (sc.Match('*', '/')) {
135
sc.ForwardSetState(SCE_D_DEFAULT);
138
case SCE_D_COMMENTDOC:
139
if (sc.Match('*', '/')) {
141
sc.ForwardSetState(SCE_D_DEFAULT);
142
} else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
143
// Verify that we have the conditions to mark a comment-doc-keyword
144
if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
145
styleBeforeDCKeyword = SCE_D_COMMENTDOC;
146
sc.SetState(SCE_D_COMMENTDOCKEYWORD);
150
case SCE_D_COMMENTLINE:
151
if (sc.atLineStart) {
152
sc.SetState(SCE_D_DEFAULT);
155
case SCE_D_COMMENTLINEDOC:
156
if (sc.atLineStart) {
157
sc.SetState(SCE_D_DEFAULT);
158
} else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
159
// Verify that we have the conditions to mark a comment-doc-keyword
160
if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
161
styleBeforeDCKeyword = SCE_D_COMMENTLINEDOC;
162
sc.SetState(SCE_D_COMMENTDOCKEYWORD);
166
case SCE_D_COMMENTDOCKEYWORD:
167
if ((styleBeforeDCKeyword == SCE_D_COMMENTDOC) && sc.Match('*', '/')) {
168
sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
170
sc.ForwardSetState(SCE_D_DEFAULT);
171
} else if (!IsDoxygen(sc.ch)) {
174
sc.GetCurrent(s, sizeof(s));
176
sc.GetCurrentLowered(s, sizeof(s));
178
if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
179
sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
181
sc.SetState(styleBeforeDCKeyword);
184
case SCE_D_COMMENTNESTED:
185
if (sc.Match('+', '/')) {
188
curLine = styler.GetLine(sc.currentPos);
189
styler.SetLineState(curLine, curNcLevel);
191
if (curNcLevel == 0) {
192
sc.ForwardSetState(SCE_D_DEFAULT);
194
} else if (sc.Match('/','+')) {
196
curLine = styler.GetLine(sc.currentPos);
197
styler.SetLineState(curLine, curNcLevel);
203
if (sc.chNext == '"' || sc.chNext == '\\') {
206
} else if (sc.ch == '"') {
207
if(IsStringSuffix(sc.chNext))
209
sc.ForwardSetState(SCE_D_DEFAULT);
212
case SCE_D_CHARACTER:
214
sc.ChangeState(SCE_D_STRINGEOL);
215
} else if (sc.ch == '\\') {
216
if (sc.chNext == '\'' || sc.chNext == '\\') {
219
} else if (sc.ch == '\'') {
220
// Char has no suffixes
221
sc.ForwardSetState(SCE_D_DEFAULT);
224
case SCE_D_STRINGEOL:
225
if (sc.atLineStart) {
226
sc.SetState(SCE_D_DEFAULT);
231
if(IsStringSuffix(sc.chNext))
233
sc.ForwardSetState(SCE_D_DEFAULT);
238
if(IsStringSuffix(sc.chNext))
240
sc.ForwardSetState(SCE_D_DEFAULT);
245
// Determine if a new state should be entered.
246
if (sc.state == SCE_D_DEFAULT) {
247
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
248
sc.SetState(SCE_D_NUMBER);
249
numFloat = sc.ch == '.';
250
// Remember hex literal
251
numHex = sc.ch == '0' && ( sc.chNext == 'x' || sc.chNext == 'X' );
252
} else if ( (sc.ch == 'r' || sc.ch == 'x' || sc.ch == 'q')
253
&& sc.chNext == '"' ) {
254
// Limited support for hex and delimited strings: parse as r""
255
sc.SetState(SCE_D_STRINGR);
257
} else if (IsWordStart(sc.ch) || sc.ch == '$') {
258
sc.SetState(SCE_D_IDENTIFIER);
259
} else if (sc.Match('/','+')) {
261
curLine = styler.GetLine(sc.currentPos);
262
styler.SetLineState(curLine, curNcLevel);
263
sc.SetState(SCE_D_COMMENTNESTED);
265
} else if (sc.Match('/', '*')) {
266
if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
267
sc.SetState(SCE_D_COMMENTDOC);
269
sc.SetState(SCE_D_COMMENT);
271
sc.Forward(); // Eat the * so it isn't used for the end of the comment
272
} else if (sc.Match('/', '/')) {
273
if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
274
// Support of Qt/Doxygen doc. style
275
sc.SetState(SCE_D_COMMENTLINEDOC);
277
sc.SetState(SCE_D_COMMENTLINE);
278
} else if (sc.ch == '"') {
279
sc.SetState(SCE_D_STRING);
280
} else if (sc.ch == '\'') {
281
sc.SetState(SCE_D_CHARACTER);
282
} else if (sc.ch == '`') {
283
sc.SetState(SCE_D_STRINGB);
284
} else if (isoperator(static_cast<char>(sc.ch))) {
285
sc.SetState(SCE_D_OPERATOR);
286
if (sc.ch == '.' && sc.chNext == '.') sc.Forward(); // Range operator
293
static bool IsStreamCommentStyle(int style) {
294
return style == SCE_D_COMMENT ||
295
style == SCE_D_COMMENTDOC ||
296
style == SCE_D_COMMENTDOCKEYWORD ||
297
style == SCE_D_COMMENTDOCKEYWORDERROR;
300
// Store both the current line's fold level and the next lines in the
301
// level store to make it easy to pick up with each increment
302
// and to make it possible to fiddle the current level for "} else {".
303
static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) {
304
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
305
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
307
// property lexer.d.fold.at.else
308
// This option enables D folding on a "} else {" line of an if statement.
309
bool foldAtElse = styler.GetPropertyInt("lexer.d.fold.at.else",
310
styler.GetPropertyInt("fold.at.else", 0)) != 0;
311
unsigned int endPos = startPos + length;
312
int visibleChars = 0;
313
int lineCurrent = styler.GetLine(startPos);
314
int levelCurrent = SC_FOLDLEVELBASE;
316
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
317
int levelMinCurrent = levelCurrent;
318
int levelNext = levelCurrent;
319
char chNext = styler[startPos];
320
int styleNext = styler.StyleAt(startPos);
321
int style = initStyle;
322
for (unsigned int i = startPos; i < endPos; i++) {
324
chNext = styler.SafeGetCharAt(i + 1);
325
int stylePrev = style;
327
styleNext = styler.StyleAt(i + 1);
328
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
329
if (foldComment && IsStreamCommentStyle(style)) {
330
if (!IsStreamCommentStyle(stylePrev)) {
332
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
333
// Comments don't end at end of line and the next character may be unstyled.
337
if (style == SCE_D_OPERATOR) {
339
// Measure the minimum before a '{' to allow
340
// folding on "} else {"
341
if (levelMinCurrent > levelNext) {
342
levelMinCurrent = levelNext;
345
} else if (ch == '}') {
350
if (foldComment) { // Handle nested comments
352
nc = styler.GetLineState(lineCurrent);
353
nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0;
356
int levelUse = levelCurrent;
358
levelUse = levelMinCurrent;
360
int lev = levelUse | levelNext << 16;
361
if (visibleChars == 0 && foldCompact)
362
lev |= SC_FOLDLEVELWHITEFLAG;
363
if (levelUse < levelNext)
364
lev |= SC_FOLDLEVELHEADERFLAG;
365
if (lev != styler.LevelAt(lineCurrent)) {
366
styler.SetLevel(lineCurrent, lev);
369
levelCurrent = levelNext;
370
levelMinCurrent = levelCurrent;
378
static void FoldDDoc(unsigned int startPos, int length, int initStyle,
379
WordList *[], Accessor &styler) {
380
FoldDoc(startPos, length, initStyle, styler);
383
static const char * const dWordLists[] = {
384
"Primary keywords and identifiers",
385
"Secondary keywords and identifiers",
386
"Documentation comment keywords",
387
"Type definitions and aliases",
394
static void ColouriseDDoc(unsigned int startPos, int length,
395
int initStyle, WordList *keywordlists[], Accessor &styler) {
396
ColouriseDoc(startPos, length, initStyle, keywordlists, styler, true);
399
LexerModule lmD(SCLEX_D, ColouriseDDoc, "d", FoldDDoc, dWordLists);