1 | // SciTE - Scintilla based Text Editor |
2 | // LexBullant.cxx - lexer for Bullant |
3 | |
4 | #include <stdlib.h> |
5 | #include <string.h> |
6 | #include <stdio.h> |
7 | #include <stdarg.h> |
8 | #include <assert.h> |
9 | #include <ctype.h> |
10 | |
11 | #include <string> |
12 | #include <string_view> |
13 | |
14 | #include "ILexer.h" |
15 | #include "Scintilla.h" |
16 | #include "SciLexer.h" |
17 | |
18 | #include "WordList.h" |
19 | #include "LexAccessor.h" |
20 | #include "Accessor.h" |
21 | #include "StyleContext.h" |
22 | #include "CharacterSet.h" |
23 | #include "LexerModule.h" |
24 | |
25 | using namespace Lexilla; |
26 | |
27 | static int classifyWordBullant(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler) { |
28 | char s[100]; |
29 | s[0] = '\0'; |
30 | for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) { |
31 | s[i] = static_cast<char>(tolower(styler[start + i])); |
32 | s[i + 1] = '\0'; |
33 | } |
34 | int lev= 0; |
35 | char chAttr = SCE_C_IDENTIFIER; |
36 | if (isdigit(s[0]) || (s[0] == '.')){ |
37 | chAttr = SCE_C_NUMBER; |
38 | } |
39 | else { |
40 | if (keywords.InList(s)) { |
41 | chAttr = SCE_C_WORD; |
42 | if (strcmp(s, "end" ) == 0) |
43 | lev = -1; |
44 | else if (strcmp(s, "method" ) == 0 || |
45 | strcmp(s, "case" ) == 0 || |
46 | strcmp(s, "class" ) == 0 || |
47 | strcmp(s, "debug" ) == 0 || |
48 | strcmp(s, "test" ) == 0 || |
49 | strcmp(s, "if" ) == 0 || |
50 | strcmp(s, "lock" ) == 0 || |
51 | strcmp(s, "transaction" ) == 0 || |
52 | strcmp(s, "trap" ) == 0 || |
53 | strcmp(s, "until" ) == 0 || |
54 | strcmp(s, "while" ) == 0) |
55 | lev = 1; |
56 | } |
57 | } |
58 | styler.ColourTo(end, chAttr); |
59 | return lev; |
60 | } |
61 | |
62 | static void ColouriseBullantDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[], |
63 | Accessor &styler) { |
64 | WordList &keywords = *keywordlists[0]; |
65 | |
66 | styler.StartAt(startPos); |
67 | |
68 | bool fold = styler.GetPropertyInt("fold" ) != 0; |
69 | Sci_Position lineCurrent = styler.GetLine(startPos); |
70 | int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; |
71 | int levelCurrent = levelPrev; |
72 | |
73 | int state = initStyle; |
74 | if (state == SCE_C_STRINGEOL) // Does not leak onto next line |
75 | state = SCE_C_DEFAULT; |
76 | char chPrev = ' '; |
77 | char chNext = styler[startPos]; |
78 | Sci_PositionU lengthDoc = startPos + length; |
79 | int visibleChars = 0; |
80 | styler.StartSegment(startPos); |
81 | int endFoundThisLine = 0; |
82 | for (Sci_PositionU i = startPos; i < lengthDoc; i++) { |
83 | char ch = chNext; |
84 | chNext = styler.SafeGetCharAt(i + 1); |
85 | |
86 | if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { |
87 | // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) |
88 | // Avoid triggering two times on Dos/Win |
89 | // End of line |
90 | endFoundThisLine = 0; |
91 | if (state == SCE_C_STRINGEOL) { |
92 | styler.ColourTo(i, state); |
93 | state = SCE_C_DEFAULT; |
94 | } |
95 | if (fold) { |
96 | int lev = levelPrev; |
97 | if (visibleChars == 0) |
98 | lev |= SC_FOLDLEVELWHITEFLAG; |
99 | if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
100 | lev |= SC_FOLDLEVELHEADERFLAG; |
101 | styler.SetLevel(lineCurrent, lev); |
102 | lineCurrent++; |
103 | levelPrev = levelCurrent; |
104 | } |
105 | visibleChars = 0; |
106 | |
107 | /* int indentBlock = GetLineIndentation(lineCurrent); |
108 | if (blockChange==1){ |
109 | lineCurrent++; |
110 | int pos=SetLineIndentation(lineCurrent, indentBlock + indentSize); |
111 | } else if (blockChange==-1) { |
112 | indentBlock -= indentSize; |
113 | if (indentBlock < 0) |
114 | indentBlock = 0; |
115 | SetLineIndentation(lineCurrent, indentBlock); |
116 | lineCurrent++; |
117 | } |
118 | blockChange=0; |
119 | */ } |
120 | if (!(IsASCII(ch) && isspace(ch))) |
121 | visibleChars++; |
122 | |
123 | if (styler.IsLeadByte(ch)) { |
124 | chNext = styler.SafeGetCharAt(i + 2); |
125 | chPrev = ' '; |
126 | i += 1; |
127 | continue; |
128 | } |
129 | |
130 | if (state == SCE_C_DEFAULT) { |
131 | if (iswordstart(ch)) { |
132 | styler.ColourTo(i-1, state); |
133 | state = SCE_C_IDENTIFIER; |
134 | } else if (ch == '@' && chNext == 'o') { |
135 | if ((styler.SafeGetCharAt(i+2) =='f') && (styler.SafeGetCharAt(i+3) == 'f')) { |
136 | styler.ColourTo(i-1, state); |
137 | state = SCE_C_COMMENT; |
138 | } |
139 | } else if (ch == '#') { |
140 | styler.ColourTo(i-1, state); |
141 | state = SCE_C_COMMENTLINE; |
142 | } else if (ch == '\"') { |
143 | styler.ColourTo(i-1, state); |
144 | state = SCE_C_STRING; |
145 | } else if (ch == '\'') { |
146 | styler.ColourTo(i-1, state); |
147 | state = SCE_C_CHARACTER; |
148 | } else if (isoperator(ch)) { |
149 | styler.ColourTo(i-1, state); |
150 | styler.ColourTo(i, SCE_C_OPERATOR); |
151 | } |
152 | } else if (state == SCE_C_IDENTIFIER) { |
153 | if (!iswordchar(ch)) { |
154 | int levelChange = classifyWordBullant(styler.GetStartSegment(), i - 1, keywords, styler); |
155 | state = SCE_C_DEFAULT; |
156 | chNext = styler.SafeGetCharAt(i + 1); |
157 | if (ch == '#') { |
158 | state = SCE_C_COMMENTLINE; |
159 | } else if (ch == '\"') { |
160 | state = SCE_C_STRING; |
161 | } else if (ch == '\'') { |
162 | state = SCE_C_CHARACTER; |
163 | } else if (isoperator(ch)) { |
164 | styler.ColourTo(i, SCE_C_OPERATOR); |
165 | } |
166 | if (endFoundThisLine == 0) |
167 | levelCurrent+=levelChange; |
168 | if (levelChange == -1) |
169 | endFoundThisLine=1; |
170 | } |
171 | } else if (state == SCE_C_COMMENT) { |
172 | if (ch == '@' && chNext == 'o') { |
173 | if (styler.SafeGetCharAt(i+2) == 'n') { |
174 | styler.ColourTo(i+2, state); |
175 | state = SCE_C_DEFAULT; |
176 | i+=2; |
177 | } |
178 | } |
179 | } else if (state == SCE_C_COMMENTLINE) { |
180 | if (ch == '\r' || ch == '\n') { |
181 | endFoundThisLine = 0; |
182 | styler.ColourTo(i-1, state); |
183 | state = SCE_C_DEFAULT; |
184 | } |
185 | } else if (state == SCE_C_STRING) { |
186 | if (ch == '\\') { |
187 | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { |
188 | i++; |
189 | ch = chNext; |
190 | chNext = styler.SafeGetCharAt(i + 1); |
191 | } |
192 | } else if (ch == '\"') { |
193 | styler.ColourTo(i, state); |
194 | state = SCE_C_DEFAULT; |
195 | } else if (chNext == '\r' || chNext == '\n') { |
196 | endFoundThisLine = 0; |
197 | styler.ColourTo(i-1, SCE_C_STRINGEOL); |
198 | state = SCE_C_STRINGEOL; |
199 | } |
200 | } else if (state == SCE_C_CHARACTER) { |
201 | if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { |
202 | endFoundThisLine = 0; |
203 | styler.ColourTo(i-1, SCE_C_STRINGEOL); |
204 | state = SCE_C_STRINGEOL; |
205 | } else if (ch == '\\') { |
206 | if (chNext == '\"' || chNext == '\'' || chNext == '\\') { |
207 | i++; |
208 | ch = chNext; |
209 | chNext = styler.SafeGetCharAt(i + 1); |
210 | } |
211 | } else if (ch == '\'') { |
212 | styler.ColourTo(i, state); |
213 | state = SCE_C_DEFAULT; |
214 | } |
215 | } |
216 | chPrev = ch; |
217 | } |
218 | styler.ColourTo(lengthDoc - 1, state); |
219 | |
220 | // Fill in the real level of the next line, keeping the current flags as they will be filled in later |
221 | if (fold) { |
222 | int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
223 | //styler.SetLevel(lineCurrent, levelCurrent | flagsNext); |
224 | styler.SetLevel(lineCurrent, levelPrev | flagsNext); |
225 | |
226 | } |
227 | } |
228 | |
229 | static const char * const bullantWordListDesc[] = { |
230 | "Keywords" , |
231 | 0 |
232 | }; |
233 | |
234 | LexerModule lmBullant(SCLEX_BULLANT, ColouriseBullantDoc, "bullant" , 0, bullantWordListDesc); |
235 | |