1 // Scintilla source code edit control
4 ** Based on LexPascal.cxx
5 ** Written by Laurent le Tynevez
6 ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
7 ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
8 ** Updated by Rod Falck, Aug 2006 Converted to TAL
22 #include "Scintilla.h"
24 #include "StyleContext.h"
27 using namespace Scintilla
;
30 inline bool isTALoperator(char ch
)
32 return ch
== '\'' || ch
== '@' || ch
== '#' || isoperator(ch
);
35 inline bool isTALwordchar(char ch
)
37 return ch
== '$' || ch
== '^' || iswordchar(ch
);
40 inline bool isTALwordstart(char ch
)
42 return ch
== '$' || ch
== '^' || iswordstart(ch
);
45 static void getRange(unsigned int start
,
51 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
52 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
58 static bool IsStreamCommentStyle(int style
) {
59 return style
== SCE_C_COMMENT
||
60 style
== SCE_C_COMMENTDOC
||
61 style
== SCE_C_COMMENTDOCKEYWORD
||
62 style
== SCE_C_COMMENTDOCKEYWORDERROR
;
65 static void ColourTo(Accessor
&styler
, unsigned int end
, unsigned int attr
, bool bInAsm
) {
66 if ((bInAsm
) && (attr
== SCE_C_OPERATOR
|| attr
== SCE_C_NUMBER
|| attr
== SCE_C_DEFAULT
|| attr
== SCE_C_WORD
|| attr
== SCE_C_IDENTIFIER
)) {
67 styler
.ColourTo(end
, SCE_C_REGEX
);
69 styler
.ColourTo(end
, attr
);
72 // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm"
73 static int classifyWordTAL(unsigned int start
, unsigned int end
, /*WordList &keywords*/WordList
*keywordlists
[], Accessor
&styler
, bool bInAsm
) {
76 WordList
& keywords
= *keywordlists
[0];
77 WordList
& builtins
= *keywordlists
[1];
78 WordList
& nonreserved_keywords
= *keywordlists
[2];
81 getRange(start
, end
, styler
, s
, sizeof(s
));
83 char chAttr
= SCE_C_IDENTIFIER
;
84 if (isdigit(s
[0]) || (s
[0] == '.')) {
85 chAttr
= SCE_C_NUMBER
;
88 if (keywords
.InList(s
)) {
91 if (strcmp(s
, "asm") == 0) {
94 else if (strcmp(s
, "end") == 0) {
98 else if (s
[0] == '$' || builtins
.InList(s
)) {
101 else if (nonreserved_keywords
.InList(s
)) {
105 ColourTo(styler
, end
, chAttr
, (bInAsm
&& ret
!= -1));
109 static int classifyFoldPointTAL(const char* s
) {
111 if (!(isdigit(s
[0]) || (s
[0] == '.'))) {
112 if (strcmp(s
, "begin") == 0 ||
113 strcmp(s
, "block") == 0) {
115 } else if (strcmp(s
, "end") == 0) {
122 static void ColouriseTALDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
125 styler
.StartAt(startPos
);
127 int state
= initStyle
;
128 if (state
== SCE_C_CHARACTER
) // Does not leak onto next line
129 state
= SCE_C_DEFAULT
;
131 char chNext
= styler
[startPos
];
132 unsigned int lengthDoc
= startPos
+ length
;
134 bool bInClassDefinition
;
136 int currentLine
= styler
.GetLine(startPos
);
137 if (currentLine
> 0) {
138 styler
.SetLineState(currentLine
, styler
.GetLineState(currentLine
-1));
139 bInClassDefinition
= (styler
.GetLineState(currentLine
) == 1);
141 styler
.SetLineState(currentLine
, 0);
142 bInClassDefinition
= false;
145 bool bInAsm
= (state
== SCE_C_REGEX
);
147 state
= SCE_C_DEFAULT
;
149 styler
.StartSegment(startPos
);
150 int visibleChars
= 0;
151 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
154 chNext
= styler
.SafeGetCharAt(i
+ 1);
156 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
157 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
158 // Avoid triggering two times on Dos/Win
160 if (state
== SCE_C_CHARACTER
) {
161 ColourTo(styler
, i
, state
, bInAsm
);
162 state
= SCE_C_DEFAULT
;
166 styler
.SetLineState(currentLine
, (bInClassDefinition
? 1 : 0));
169 if (styler
.IsLeadByte(ch
)) {
170 chNext
= styler
.SafeGetCharAt(i
+ 2);
176 if (state
== SCE_C_DEFAULT
) {
177 if (isTALwordstart(ch
)) {
178 ColourTo(styler
, i
-1, state
, bInAsm
);
179 state
= SCE_C_IDENTIFIER
;
180 } else if (ch
== '!' && chNext
!= '*') {
181 ColourTo(styler
, i
-1, state
, bInAsm
);
182 state
= SCE_C_COMMENT
;
183 } else if (ch
== '!' && chNext
== '*') {
184 ColourTo(styler
, i
-1, state
, bInAsm
);
185 state
= SCE_C_COMMENTDOC
;
186 } else if (ch
== '-' && chNext
== '-') {
187 ColourTo(styler
, i
-1, state
, bInAsm
);
188 state
= SCE_C_COMMENTLINE
;
189 } else if (ch
== '"') {
190 ColourTo(styler
, i
-1, state
, bInAsm
);
191 state
= SCE_C_STRING
;
192 } else if (ch
== '?' && visibleChars
== 0) {
193 ColourTo(styler
, i
-1, state
, bInAsm
);
194 state
= SCE_C_PREPROCESSOR
;
195 } else if (isTALoperator(ch
)) {
196 ColourTo(styler
, i
-1, state
, bInAsm
);
197 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
199 } else if (state
== SCE_C_IDENTIFIER
) {
200 if (!isTALwordchar(ch
)) {
201 int lStateChange
= classifyWordTAL(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, bInAsm
);
203 if(lStateChange
== 1) {
204 styler
.SetLineState(currentLine
, 1);
205 bInClassDefinition
= true;
206 } else if(lStateChange
== 2) {
208 } else if(lStateChange
== -1) {
209 styler
.SetLineState(currentLine
, 0);
210 bInClassDefinition
= false;
214 state
= SCE_C_DEFAULT
;
215 chNext
= styler
.SafeGetCharAt(i
+ 1);
216 if (ch
== '!' && chNext
!= '*') {
217 state
= SCE_C_COMMENT
;
218 } else if (ch
== '!' && chNext
== '*') {
219 ColourTo(styler
, i
-1, state
, bInAsm
);
220 state
= SCE_C_COMMENTDOC
;
221 } else if (ch
== '-' && chNext
== '-') {
222 state
= SCE_C_COMMENTLINE
;
223 } else if (ch
== '"') {
224 state
= SCE_C_STRING
;
225 } else if (isTALoperator(ch
)) {
226 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
230 if (state
== SCE_C_PREPROCESSOR
) {
231 if ((ch
== '\r' || ch
== '\n') && !(chPrev
== '\\' || chPrev
== '\r')) {
232 ColourTo(styler
, i
-1, state
, bInAsm
);
233 state
= SCE_C_DEFAULT
;
235 } else if (state
== SCE_C_COMMENT
) {
236 if (ch
== '!' || (ch
== '\r' || ch
== '\n') ) {
237 ColourTo(styler
, i
, state
, bInAsm
);
238 state
= SCE_C_DEFAULT
;
240 } else if (state
== SCE_C_COMMENTDOC
) {
241 if (ch
== '!' || (ch
== '\r' || ch
== '\n')) {
242 if (((i
> styler
.GetStartSegment() + 2) || (
243 (initStyle
== SCE_C_COMMENTDOC
) &&
244 (styler
.GetStartSegment() == static_cast<unsigned int>(startPos
))))) {
245 ColourTo(styler
, i
, state
, bInAsm
);
246 state
= SCE_C_DEFAULT
;
249 } else if (state
== SCE_C_COMMENTLINE
) {
250 if (ch
== '\r' || ch
== '\n') {
251 ColourTo(styler
, i
-1, state
, bInAsm
);
252 state
= SCE_C_DEFAULT
;
254 } else if (state
== SCE_C_STRING
) {
256 ColourTo(styler
, i
, state
, bInAsm
);
257 state
= SCE_C_DEFAULT
;
261 if (!isspacechar(ch
))
265 ColourTo(styler
, lengthDoc
- 1, state
, bInAsm
);
268 static void FoldTALDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],
270 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
271 bool foldPreprocessor
= styler
.GetPropertyInt("fold.preprocessor") != 0;
272 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
273 unsigned int endPos
= startPos
+ length
;
274 int visibleChars
= 0;
275 int lineCurrent
= styler
.GetLine(startPos
);
276 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
277 int levelCurrent
= levelPrev
;
278 char chNext
= styler
[startPos
];
279 int styleNext
= styler
.StyleAt(startPos
);
280 int style
= initStyle
;
281 bool was_end
= false;
282 bool section
= false;
286 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
288 chNext
= styler
.SafeGetCharAt(i
+ 1);
289 int stylePrev
= style
;
291 styleNext
= styler
.StyleAt(i
+ 1);
292 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
294 if (stylePrev
== SCE_C_DEFAULT
&& (style
== SCE_C_WORD
|| style
== SCE_C_UUID
|| style
== SCE_C_PREPROCESSOR
))
296 // Store last word start point.
300 if (stylePrev
== SCE_C_WORD
|| style
== SCE_C_UUID
|| stylePrev
== SCE_C_PREPROCESSOR
) {
301 if(isTALwordchar(ch
) && !isTALwordchar(chNext
)) {
303 getRange(lastStart
, i
, styler
, s
, sizeof(s
));
304 if (stylePrev
== SCE_C_PREPROCESSOR
&& strcmp(s
, "?section") == 0)
310 else if (stylePrev
== SCE_C_WORD
|| stylePrev
== SCE_C_UUID
)
312 if (strcmp(s
, "block") == 0)
314 // block keyword is ignored immediately after end keyword
319 levelCurrent
+= classifyFoldPointTAL(s
);
320 if (strcmp(s
, "end") == 0)
332 if (foldComment
&& (style
== SCE_C_COMMENTLINE
)) {
333 if ((ch
== '/') && (chNext
== '/')) {
334 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
335 if (chNext2
== '{') {
337 } else if (chNext2
== '}') {
343 if (foldPreprocessor
&& (style
== SCE_C_PREPROCESSOR
)) {
344 if (ch
== '{' && chNext
== '$') {
345 unsigned int j
=i
+2; // skip {$
346 while ((j
<endPos
) && IsASpaceOrTab(styler
.SafeGetCharAt(j
))) {
349 if (styler
.Match(j
, "region") || styler
.Match(j
, "if")) {
351 } else if (styler
.Match(j
, "end")) {
357 if (foldComment
&& IsStreamCommentStyle(style
)) {
358 if (!IsStreamCommentStyle(stylePrev
)) {
360 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
361 // Comments don't end at end of line and the next character may be unstyled.
367 int lev
= levelPrev
| SC_FOLDLEVELBASE
;
368 if (visibleChars
== 0 && foldCompact
)
369 lev
|= SC_FOLDLEVELWHITEFLAG
;
370 if ((levelCurrent
> levelPrev
|| section
) && (visibleChars
> 0))
371 lev
|= SC_FOLDLEVELHEADERFLAG
;
372 if (lev
!= styler
.LevelAt(lineCurrent
)) {
373 styler
.SetLevel(lineCurrent
, lev
);
376 levelPrev
= levelCurrent
;
381 if (!isspacechar(ch
))
385 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
386 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
387 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
390 static const char * const TALWordListDesc
[] = {
396 LexerModule
lmTAL(SCLEX_TAL
, ColouriseTALDoc
, "TAL", FoldTALDoc
, TALWordListDesc
);