Add an UI to enable/disable specific overlay handlers.
[TortoiseGit.git] / ext / scintilla / src / LexD.cxx
blob0d6db93ca727fc25be8ca0ec949ab6ad271fde23
1 /** @file LexD.cxx
2 ** Lexer for D.
3 **
4 ** Copyright (c) 2006 by Waldemar Augustyn <waldemar@wdmsys.com>
5 **/
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.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
15 #include "Platform.h"
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #ifdef SCI_NAMESPACE
25 using namespace Scintilla;
26 #endif
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.
32 /*/
34 // We use custom qualifiers since it is not clear what D allows.
36 static bool IsWordStart(int ch) {
37 return isascii(ch) && (isalpha(ch) || ch == '_');
40 static bool IsWord(int ch) {
41 return isascii(ch) && (isalnum(ch) || ch == '_');
44 static bool IsDoxygen(int ch) {
45 if (isascii(ch) && islower(ch))
46 return true;
47 if (ch == '$' || ch == '@' || ch == '\\' ||
48 ch == '&' || ch == '#' || ch == '<' || ch == '>' ||
49 ch == '{' || ch == '}' || ch == '[' || ch == ']')
50 return true;
51 return false;
55 static void ColouriseDoc(unsigned int startPos, int length, int initStyle,
56 WordList *keywordlists[], Accessor &styler, bool caseSensitive) {
58 WordList &keywords = *keywordlists[0];
59 WordList &keywords2 = *keywordlists[1];
60 WordList &keywords3 = *keywordlists[2];
61 WordList &keywords4 = *keywordlists[3];
63 int styleBeforeDCKeyword = SCE_D_DEFAULT;
65 StyleContext sc(startPos, length, initStyle, styler);
67 int curLine = styler.GetLine(startPos);
68 int curNcLevel = curLine > 0? styler.GetLineState(curLine-1): 0;
70 for (; sc.More(); sc.Forward()) {
72 if (sc.atLineStart) {
73 if (sc.state == SCE_D_STRING) {
74 // Prevent SCE_D_STRINGEOL from leaking back to previous line which
75 // ends with a line continuation by locking in the state upto this position.
76 sc.SetState(SCE_D_STRING);
78 curLine = styler.GetLine(sc.currentPos);
79 styler.SetLineState(curLine, curNcLevel);
82 // Handle line continuation generically.
83 if (sc.ch == '\\') {
84 if (sc.chNext == '\n' || sc.chNext == '\r') {
85 sc.Forward();
86 if (sc.ch == '\r' && sc.chNext == '\n') {
87 sc.Forward();
89 continue;
93 // Determine if the current state should terminate.
94 switch (sc.state) {
95 case SCE_D_OPERATOR:
96 sc.SetState(SCE_D_DEFAULT);
97 break;
98 case SCE_D_NUMBER:
99 // We accept almost anything because of hex. and number suffixes
100 if (!IsWord(sc.ch) && sc.ch != '.') {
101 sc.SetState(SCE_D_DEFAULT);
103 break;
104 case SCE_D_IDENTIFIER:
105 if (!IsWord(sc.ch)) {
106 char s[1000];
107 if (caseSensitive) {
108 sc.GetCurrent(s, sizeof(s));
109 } else {
110 sc.GetCurrentLowered(s, sizeof(s));
112 if (keywords.InList(s)) {
113 sc.ChangeState(SCE_D_WORD);
114 } else if (keywords2.InList(s)) {
115 sc.ChangeState(SCE_D_WORD2);
116 } else if (keywords4.InList(s)) {
117 sc.ChangeState(SCE_D_TYPEDEF);
119 sc.SetState(SCE_D_DEFAULT);
121 break;
122 case SCE_D_COMMENT:
123 if (sc.Match('*', '/')) {
124 sc.Forward();
125 sc.ForwardSetState(SCE_D_DEFAULT);
127 break;
128 case SCE_D_COMMENTDOC:
129 if (sc.Match('*', '/')) {
130 sc.Forward();
131 sc.ForwardSetState(SCE_D_DEFAULT);
132 } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
133 // Verify that we have the conditions to mark a comment-doc-keyword
134 if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
135 styleBeforeDCKeyword = SCE_D_COMMENTDOC;
136 sc.SetState(SCE_D_COMMENTDOCKEYWORD);
139 break;
140 case SCE_D_COMMENTLINE:
141 if (sc.atLineStart) {
142 sc.SetState(SCE_D_DEFAULT);
144 break;
145 case SCE_D_COMMENTLINEDOC:
146 if (sc.atLineStart) {
147 sc.SetState(SCE_D_DEFAULT);
148 } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
149 // Verify that we have the conditions to mark a comment-doc-keyword
150 if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
151 styleBeforeDCKeyword = SCE_D_COMMENTLINEDOC;
152 sc.SetState(SCE_D_COMMENTDOCKEYWORD);
155 break;
156 case SCE_D_COMMENTDOCKEYWORD:
157 if ((styleBeforeDCKeyword == SCE_D_COMMENTDOC) && sc.Match('*', '/')) {
158 sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
159 sc.Forward();
160 sc.ForwardSetState(SCE_D_DEFAULT);
161 } else if (!IsDoxygen(sc.ch)) {
162 char s[100];
163 if (caseSensitive) {
164 sc.GetCurrent(s, sizeof(s));
165 } else {
166 sc.GetCurrentLowered(s, sizeof(s));
168 if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
169 sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR);
171 sc.SetState(styleBeforeDCKeyword);
173 break;
174 case SCE_D_COMMENTNESTED:
175 if (sc.Match('+', '/')) {
176 if (curNcLevel > 0)
177 curNcLevel -= 1;
178 curLine = styler.GetLine(sc.currentPos);
179 styler.SetLineState(curLine, curNcLevel);
180 sc.Forward();
181 if (curNcLevel == 0) {
182 sc.ForwardSetState(SCE_D_DEFAULT);
185 else if (sc.Match('/','+')) {
186 curNcLevel += 1;
187 curLine = styler.GetLine(sc.currentPos);
188 styler.SetLineState(curLine, curNcLevel);
189 sc.Forward();
191 break;
192 case SCE_D_STRING:
193 if (sc.atLineEnd) {
194 sc.ChangeState(SCE_D_STRINGEOL);
195 } else if (sc.ch == '\\') {
196 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
197 sc.Forward();
199 } else if (sc.ch == '\"') {
200 sc.ForwardSetState(SCE_D_DEFAULT);
202 break;
203 case SCE_D_CHARACTER:
204 if (sc.atLineEnd) {
205 sc.ChangeState(SCE_D_STRINGEOL);
206 } else if (sc.ch == '\\') {
207 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
208 sc.Forward();
210 } else if (sc.ch == '\'') {
211 sc.ForwardSetState(SCE_D_DEFAULT);
213 break;
214 case SCE_D_STRINGEOL:
215 if (sc.atLineStart) {
216 sc.SetState(SCE_D_DEFAULT);
218 break;
221 // Determine if a new state should be entered.
222 if (sc.state == SCE_D_DEFAULT) {
223 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
224 sc.SetState(SCE_D_NUMBER);
225 } else if (IsWordStart(sc.ch)) {
226 sc.SetState(SCE_D_IDENTIFIER);
227 } else if (sc.Match('/','+')) {
228 curNcLevel += 1;
229 curLine = styler.GetLine(sc.currentPos);
230 styler.SetLineState(curLine, curNcLevel);
231 sc.SetState(SCE_D_COMMENTNESTED);
232 sc.Forward();
233 } else if (sc.Match('/', '*')) {
234 if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
235 sc.SetState(SCE_D_COMMENTDOC);
236 } else {
237 sc.SetState(SCE_D_COMMENT);
239 sc.Forward(); // Eat the * so it isn't used for the end of the comment
240 } else if (sc.Match('/', '/')) {
241 if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
242 // Support of Qt/Doxygen doc. style
243 sc.SetState(SCE_D_COMMENTLINEDOC);
244 else
245 sc.SetState(SCE_D_COMMENTLINE);
246 } else if (sc.ch == '\"') {
247 sc.SetState(SCE_D_STRING);
248 } else if (sc.ch == '\'') {
249 sc.SetState(SCE_D_CHARACTER);
250 } else if (isoperator(static_cast<char>(sc.ch))) {
251 sc.SetState(SCE_D_OPERATOR);
255 sc.Complete();
258 static bool IsStreamCommentStyle(int style) {
259 return style == SCE_D_COMMENT ||
260 style == SCE_D_COMMENTDOC ||
261 style == SCE_D_COMMENTDOCKEYWORD ||
262 style == SCE_D_COMMENTDOCKEYWORDERROR;
265 // Store both the current line's fold level and the next lines in the
266 // level store to make it easy to pick up with each increment
267 // and to make it possible to fiddle the current level for "} else {".
268 static void FoldDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) {
269 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
270 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
271 bool foldAtElse = styler.GetPropertyInt("lexer.d.fold.at.else",
272 styler.GetPropertyInt("fold.at.else", 0)) != 0;
273 unsigned int endPos = startPos + length;
274 int visibleChars = 0;
275 int lineCurrent = styler.GetLine(startPos);
276 int levelCurrent = SC_FOLDLEVELBASE;
277 if (lineCurrent > 0)
278 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
279 int levelMinCurrent = levelCurrent;
280 int levelNext = levelCurrent;
281 char chNext = styler[startPos];
282 int styleNext = styler.StyleAt(startPos);
283 int style = initStyle;
284 for (unsigned int i = startPos; i < endPos; i++) {
285 char ch = chNext;
286 chNext = styler.SafeGetCharAt(i + 1);
287 int stylePrev = style;
288 style = styleNext;
289 styleNext = styler.StyleAt(i + 1);
290 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
291 if (foldComment && IsStreamCommentStyle(style)) {
292 if (!IsStreamCommentStyle(stylePrev)) {
293 levelNext++;
294 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
295 // Comments don't end at end of line and the next character may be unstyled.
296 levelNext--;
299 if (style == SCE_D_OPERATOR) {
300 if (ch == '{') {
301 // Measure the minimum before a '{' to allow
302 // folding on "} else {"
303 if (levelMinCurrent > levelNext) {
304 levelMinCurrent = levelNext;
306 levelNext++;
307 } else if (ch == '}') {
308 levelNext--;
311 if (atEOL) {
312 if (foldComment) { // Handle nested comments
313 int nc;
314 nc = styler.GetLineState(lineCurrent);
315 nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0;
316 levelNext += nc;
318 int levelUse = levelCurrent;
319 if (foldAtElse) {
320 levelUse = levelMinCurrent;
322 int lev = levelUse | levelNext << 16;
323 if (visibleChars == 0 && foldCompact)
324 lev |= SC_FOLDLEVELWHITEFLAG;
325 if (levelUse < levelNext)
326 lev |= SC_FOLDLEVELHEADERFLAG;
327 if (lev != styler.LevelAt(lineCurrent)) {
328 styler.SetLevel(lineCurrent, lev);
330 lineCurrent++;
331 levelCurrent = levelNext;
332 levelMinCurrent = levelCurrent;
333 visibleChars = 0;
335 if (!IsASpace(ch))
336 visibleChars++;
340 static void FoldDDoc(unsigned int startPos, int length, int initStyle,
341 WordList *[], Accessor &styler) {
342 FoldDoc(startPos, length, initStyle, styler);
345 static const char * const dWordLists[] = {
346 "Primary keywords and identifiers",
347 "Secondary keywords and identifiers",
348 "Documentation comment keywords",
349 "Type definitions and aliases",
353 static void ColouriseDDoc(unsigned int startPos, int length,
354 int initStyle, WordList *keywordlists[], Accessor &styler) {
355 ColouriseDoc(startPos, length, initStyle, keywordlists, styler, true);
358 LexerModule lmD(SCLEX_D, ColouriseDDoc, "d", FoldDDoc, dWordLists);