1 // Scintilla source code edit control
2 /** @file LexPascal.cxx
4 ** Written by Laurent le Tynevez
5 ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
6 ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
20 #include "Scintilla.h"
22 #include "StyleContext.h"
25 using namespace Scintilla
;
28 static void getRange(unsigned int start
,
34 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
35 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
41 static bool IsStreamCommentStyle(int style
) {
42 return style
== SCE_C_COMMENT
||
43 style
== SCE_C_COMMENTDOC
||
44 style
== SCE_C_COMMENTDOCKEYWORD
||
45 style
== SCE_C_COMMENTDOCKEYWORDERROR
;
48 static void ColourTo(Accessor
&styler
, unsigned int end
, unsigned int attr
, bool bInAsm
) {
49 if ((bInAsm
) && (attr
== SCE_C_OPERATOR
|| attr
== SCE_C_NUMBER
|| attr
== SCE_C_DEFAULT
|| attr
== SCE_C_WORD
|| attr
== SCE_C_IDENTIFIER
)) {
50 styler
.ColourTo(end
, SCE_C_REGEX
);
52 styler
.ColourTo(end
, attr
);
55 // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm"
56 static int classifyWordPascal(unsigned int start
, unsigned int end
, /*WordList &keywords*/WordList
*keywordlists
[], Accessor
&styler
, bool bInClass
, bool bInAsm
) {
59 WordList
& keywords
= *keywordlists
[0];
60 WordList
& classwords
= *keywordlists
[1];
63 getRange(start
, end
, styler
, s
, sizeof(s
));
65 char chAttr
= SCE_C_IDENTIFIER
;
66 if (isdigit(s
[0]) || (s
[0] == '.') ||(s
[0] == '$')) {
67 chAttr
= SCE_C_NUMBER
;
71 chAttr
= SCE_C_CHARACTER
;
74 if (keywords
.InList(s
)) {
77 if(strcmp(s
, "class") == 0) {
80 else if (strcmp(s
, "asm") == 0) {
83 else if (strcmp(s
, "end") == 0) {
86 } else if (bInClass
) {
87 if (classwords
.InList(s
)) {
93 ColourTo(styler
, end
, chAttr
, (bInAsm
&& ret
!= -1));
97 static int classifyFoldPointPascal(const char* s
) {
99 if (!(isdigit(s
[0]) || (s
[0] == '.'))) {
100 if (strcmp(s
, "begin") == 0 ||
101 strcmp(s
, "object") == 0 ||
102 strcmp(s
, "case") == 0 ||
103 strcmp(s
, "class") == 0 ||
104 strcmp(s
, "record") == 0 ||
105 strcmp(s
, "try") == 0) {
107 } else if (strcmp(s
, "end") == 0) {
114 static void ColourisePascalDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
117 styler
.StartAt(startPos
);
119 int state
= initStyle
;
120 if (state
== SCE_C_CHARACTER
) // Does not leak onto next line
121 state
= SCE_C_DEFAULT
;
123 char chNext
= styler
[startPos
];
124 unsigned int lengthDoc
= startPos
+ length
;
126 bool bInClassDefinition
;
128 int currentLine
= styler
.GetLine(startPos
);
129 if (currentLine
> 0) {
130 styler
.SetLineState(currentLine
, styler
.GetLineState(currentLine
-1));
131 bInClassDefinition
= (styler
.GetLineState(currentLine
) == 1);
133 styler
.SetLineState(currentLine
, 0);
134 bInClassDefinition
= false;
137 bool bInAsm
= (state
== SCE_C_REGEX
);
139 state
= SCE_C_DEFAULT
;
141 styler
.StartSegment(startPos
);
142 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
145 chNext
= styler
.SafeGetCharAt(i
+ 1);
147 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
148 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
149 // Avoid triggering two times on Dos/Win
151 if (state
== SCE_C_CHARACTER
) {
152 ColourTo(styler
, i
, state
, bInAsm
);
153 state
= SCE_C_DEFAULT
;
156 styler
.SetLineState(currentLine
, (bInClassDefinition
? 1 : 0));
159 if (styler
.IsLeadByte(ch
)) {
160 chNext
= styler
.SafeGetCharAt(i
+ 2);
166 if (state
== SCE_C_DEFAULT
) {
167 if (iswordstart(ch
) || ch
== '#' || ch
== '$' || (ch
== '@' && bInAsm
)) {
168 ColourTo(styler
, i
-1, state
, bInAsm
);
169 state
= SCE_C_IDENTIFIER
;
170 } else if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
171 ColourTo(styler
, i
-1, state
, bInAsm
);
172 state
= SCE_C_COMMENT
;
173 } else if (ch
== '(' && chNext
== '*'
174 && styler
.SafeGetCharAt(i
+ 2) != '$'
175 && styler
.SafeGetCharAt(i
+ 2) != '&') {
176 ColourTo(styler
, i
-1, state
, bInAsm
);
177 state
= SCE_C_COMMENTDOC
;
178 } else if (ch
== '/' && chNext
== '/') {
179 ColourTo(styler
, i
-1, state
, bInAsm
);
180 state
= SCE_C_COMMENTLINE
;
181 } else if (ch
== '\'') {
182 ColourTo(styler
, i
-1, state
, bInAsm
);
183 state
= SCE_C_CHARACTER
;
184 } else if (ch
== '{' && (chNext
== '$' || chNext
=='&')) {
185 ColourTo(styler
, i
-1, state
, bInAsm
);
186 state
= SCE_C_PREPROCESSOR
;
187 } else if (isoperator(ch
)) {
188 ColourTo(styler
, i
-1, state
, bInAsm
);
189 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
192 } else if (state
== SCE_C_IDENTIFIER
) {
193 bool bDoublePoint
= ((ch
== '.') && (chPrev
== '.'));
194 if ((!iswordchar(ch
) && ch
!= '$' && ch
!= '#' && (ch
!= '@' || !bInAsm
)) || bDoublePoint
) {
195 if (bDoublePoint
) i
--;
196 int lStateChange
= classifyWordPascal(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, bInClassDefinition
, bInAsm
);
198 if(lStateChange
== 1) {
199 styler
.SetLineState(currentLine
, 1);
200 bInClassDefinition
= true;
201 } else if(lStateChange
== 2) {
203 } else if(lStateChange
== -1) {
204 styler
.SetLineState(currentLine
, 0);
205 bInClassDefinition
= false;
210 ColourTo(styler
, i
-1, SCE_C_DEFAULT
, bInAsm
);
213 state
= SCE_C_DEFAULT
;
214 chNext
= styler
.SafeGetCharAt(i
+ 1);
215 if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
216 state
= SCE_C_COMMENT
;
217 } else if (ch
== '(' && chNext
== '*'
218 && styler
.SafeGetCharAt(i
+ 2) != '$'
219 && styler
.SafeGetCharAt(i
+ 2) != '&') {
220 ColourTo(styler
, i
-1, state
, bInAsm
);
221 state
= SCE_C_COMMENTDOC
;
222 } else if (ch
== '/' && chNext
== '/') {
223 state
= SCE_C_COMMENTLINE
;
224 } else if (ch
== '\'') {
225 state
= SCE_C_CHARACTER
;
226 } else if (isoperator(ch
)) {
227 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
231 if (state
== SCE_C_PREPROCESSOR
) {
233 ColourTo(styler
, i
, state
, bInAsm
);
234 state
= SCE_C_DEFAULT
;
236 if ((ch
== '\r' || ch
== '\n') && !(chPrev
== '\\' || chPrev
== '\r')) {
237 ColourTo(styler
, i
-1, state
, bInAsm
);
238 state
= SCE_C_DEFAULT
;
241 } else if (state
== SCE_C_COMMENT
) {
243 ColourTo(styler
, i
, state
, bInAsm
);
244 state
= SCE_C_DEFAULT
;
246 } else if (state
== SCE_C_COMMENTDOC
) {
247 if (ch
== ')' && chPrev
== '*') {
248 if (((i
> styler
.GetStartSegment() + 2) || (
249 (initStyle
== SCE_C_COMMENTDOC
) &&
250 (styler
.GetStartSegment() == static_cast<unsigned int>(startPos
))))) {
251 ColourTo(styler
, i
, state
, bInAsm
);
252 state
= SCE_C_DEFAULT
;
255 } else if (state
== SCE_C_COMMENTLINE
) {
256 if (ch
== '\r' || ch
== '\n') {
257 ColourTo(styler
, i
-1, state
, bInAsm
);
258 state
= SCE_C_DEFAULT
;
260 } else if (state
== SCE_C_CHARACTER
) {
262 ColourTo(styler
, i
, state
, bInAsm
);
263 state
= SCE_C_DEFAULT
;
269 ColourTo(styler
, lengthDoc
- 1, state
, bInAsm
);
272 static void FoldPascalDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],
274 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
275 bool foldPreprocessor
= styler
.GetPropertyInt("fold.preprocessor") != 0;
276 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
277 unsigned int endPos
= startPos
+ length
;
278 int visibleChars
= 0;
279 int lineCurrent
= styler
.GetLine(startPos
);
280 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
281 int levelCurrent
= levelPrev
;
282 char chNext
= styler
[startPos
];
283 int styleNext
= styler
.StyleAt(startPos
);
284 int style
= initStyle
;
288 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
290 chNext
= styler
.SafeGetCharAt(i
+ 1);
291 int stylePrev
= style
;
293 styleNext
= styler
.StyleAt(i
+ 1);
294 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
296 if (stylePrev
!= SCE_C_WORD
&& style
== SCE_C_WORD
)
298 // Store last word start point.
302 if (stylePrev
== SCE_C_WORD
) {
303 if(iswordchar(ch
) && !iswordchar(chNext
)) {
305 getRange(lastStart
, i
, styler
, s
, sizeof(s
));
306 levelCurrent
+= classifyFoldPointPascal(s
);
310 if (foldComment
&& (style
== SCE_C_COMMENTLINE
)) {
311 if ((ch
== '/') && (chNext
== '/')) {
312 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
313 if (chNext2
== '{') {
315 } else if (chNext2
== '}') {
321 if (foldPreprocessor
&& (style
== SCE_C_PREPROCESSOR
)) {
322 if (ch
== '{' && chNext
== '$') {
323 unsigned int j
=i
+2; // skip {$
324 while ((j
<endPos
) && IsASpaceOrTab(styler
.SafeGetCharAt(j
))) {
327 if (styler
.Match(j
, "region") || styler
.Match(j
, "if")) {
329 } else if (styler
.Match(j
, "end")) {
335 if (foldComment
&& IsStreamCommentStyle(style
)) {
336 if (!IsStreamCommentStyle(stylePrev
)) {
338 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
339 // Comments don't end at end of line and the next character may be unstyled.
346 if (visibleChars
== 0 && foldCompact
)
347 lev
|= SC_FOLDLEVELWHITEFLAG
;
348 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
349 lev
|= SC_FOLDLEVELHEADERFLAG
;
350 if (lev
!= styler
.LevelAt(lineCurrent
)) {
351 styler
.SetLevel(lineCurrent
, lev
);
354 levelPrev
= levelCurrent
;
358 if (!isspacechar(ch
))
362 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
363 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
364 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
367 static const char * const pascalWordListDesc
[] = {
373 LexerModule
lmPascal(SCLEX_PASCAL
, ColourisePascalDoc
, "pascal", FoldPascalDoc
, pascalWordListDesc
);