1 // Scintilla source code edit control
\r
2 /** @file LexEiffel.cxx
\r
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
\r
6 // The License.txt file describes the conditions under which this software may be distributed.
\r
14 #include "Platform.h"
\r
16 #include "PropSet.h"
\r
17 #include "Accessor.h"
\r
18 #include "StyleContext.h"
\r
19 #include "KeyWords.h"
\r
20 #include "Scintilla.h"
\r
21 #include "SciLexer.h"
\r
23 #ifdef SCI_NAMESPACE
\r
24 using namespace Scintilla;
\r
27 static inline bool isEiffelOperator(unsigned int ch) {
\r
28 // '.' left out as it is used to make up numbers
\r
29 return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
\r
30 ch == '(' || ch == ')' || ch == '=' ||
\r
31 ch == '{' || ch == '}' || ch == '~' ||
\r
32 ch == '[' || ch == ']' || ch == ';' ||
\r
33 ch == '<' || ch == '>' || ch == ',' ||
\r
34 ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
\r
35 ch == '!' || ch == '@' || ch == '?';
\r
38 static inline bool IsAWordChar(unsigned int ch) {
\r
39 return (ch < 0x80) && (isalnum(ch) || ch == '_');
\r
42 static inline bool IsAWordStart(unsigned int ch) {
\r
43 return (ch < 0x80) && (isalnum(ch) || ch == '_');
\r
46 static void ColouriseEiffelDoc(unsigned int startPos,
\r
49 WordList *keywordlists[],
\r
52 WordList &keywords = *keywordlists[0];
\r
54 StyleContext sc(startPos, length, initStyle, styler);
\r
56 for (; sc.More(); sc.Forward()) {
\r
58 if (sc.state == SCE_EIFFEL_STRINGEOL) {
\r
59 if (sc.ch != '\r' && sc.ch != '\n') {
\r
60 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
62 } else if (sc.state == SCE_EIFFEL_OPERATOR) {
\r
63 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
64 } else if (sc.state == SCE_EIFFEL_WORD) {
\r
65 if (!IsAWordChar(sc.ch)) {
\r
67 sc.GetCurrentLowered(s, sizeof(s));
\r
68 if (!keywords.InList(s)) {
\r
69 sc.ChangeState(SCE_EIFFEL_IDENTIFIER);
\r
71 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
73 } else if (sc.state == SCE_EIFFEL_NUMBER) {
\r
74 if (!IsAWordChar(sc.ch)) {
\r
75 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
77 } else if (sc.state == SCE_EIFFEL_COMMENTLINE) {
\r
78 if (sc.ch == '\r' || sc.ch == '\n') {
\r
79 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
81 } else if (sc.state == SCE_EIFFEL_STRING) {
\r
84 } else if (sc.ch == '\"') {
\r
86 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
88 } else if (sc.state == SCE_EIFFEL_CHARACTER) {
\r
89 if (sc.ch == '\r' || sc.ch == '\n') {
\r
90 sc.SetState(SCE_EIFFEL_STRINGEOL);
\r
91 } else if (sc.ch == '%') {
\r
93 } else if (sc.ch == '\'') {
\r
95 sc.SetState(SCE_EIFFEL_DEFAULT);
\r
99 if (sc.state == SCE_EIFFEL_DEFAULT) {
\r
100 if (sc.ch == '-' && sc.chNext == '-') {
\r
101 sc.SetState(SCE_EIFFEL_COMMENTLINE);
\r
102 } else if (sc.ch == '\"') {
\r
103 sc.SetState(SCE_EIFFEL_STRING);
\r
104 } else if (sc.ch == '\'') {
\r
105 sc.SetState(SCE_EIFFEL_CHARACTER);
\r
106 } else if (IsADigit(sc.ch) || (sc.ch == '.')) {
\r
107 sc.SetState(SCE_EIFFEL_NUMBER);
\r
108 } else if (IsAWordStart(sc.ch)) {
\r
109 sc.SetState(SCE_EIFFEL_WORD);
\r
110 } else if (isEiffelOperator(sc.ch)) {
\r
111 sc.SetState(SCE_EIFFEL_OPERATOR);
\r
118 static bool IsEiffelComment(Accessor &styler, int pos, int len) {
\r
119 return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
\r
122 static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
\r
123 WordList *[], Accessor &styler) {
\r
124 int lengthDoc = startPos + length;
\r
126 // Backtrack to previous line in case need to fix its fold status
\r
127 int lineCurrent = styler.GetLine(startPos);
\r
128 if (startPos > 0) {
\r
129 if (lineCurrent > 0) {
\r
131 startPos = styler.LineStart(lineCurrent);
\r
134 int spaceFlags = 0;
\r
135 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
\r
136 char chNext = styler[startPos];
\r
137 for (int i = startPos; i < lengthDoc; i++) {
\r
139 chNext = styler.SafeGetCharAt(i + 1);
\r
141 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
\r
142 int lev = indentCurrent;
\r
143 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
\r
144 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
\r
145 // Only non whitespace lines can be headers
\r
146 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
\r
147 lev |= SC_FOLDLEVELHEADERFLAG;
\r
148 } else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
\r
149 // Line after is blank so check the next - maybe should continue further?
\r
150 int spaceFlags2 = 0;
\r
151 int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
\r
152 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
\r
153 lev |= SC_FOLDLEVELHEADERFLAG;
\r
157 indentCurrent = indentNext;
\r
158 styler.SetLevel(lineCurrent, lev);
\r
164 static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
\r
165 Accessor &styler) {
\r
166 unsigned int lengthDoc = startPos + length;
\r
167 int visibleChars = 0;
\r
168 int lineCurrent = styler.GetLine(startPos);
\r
169 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
\r
170 int levelCurrent = levelPrev;
\r
171 char chNext = styler[startPos];
\r
173 int styleNext = styler.StyleAt(startPos);
\r
174 // lastDeferred should be determined by looking back to last keyword in case
\r
175 // the "deferred" is on a line before "class"
\r
176 bool lastDeferred = false;
\r
177 for (unsigned int i = startPos; i < lengthDoc; i++) {
\r
179 chNext = styler.SafeGetCharAt(i + 1);
\r
180 int style = styleNext;
\r
181 styleNext = styler.StyleAt(i + 1);
\r
182 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
\r
183 if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
\r
185 unsigned int j = 0;
\r
186 while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
\r
187 s[j] = styler[i + j];
\r
193 (strcmp(s, "check") == 0) ||
\r
194 (strcmp(s, "debug") == 0) ||
\r
195 (strcmp(s, "deferred") == 0) ||
\r
196 (strcmp(s, "do") == 0) ||
\r
197 (strcmp(s, "from") == 0) ||
\r
198 (strcmp(s, "if") == 0) ||
\r
199 (strcmp(s, "inspect") == 0) ||
\r
200 (strcmp(s, "once") == 0)
\r
203 if (!lastDeferred && (strcmp(s, "class") == 0))
\r
205 if (strcmp(s, "end") == 0)
\r
207 lastDeferred = strcmp(s, "deferred") == 0;
\r
211 int lev = levelPrev;
\r
212 if (visibleChars == 0)
\r
213 lev |= SC_FOLDLEVELWHITEFLAG;
\r
214 if ((levelCurrent > levelPrev) && (visibleChars > 0))
\r
215 lev |= SC_FOLDLEVELHEADERFLAG;
\r
216 if (lev != styler.LevelAt(lineCurrent)) {
\r
217 styler.SetLevel(lineCurrent, lev);
\r
220 levelPrev = levelCurrent;
\r
223 if (!isspacechar(ch))
\r
227 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
\r
228 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
\r
229 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
\r
232 static const char * const eiffelWordListDesc[] = {
\r
237 LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent, eiffelWordListDesc);
\r
238 LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords, eiffelWordListDesc);
\r