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"
24 static void getRange(unsigned int start
,
30 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
31 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
37 static bool IsStreamCommentStyle(int style
) {
38 return style
== SCE_C_COMMENT
||
39 style
== SCE_C_COMMENTDOC
||
40 style
== SCE_C_COMMENTDOCKEYWORD
||
41 style
== SCE_C_COMMENTDOCKEYWORDERROR
;
44 static void ColourTo(Accessor
&styler
, unsigned int end
, unsigned int attr
, bool bInAsm
) {
45 if ((bInAsm
) && (attr
== SCE_C_OPERATOR
|| attr
== SCE_C_NUMBER
|| attr
== SCE_C_DEFAULT
|| attr
== SCE_C_WORD
|| attr
== SCE_C_IDENTIFIER
)) {
46 styler
.ColourTo(end
, SCE_C_REGEX
);
48 styler
.ColourTo(end
, attr
);
51 // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm"
52 static int classifyWordPascal(unsigned int start
, unsigned int end
, /*WordList &keywords*/WordList
*keywordlists
[], Accessor
&styler
, bool bInClass
, bool bInAsm
) {
55 WordList
& keywords
= *keywordlists
[0];
56 WordList
& classwords
= *keywordlists
[1];
59 getRange(start
, end
, styler
, s
, sizeof(s
));
61 char chAttr
= SCE_C_IDENTIFIER
;
62 if (isdigit(s
[0]) || (s
[0] == '.') ||(s
[0] == '$')) {
63 chAttr
= SCE_C_NUMBER
;
67 chAttr
= SCE_C_CHARACTER
;
70 if (keywords
.InList(s
)) {
73 if(strcmp(s
, "class") == 0) {
76 else if (strcmp(s
, "asm") == 0) {
79 else if (strcmp(s
, "end") == 0) {
82 } else if (bInClass
) {
83 if (classwords
.InList(s
)) {
89 ColourTo(styler
, end
, chAttr
, (bInAsm
&& ret
!= -1));
93 static int classifyFoldPointPascal(const char* s
) {
95 if (!(isdigit(s
[0]) || (s
[0] == '.'))) {
96 if (strcmp(s
, "begin") == 0 ||
97 strcmp(s
, "object") == 0 ||
98 strcmp(s
, "case") == 0 ||
99 strcmp(s
, "class") == 0 ||
100 strcmp(s
, "record") == 0 ||
101 strcmp(s
, "try") == 0) {
103 } else if (strcmp(s
, "end") == 0) {
110 static void ColourisePascalDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
113 styler
.StartAt(startPos
);
115 int state
= initStyle
;
116 if (state
== SCE_C_CHARACTER
) // Does not leak onto next line
117 state
= SCE_C_DEFAULT
;
119 char chNext
= styler
[startPos
];
120 unsigned int lengthDoc
= startPos
+ length
;
122 bool bInClassDefinition
;
124 int currentLine
= styler
.GetLine(startPos
);
125 if (currentLine
> 0) {
126 styler
.SetLineState(currentLine
, styler
.GetLineState(currentLine
-1));
127 bInClassDefinition
= (styler
.GetLineState(currentLine
) == 1);
129 styler
.SetLineState(currentLine
, 0);
130 bInClassDefinition
= false;
133 bool bInAsm
= (state
== SCE_C_REGEX
);
135 state
= SCE_C_DEFAULT
;
137 styler
.StartSegment(startPos
);
138 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
141 chNext
= styler
.SafeGetCharAt(i
+ 1);
143 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
144 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
145 // Avoid triggering two times on Dos/Win
147 if (state
== SCE_C_CHARACTER
) {
148 ColourTo(styler
, i
, state
, bInAsm
);
149 state
= SCE_C_DEFAULT
;
152 styler
.SetLineState(currentLine
, (bInClassDefinition
? 1 : 0));
155 if (styler
.IsLeadByte(ch
)) {
156 chNext
= styler
.SafeGetCharAt(i
+ 2);
162 if (state
== SCE_C_DEFAULT
) {
163 if (iswordstart(ch
) || ch
== '#' || ch
== '$' || (ch
== '@' && bInAsm
)) {
164 ColourTo(styler
, i
-1, state
, bInAsm
);
165 state
= SCE_C_IDENTIFIER
;
166 } else if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
167 ColourTo(styler
, i
-1, state
, bInAsm
);
168 state
= SCE_C_COMMENT
;
169 } else if (ch
== '(' && chNext
== '*'
170 && styler
.SafeGetCharAt(i
+ 2) != '$'
171 && styler
.SafeGetCharAt(i
+ 2) != '&') {
172 ColourTo(styler
, i
-1, state
, bInAsm
);
173 state
= SCE_C_COMMENTDOC
;
174 } else if (ch
== '/' && chNext
== '/') {
175 ColourTo(styler
, i
-1, state
, bInAsm
);
176 state
= SCE_C_COMMENTLINE
;
177 } else if (ch
== '\'') {
178 ColourTo(styler
, i
-1, state
, bInAsm
);
179 state
= SCE_C_CHARACTER
;
180 } else if (ch
== '{' && (chNext
== '$' || chNext
=='&')) {
181 ColourTo(styler
, i
-1, state
, bInAsm
);
182 state
= SCE_C_PREPROCESSOR
;
183 } else if (isoperator(ch
)) {
184 ColourTo(styler
, i
-1, state
, bInAsm
);
185 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
188 } else if (state
== SCE_C_IDENTIFIER
) {
189 bool bDoublePoint
= ((ch
== '.') && (chPrev
== '.'));
190 if ((!iswordchar(ch
) && ch
!= '$' && ch
!= '#' && (ch
!= '@' || !bInAsm
)) || bDoublePoint
) {
191 if (bDoublePoint
) i
--;
192 int lStateChange
= classifyWordPascal(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, bInClassDefinition
, bInAsm
);
194 if(lStateChange
== 1) {
195 styler
.SetLineState(currentLine
, 1);
196 bInClassDefinition
= true;
197 } else if(lStateChange
== 2) {
199 } else if(lStateChange
== -1) {
200 styler
.SetLineState(currentLine
, 0);
201 bInClassDefinition
= false;
206 ColourTo(styler
, i
-1, SCE_C_DEFAULT
, bInAsm
);
209 state
= SCE_C_DEFAULT
;
210 chNext
= styler
.SafeGetCharAt(i
+ 1);
211 if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
212 state
= SCE_C_COMMENT
;
213 } else if (ch
== '(' && chNext
== '*'
214 && styler
.SafeGetCharAt(i
+ 2) != '$'
215 && styler
.SafeGetCharAt(i
+ 2) != '&') {
216 ColourTo(styler
, i
-1, state
, bInAsm
);
217 state
= SCE_C_COMMENTDOC
;
218 } else if (ch
== '/' && chNext
== '/') {
219 state
= SCE_C_COMMENTLINE
;
220 } else if (ch
== '\'') {
221 state
= SCE_C_CHARACTER
;
222 } else if (isoperator(ch
)) {
223 ColourTo(styler
, i
, SCE_C_OPERATOR
, bInAsm
);
227 if (state
== SCE_C_PREPROCESSOR
) {
229 ColourTo(styler
, i
, state
, bInAsm
);
230 state
= SCE_C_DEFAULT
;
232 if ((ch
== '\r' || ch
== '\n') && !(chPrev
== '\\' || chPrev
== '\r')) {
233 ColourTo(styler
, i
-1, state
, bInAsm
);
234 state
= SCE_C_DEFAULT
;
237 } else if (state
== SCE_C_COMMENT
) {
239 ColourTo(styler
, i
, state
, bInAsm
);
240 state
= SCE_C_DEFAULT
;
242 } else if (state
== SCE_C_COMMENTDOC
) {
243 if (ch
== ')' && chPrev
== '*') {
244 if (((i
> styler
.GetStartSegment() + 2) || (
245 (initStyle
== SCE_C_COMMENTDOC
) &&
246 (styler
.GetStartSegment() == static_cast<unsigned int>(startPos
))))) {
247 ColourTo(styler
, i
, state
, bInAsm
);
248 state
= SCE_C_DEFAULT
;
251 } else if (state
== SCE_C_COMMENTLINE
) {
252 if (ch
== '\r' || ch
== '\n') {
253 ColourTo(styler
, i
-1, state
, bInAsm
);
254 state
= SCE_C_DEFAULT
;
256 } else if (state
== SCE_C_CHARACTER
) {
258 ColourTo(styler
, i
, state
, bInAsm
);
259 state
= SCE_C_DEFAULT
;
265 ColourTo(styler
, lengthDoc
- 1, state
, bInAsm
);
268 static void FoldPascalDoc(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
;
284 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
286 chNext
= styler
.SafeGetCharAt(i
+ 1);
287 int stylePrev
= style
;
289 styleNext
= styler
.StyleAt(i
+ 1);
290 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
292 if (stylePrev
== SCE_C_DEFAULT
&& style
== SCE_C_WORD
)
294 // Store last word start point.
298 if (stylePrev
== SCE_C_WORD
) {
299 if(iswordchar(ch
) && !iswordchar(chNext
)) {
301 getRange(lastStart
, i
, styler
, s
, sizeof(s
));
302 levelCurrent
+= classifyFoldPointPascal(s
);
306 if (foldComment
&& (style
== SCE_C_COMMENTLINE
)) {
307 if ((ch
== '/') && (chNext
== '/')) {
308 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
309 if (chNext2
== '{') {
311 } else if (chNext2
== '}') {
317 if (foldPreprocessor
&& (style
== SCE_C_PREPROCESSOR
)) {
318 if (ch
== '{' && chNext
== '$') {
319 unsigned int j
=i
+2; // skip {$
320 while ((j
<endPos
) && IsASpaceOrTab(styler
.SafeGetCharAt(j
))) {
323 if (styler
.Match(j
, "region") || styler
.Match(j
, "if")) {
325 } else if (styler
.Match(j
, "end")) {
331 if (foldComment
&& IsStreamCommentStyle(style
)) {
332 if (!IsStreamCommentStyle(stylePrev
)) {
334 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
335 // Comments don't end at end of line and the next character may be unstyled.
342 if (visibleChars
== 0 && foldCompact
)
343 lev
|= SC_FOLDLEVELWHITEFLAG
;
344 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
345 lev
|= SC_FOLDLEVELHEADERFLAG
;
346 if (lev
!= styler
.LevelAt(lineCurrent
)) {
347 styler
.SetLevel(lineCurrent
, lev
);
350 levelPrev
= levelCurrent
;
354 if (!isspacechar(ch
))
358 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
359 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
360 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
363 static const char * const pascalWordListDesc
[] = {
369 LexerModule
lmPascal(SCLEX_PASCAL
, ColourisePascalDoc
, "pascal", FoldPascalDoc
, pascalWordListDesc
);