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
19 #include "Scintilla.h"
21 #include "StyleContext.h"
23 static void getRange(unsigned int start
,
29 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
30 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
36 static bool IsStreamCommentStyle(int style
) {
37 return style
== SCE_C_COMMENT
||
38 style
== SCE_C_COMMENTDOC
||
39 style
== SCE_C_COMMENTDOCKEYWORD
||
40 style
== SCE_C_COMMENTDOCKEYWORDERROR
;
43 static inline bool IsAWordChar(const int ch
) {
44 return (ch
< 0x80) && (isalnum(ch
) || ch
== '.' || ch
== '_');
47 // returns 1 if the item starts a class definition, and -1 if the word is "end".
48 static int classifyWordPascal(unsigned int start
, unsigned int end
, /*WordList &keywords*/WordList
*keywordlists
[], Accessor
&styler
, bool bInClass
) {
51 WordList
& keywords
= *keywordlists
[0];
52 WordList
& classwords
= *keywordlists
[1];
55 getRange(start
, end
, styler
, s
, sizeof(s
));
57 char chAttr
= SCE_C_IDENTIFIER
;
58 if (isdigit(s
[0]) || (s
[0] == '.')) {
59 chAttr
= SCE_C_NUMBER
;
62 if (keywords
.InList(s
)) {
65 if(strcmp(s
, "class") == 0)
67 else if(strcmp(s
, "end") == 0)
69 } else if (bInClass
) {
70 if (classwords
.InList(s
)) {
75 styler
.ColourTo(end
, chAttr
);
79 static int classifyFoldPointPascal(const char* s
) {
81 if (!(isdigit(s
[0]) || (s
[0] == '.'))) {
82 if (strcmp(s
, "begin") == 0 ||
83 strcmp(s
, "object") == 0 ||
84 strcmp(s
, "case") == 0 ||
85 strcmp(s
, "class") == 0 ||
86 strcmp(s
, "record") == 0 ||
87 strcmp(s
, "try") == 0) {
89 } else if (strcmp(s
, "end") == 0) {
96 static void ColourisePascalDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
99 styler
.StartAt(startPos
);
101 int state
= initStyle
;
102 if (state
== SCE_C_STRINGEOL
) // Does not leak onto next line
103 state
= SCE_C_DEFAULT
;
105 char chNext
= styler
[startPos
];
106 unsigned int lengthDoc
= startPos
+ length
;
107 int visibleChars
= 0;
109 bool bInClassDefinition
;
110 int currentLine
= styler
.GetLine(startPos
);
111 if (currentLine
> 0) {
112 styler
.SetLineState(currentLine
, styler
.GetLineState(currentLine
-1));
113 bInClassDefinition
= (styler
.GetLineState(currentLine
) == 1);
115 styler
.SetLineState(currentLine
, 0);
116 bInClassDefinition
= false;
119 styler
.StartSegment(startPos
);
120 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
123 chNext
= styler
.SafeGetCharAt(i
+ 1);
125 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
126 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
127 // Avoid triggering two times on Dos/Win
129 if (state
== SCE_C_STRINGEOL
) {
130 styler
.ColourTo(i
, state
);
131 state
= SCE_C_DEFAULT
;
135 styler
.SetLineState(currentLine
, (bInClassDefinition
? 1 : 0));
137 if (!isspacechar(ch
))
140 if (styler
.IsLeadByte(ch
)) {
141 chNext
= styler
.SafeGetCharAt(i
+ 2);
147 if (state
== SCE_C_DEFAULT
) {
148 if (iswordstart(ch
) || (ch
== '@')) {
149 styler
.ColourTo(i
-1, state
);
150 state
= SCE_C_IDENTIFIER
;
151 } else if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
152 styler
.ColourTo(i
-1, state
);
153 state
= SCE_C_COMMENT
;
154 } else if (ch
== '(' && chNext
== '*'
155 && styler
.SafeGetCharAt(i
+ 2) != '$'
156 && styler
.SafeGetCharAt(i
+ 2) != '&') {
157 styler
.ColourTo(i
-1, state
);
158 state
= SCE_C_COMMENTDOC
;
159 } else if (ch
== '/' && chNext
== '/') {
160 styler
.ColourTo(i
-1, state
);
161 state
= SCE_C_COMMENTLINE
;
162 } else if (ch
== '\'') {
163 styler
.ColourTo(i
-1, state
);
164 state
= SCE_C_CHARACTER
;
165 } else if (ch
== '{' && (chNext
== '$' || chNext
=='&') && visibleChars
== 1) {
166 styler
.ColourTo(i
-1, state
);
167 state
= SCE_C_PREPROCESSOR
;
168 } else if (isoperator(ch
)) {
169 styler
.ColourTo(i
-1, state
);
170 styler
.ColourTo(i
, SCE_C_OPERATOR
);
173 } else if (state
== SCE_C_IDENTIFIER
) {
174 if (!iswordchar(ch
)) {
175 int lStateChange
= classifyWordPascal(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, bInClassDefinition
);
177 if(lStateChange
== 1) {
178 styler
.SetLineState(currentLine
, 1);
179 bInClassDefinition
= true;
180 } else if(lStateChange
== -1) {
181 styler
.SetLineState(currentLine
, 0);
182 bInClassDefinition
= false;
185 state
= SCE_C_DEFAULT
;
186 chNext
= styler
.SafeGetCharAt(i
+ 1);
187 if (ch
== '{' && chNext
!= '$' && chNext
!= '&') {
188 state
= SCE_C_COMMENT
;
189 } else if (ch
== '(' && chNext
== '*'
190 && styler
.SafeGetCharAt(i
+ 2) != '$'
191 && styler
.SafeGetCharAt(i
+ 2) != '&') {
192 styler
.ColourTo(i
-1, state
);
193 state
= SCE_C_COMMENTDOC
;
194 } else if (ch
== '/' && chNext
== '/') {
195 state
= SCE_C_COMMENTLINE
;
196 } else if (ch
== '\'') {
197 state
= SCE_C_CHARACTER
;
198 } else if (isoperator(ch
)) {
199 styler
.ColourTo(i
, SCE_C_OPERATOR
);
203 if (state
== SCE_C_PREPROCESSOR
) {
205 styler
.ColourTo(i
, state
);
206 state
= SCE_C_DEFAULT
;
208 if ((ch
== '\r' || ch
== '\n') && !(chPrev
== '\\' || chPrev
== '\r')) {
209 styler
.ColourTo(i
-1, state
);
210 state
= SCE_C_DEFAULT
;
213 } else if (state
== SCE_C_COMMENT
) {
215 styler
.ColourTo(i
, state
);
216 state
= SCE_C_DEFAULT
;
218 } else if (state
== SCE_C_COMMENTDOC
) {
219 if (ch
== ')' && chPrev
== '*') {
220 if (((i
> styler
.GetStartSegment() + 2) || (
221 (initStyle
== SCE_C_COMMENTDOC
) &&
222 (styler
.GetStartSegment() == static_cast<unsigned int>(startPos
))))) {
223 styler
.ColourTo(i
, state
);
224 state
= SCE_C_DEFAULT
;
227 } else if (state
== SCE_C_COMMENTLINE
) {
228 if (ch
== '\r' || ch
== '\n') {
229 styler
.ColourTo(i
-1, state
);
230 state
= SCE_C_DEFAULT
;
232 } else if (state
== SCE_C_CHARACTER
) {
233 if ((ch
== '\r' || ch
== '\n')) {
234 styler
.ColourTo(i
-1, SCE_C_STRINGEOL
);
235 state
= SCE_C_STRINGEOL
;
236 } else if (ch
== '\'') {
237 styler
.ColourTo(i
, state
);
238 state
= SCE_C_DEFAULT
;
244 styler
.ColourTo(lengthDoc
- 1, state
);
247 static void FoldPascalDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],
249 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
250 bool foldPreprocessor
= styler
.GetPropertyInt("fold.preprocessor") != 0;
251 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
252 unsigned int endPos
= startPos
+ length
;
253 int visibleChars
= 0;
254 int lineCurrent
= styler
.GetLine(startPos
);
255 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
256 int levelCurrent
= levelPrev
;
257 char chNext
= styler
[startPos
];
258 int styleNext
= styler
.StyleAt(startPos
);
259 int style
= initStyle
;
263 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
265 chNext
= styler
.SafeGetCharAt(i
+ 1);
266 int stylePrev
= style
;
268 styleNext
= styler
.StyleAt(i
+ 1);
269 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
271 if (stylePrev
== SCE_C_DEFAULT
&& style
== SCE_C_WORD
)
273 // Store last word start point.
277 if (stylePrev
== SCE_C_WORD
) {
278 if(iswordchar(ch
) && !iswordchar(chNext
)) {
280 getRange(lastStart
, i
, styler
, s
, sizeof(s
));
281 levelCurrent
+= classifyFoldPointPascal(s
);
285 if (foldComment
&& (style
== SCE_C_COMMENTLINE
)) {
286 if ((ch
== '/') && (chNext
== '/')) {
287 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
288 if (chNext2
== '{') {
290 } else if (chNext2
== '}') {
296 if (foldPreprocessor
&& (style
== SCE_C_PREPROCESSOR
)) {
297 if (ch
== '{' && chNext
== '$') {
298 unsigned int j
=i
+2; // skip {$
299 while ((j
<endPos
) && IsASpaceOrTab(styler
.SafeGetCharAt(j
))) {
302 if (styler
.Match(j
, "region") || styler
.Match(j
, "if")) {
304 } else if (styler
.Match(j
, "end")) {
310 if (foldComment
&& IsStreamCommentStyle(style
)) {
311 if (!IsStreamCommentStyle(stylePrev
)) {
313 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
314 // Comments don't end at end of line and the next character may be unstyled.
321 if (visibleChars
== 0 && foldCompact
)
322 lev
|= SC_FOLDLEVELWHITEFLAG
;
323 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
324 lev
|= SC_FOLDLEVELHEADERFLAG
;
325 if (lev
!= styler
.LevelAt(lineCurrent
)) {
326 styler
.SetLevel(lineCurrent
, lev
);
329 levelPrev
= levelCurrent
;
333 if (!isspacechar(ch
))
337 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
338 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
339 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
342 LexerModule
lmPascal(SCLEX_PASCAL
, ColourisePascalDoc
, "pascal", FoldPascalDoc
);