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