19
19
#include "KeyWords.h"
20
20
#include "Scintilla.h"
21
21
#include "SciLexer.h"
23
#define KEYWORD_BOXHEADER 1
24
#define KEYWORD_FOLDCONTRACTED 2
26
static bool IsOKBeforeRE(int ch) {
27
return (ch == '(') || (ch == '=') || (ch == ',');
30
static inline bool IsAWordChar(int ch) {
31
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
34
static inline bool IsAWordStart(int ch) {
35
return (ch < 0x80) && (isalpha(ch) || ch == '_');
38
static inline bool IsADoxygenChar(int ch) {
39
return (ch < 0x80 && islower(ch)) || ch == '$' || ch == '@' ||
40
ch == '\\' || ch == '&' || ch == '<' ||
41
ch == '>' || ch == '#' || ch == '{' ||
42
ch == '}' || ch == '[' || ch == ']';
22
#include "CharacterSet.h"
25
using namespace Scintilla;
45
28
static bool IsSpaceEquiv(int state) {
46
29
return (state <= SCE_C_COMMENTDOC) ||
49
32
(state == SCE_C_COMMENTDOCKEYWORDERROR);
35
// Preconditions: sc.currentPos points to a character after '+' or '-'.
36
// The test for pos reaching 0 should be redundant,
37
// and is in only for safety measures.
38
// Limitation: this code will give the incorrect answer for code like
40
// Putting a space between the '++' post-inc operator and the '+' binary op
41
// fixes this, and is highly recommended for readability anyway.
42
static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) {
43
int pos = (int) sc.currentPos;
45
char ch = styler[pos];
46
if (ch == '+' || ch == '-') {
47
return styler[pos - 1] == ch;
52
53
static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
53
54
Accessor &styler, bool caseSensitive) {
57
58
WordList &keywords3 = *keywordlists[2];
58
59
WordList &keywords4 = *keywordlists[3];
61
// property styling.within.preprocessor
62
// For C++ code, determines whether all preprocessor code is styled in the preprocessor style (0, the default)
63
// or only from the initial # to the end of the command word(1).
60
64
bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;
66
CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-");
67
CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
69
CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
71
CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
72
CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
74
// property lexer.cpp.allow.dollars
75
// Set to 0 to disallow the '$' character in identifiers with the cpp lexer.
76
if (styler.GetPropertyInt("lexer.cpp.allow.dollars", 1) != 0) {
77
setWordStart.Add('$');
62
81
int chPrevNonWhite = ' ';
63
82
int visibleChars = 0;
64
83
bool lastWordWasUUID = false;
65
84
int styleBeforeDCKeyword = SCE_C_DEFAULT;
66
85
bool continuationLine = false;
86
bool isIncludePreprocessor = false;
68
88
if (initStyle == SCE_C_PREPROCESSOR) {
69
89
// Set continuationLine if last character of previous line is '\'
98
118
if (sc.atLineStart) {
99
119
if (sc.state == SCE_C_STRING) {
100
// Prevent SCE_C_STRINGEOL from leaking back to previous line which
120
// Prevent SCE_C_STRINGEOL from leaking back to previous line which
101
121
// ends with a line continuation by locking in the state upto this position.
102
122
sc.SetState(SCE_C_STRING);
127
148
case SCE_C_NUMBER:
128
149
// We accept almost anything because of hex. and number suffixes
129
if (!IsAWordChar(sc.ch)) {
150
if (!setWord.Contains(sc.ch)) {
130
151
sc.SetState(SCE_C_DEFAULT);
133
154
case SCE_C_IDENTIFIER:
134
if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
155
if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
136
157
if (caseSensitive) {
137
158
sc.GetCurrent(s, sizeof(s));
201
222
sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
203
224
sc.ForwardSetState(SCE_C_DEFAULT);
204
} else if (!IsADoxygenChar(sc.ch)) {
225
} else if (!setDoxygen.Contains(sc.ch)) {
206
227
if (caseSensitive) {
207
228
sc.GetCurrent(s, sizeof(s));
209
230
sc.GetCurrentLowered(s, sizeof(s));
211
if (!isspace(sc.ch) || !keywords3.InList(s + 1)) {
232
if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
212
233
sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
214
235
sc.SetState(styleBeforeDCKeyword);
217
238
case SCE_C_STRING:
218
239
if (sc.atLineEnd) {
219
240
sc.ChangeState(SCE_C_STRINGEOL);
241
} else if (isIncludePreprocessor) {
243
sc.ForwardSetState(SCE_C_DEFAULT);
244
isIncludePreprocessor = false;
220
246
} else if (sc.ch == '\\') {
221
247
if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
269
295
if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
270
296
sc.SetState(SCE_C_DEFAULT);
301
if (sc.Match("//*)")) {
302
sc.Forward(); sc.Forward(); sc.Forward();
303
sc.ForwardSetState(SCE_C_DEFAULT);
274
308
// Determine if a new state should be entered.
301
335
if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
302
336
// Support of Qt/Doxygen doc. style
303
337
sc.SetState(SCE_C_COMMENTLINEDOC);
339
else if (sc.Match("(*"))
340
// Support for wxSmith auto-generated code
341
sc.SetState(SCE_C_WXSMITH);
305
344
sc.SetState(SCE_C_COMMENTLINE);
306
} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
345
} else if (sc.ch == '/' && setOKBeforeRE.Contains(chPrevNonWhite) &&
346
(!setCouldBePostOp.Contains(chPrevNonWhite) || !FollowsPostfixOperator(sc, styler))) {
307
347
sc.SetState(SCE_C_REGEX); // JavaScript's RegEx
308
348
} else if (sc.ch == '\"') {
309
349
sc.SetState(SCE_C_STRING);
350
isIncludePreprocessor = false; // ensure that '>' won't end the string
351
} else if (isIncludePreprocessor && sc.ch == '<') {
352
sc.SetState(SCE_C_STRING);
310
353
} else if (sc.ch == '\'') {
311
354
sc.SetState(SCE_C_CHARACTER);
312
355
} else if (sc.ch == '#' && visibleChars == 0) {
318
361
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
319
362
if (sc.atLineEnd) {
320
363
sc.SetState(SCE_C_DEFAULT);
364
} else if (sc.Match("include")) {
365
isIncludePreprocessor = true;
322
367
} else if (isoperator(static_cast<char>(sc.ch))) {
323
368
sc.SetState(SCE_C_OPERATOR);
343
388
// Store both the current line's fold level and the next lines in the
344
389
// level store to make it easy to pick up with each increment
345
390
// and to make it possible to fiddle the current level for "} else {".
346
static void FoldNoBoxCppDoc(unsigned int startPos, int length, int initStyle,
391
static void FoldCppDoc(unsigned int startPos, int length, int initStyle,
392
WordList *[], Accessor &styler) {
394
// property fold.comment
395
// This option enables folding multi-line comments and explicit fold points when using the C++ lexer.
396
// Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //}
397
// at the end of a section that should fold.
348
398
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
400
// property fold.preprocessor
401
// This option enables folding preprocessor directives when using the C++ lexer.
402
// Includes C#'s explicit #region and #endregion folding directives.
349
403
bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
350
405
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
407
// property fold.at.else
408
// This option enables C++ folding on a "} else {" line of an if statement.
351
409
bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
411
bool foldWxSmith = styler.GetPropertyInt("fold.wxsmith", 1) != 0;
352
413
unsigned int endPos = startPos + length;
353
414
int visibleChars = 0;
354
415
int lineCurrent = styler.GetLine(startPos);
368
429
styleNext = styler.StyleAt(i + 1);
369
430
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
370
431
if (foldComment && IsStreamCommentStyle(style)) {
371
if (!IsStreamCommentStyle(stylePrev)) {
432
if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) {
373
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
434
} else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) {
374
435
// Comments don't end at end of line and the next character may be unstyled.
378
439
if (foldComment && (style == SCE_C_COMMENTLINE)) {
379
440
if ((ch == '/') && (chNext == '/')) {
380
441
char chNext2 = styler.SafeGetCharAt(i + 2);
443
char chNext3 = styler.SafeGetCharAt(i + 3);
381
445
if (chNext2 == '{') {
383
447
} else if (chNext2 == '}') {
450
} else if (chNext2 == '(' && chNext3 == '*') {
452
} else if (chNext2 == '*' && chNext3 == ')') {
459
if (foldWxSmith && (style == SCE_C_WXSMITH)) {
460
if (stylePrev != SCE_C_WXSMITH) {
462
} else if ( styleNext != SCE_C_WXSMITH) {
388
467
if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
390
469
unsigned int j = i + 1;
427
508
levelCurrent = levelNext;
428
509
levelMinCurrent = levelCurrent;
510
if (atEOL && (i == static_cast<unsigned int>(styler.Length()-1))) {
511
// There is an empty line at end of file so give it same level and empty
512
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
429
514
visibleChars = 0;
431
if (!isspacechar(ch))
436
static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
438
FoldNoBoxCppDoc(startPos, length, initStyle, styler);
441
519
static const char * const cppWordLists[] = {
442
520
"Primary keywords and identifiers",
443
521
"Secondary keywords and identifiers",
460
538
LexerModule lmCPP(SCLEX_CPP, ColouriseCppDocSensitive, "cpp", FoldCppDoc, cppWordLists);
461
539
LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, ColouriseCppDocInsensitive, "cppnocase", FoldCppDoc, cppWordLists);
462
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDocSensitive, "tcl", FoldCppDoc, cppWordLists);