]>
Commit | Line | Data |
---|---|---|
591d01be RD |
1 | // Scintilla source code edit control |
2 | // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org> | |
3 | /* | |
4 | This is the Lexer for Gui4Cli, included in SciLexer.dll | |
5 | - by d. Keletsekis, 2/10/2003 | |
6 | ||
7 | To add to SciLexer.dll: | |
8 | 1. Add the values below to INCLUDE\Scintilla.iface | |
9 | 2. Run the include/HFacer.py script | |
10 | 3. Run the src/lexGen.py script | |
11 | ||
12 | val SCE_GC_DEFAULT=0 | |
13 | val SCE_GC_COMMENTLINE=1 | |
14 | val SCE_GC_COMMENTBLOCK=2 | |
15 | val SCE_GC_GLOBAL=3 | |
16 | val SCE_GC_EVENT=4 | |
17 | val SCE_GC_ATTRIBUTE=5 | |
18 | val SCE_GC_CONTROL=6 | |
19 | val SCE_GC_COMMAND=7 | |
20 | val SCE_GC_STRING=8 | |
21 | val SCE_GC_OPERATOR=9 | |
22 | */ | |
23 | ||
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
591d01be RD |
26 | #include <stdio.h> |
27 | #include <stdarg.h> | |
1dcf666d RD |
28 | #include <assert.h> |
29 | #include <ctype.h> | |
591d01be | 30 | |
1dcf666d RD |
31 | #include "ILexer.h" |
32 | #include "Scintilla.h" | |
33 | #include "SciLexer.h" | |
591d01be | 34 | |
1dcf666d RD |
35 | #include "WordList.h" |
36 | #include "LexAccessor.h" | |
591d01be RD |
37 | #include "Accessor.h" |
38 | #include "StyleContext.h" | |
1dcf666d RD |
39 | #include "CharacterSet.h" |
40 | #include "LexerModule.h" | |
591d01be | 41 | |
7e0c58e9 RD |
42 | #ifdef SCI_NAMESPACE |
43 | using namespace Scintilla; | |
44 | #endif | |
45 | ||
591d01be RD |
46 | #define debug Platform::DebugPrintf |
47 | ||
48 | static inline bool IsAWordChar(const int ch) { | |
49 | return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch =='\\'); | |
50 | } | |
51 | ||
52 | static inline bool IsAWordStart(const int ch) { | |
53 | return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); | |
54 | } | |
55 | ||
56 | inline bool isGCOperator(int ch) | |
57 | { if (isalnum(ch)) | |
58 | return false; | |
59 | // '.' left out as it is used to make up numbers | |
60 | if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || | |
61 | ch == '(' || ch == ')' || ch == '=' || ch == '%' || | |
62 | ch == '[' || ch == ']' || ch == '<' || ch == '>' || | |
63 | ch == ',' || ch == ';' || ch == ':') | |
64 | return true; | |
65 | return false; | |
66 | } | |
67 | ||
68 | #define isSpace(x) ((x)==' ' || (x)=='\t') | |
69 | #define isNL(x) ((x)=='\n' || (x)=='\r') | |
70 | #define isSpaceOrNL(x) (isSpace(x) || isNL(x)) | |
71 | #define BUFFSIZE 500 | |
72 | #define isFoldPoint(x) ((styler.LevelAt(x) & SC_FOLDLEVELNUMBERMASK) == 1024) | |
73 | ||
74 | static void colorFirstWord(WordList *keywordlists[], Accessor &styler, | |
75 | StyleContext *sc, char *buff, int length, int) | |
76 | { | |
77 | int c = 0; | |
78 | while (sc->More() && isSpaceOrNL(sc->ch)) | |
79 | { sc->Forward(); | |
80 | } | |
81 | styler.ColourTo(sc->currentPos - 1, sc->state); | |
82 | ||
83 | if (!IsAWordChar(sc->ch)) // comment, marker, etc.. | |
84 | return; | |
85 | ||
86 | while (sc->More() && !isSpaceOrNL(sc->ch) && (c < length-1) && !isGCOperator(sc->ch)) | |
87 | { buff[c] = static_cast<char>(sc->ch); | |
88 | ++c; sc->Forward(); | |
89 | } | |
90 | buff[c] = '\0'; | |
91 | char *p = buff; | |
92 | while (*p) // capitalize.. | |
93 | { if (islower(*p)) *p = static_cast<char>(toupper(*p)); | |
94 | ++p; | |
95 | } | |
96 | ||
97 | WordList &kGlobal = *keywordlists[0]; // keyword lists set by the user | |
98 | WordList &kEvent = *keywordlists[1]; | |
99 | WordList &kAttribute = *keywordlists[2]; | |
100 | WordList &kControl = *keywordlists[3]; | |
101 | WordList &kCommand = *keywordlists[4]; | |
102 | ||
103 | int state = 0; | |
104 | // int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK; | |
105 | // debug ("line = %d, level = %d", line, level); | |
106 | ||
107 | if (kGlobal.InList(buff)) state = SCE_GC_GLOBAL; | |
108 | else if (kAttribute.InList(buff)) state = SCE_GC_ATTRIBUTE; | |
109 | else if (kControl.InList(buff)) state = SCE_GC_CONTROL; | |
110 | else if (kCommand.InList(buff)) state = SCE_GC_COMMAND; | |
111 | else if (kEvent.InList(buff)) state = SCE_GC_EVENT; | |
112 | ||
113 | if (state) | |
114 | { sc->ChangeState(state); | |
115 | styler.ColourTo(sc->currentPos - 1, sc->state); | |
116 | sc->ChangeState(SCE_GC_DEFAULT); | |
117 | } | |
118 | else | |
119 | { sc->ChangeState(SCE_GC_DEFAULT); | |
120 | styler.ColourTo(sc->currentPos - 1, sc->state); | |
121 | } | |
122 | } | |
123 | ||
124 | // Main colorizing function called by Scintilla | |
125 | static void | |
126 | ColouriseGui4CliDoc(unsigned int startPos, int length, int initStyle, | |
127 | WordList *keywordlists[], Accessor &styler) | |
128 | { | |
129 | styler.StartAt(startPos); | |
130 | ||
131 | int quotestart = 0, oldstate, currentline = styler.GetLine(startPos); | |
132 | styler.StartSegment(startPos); | |
133 | bool noforward; | |
134 | char buff[BUFFSIZE+1]; // buffer for command name | |
135 | ||
136 | StyleContext sc(startPos, length, initStyle, styler); | |
137 | buff[0] = '\0'; // cbuff = 0; | |
138 | ||
139 | if (sc.state != SCE_GC_COMMENTBLOCK) // colorize 1st word.. | |
140 | colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); | |
141 | ||
142 | while (sc.More()) | |
143 | { noforward = 0; | |
144 | ||
145 | switch (sc.ch) | |
146 | { | |
147 | case '/': | |
148 | if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_STRING) | |
149 | break; | |
150 | if (sc.chNext == '/') // line comment | |
151 | { sc.SetState (SCE_GC_COMMENTLINE); | |
152 | sc.Forward(); | |
153 | styler.ColourTo(sc.currentPos, sc.state); | |
154 | } | |
155 | else if (sc.chNext == '*') // block comment | |
156 | { sc.SetState(SCE_GC_COMMENTBLOCK); | |
157 | sc.Forward(); | |
158 | styler.ColourTo(sc.currentPos, sc.state); | |
159 | } | |
160 | else | |
161 | styler.ColourTo(sc.currentPos, sc.state); | |
162 | break; | |
163 | ||
164 | case '*': // end of comment block, or operator.. | |
165 | if (sc.state == SCE_GC_STRING) | |
166 | break; | |
167 | if (sc.state == SCE_GC_COMMENTBLOCK && sc.chNext == '/') | |
168 | { sc.Forward(); | |
169 | styler.ColourTo(sc.currentPos, sc.state); | |
170 | sc.ChangeState (SCE_GC_DEFAULT); | |
171 | } | |
172 | else | |
173 | styler.ColourTo(sc.currentPos, sc.state); | |
174 | break; | |
175 | ||
176 | case '\'': case '\"': // strings.. | |
177 | if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_COMMENTLINE) | |
178 | break; | |
179 | if (sc.state == SCE_GC_STRING) | |
180 | { if (sc.ch == quotestart) // match same quote char.. | |
181 | { styler.ColourTo(sc.currentPos, sc.state); | |
182 | sc.ChangeState(SCE_GC_DEFAULT); | |
183 | quotestart = 0; | |
184 | } } | |
185 | else | |
186 | { styler.ColourTo(sc.currentPos - 1, sc.state); | |
187 | sc.ChangeState(SCE_GC_STRING); | |
188 | quotestart = sc.ch; | |
189 | } | |
190 | break; | |
191 | ||
192 | case ';': // end of commandline character | |
193 | if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && | |
194 | sc.state != SCE_GC_STRING) | |
195 | { | |
196 | styler.ColourTo(sc.currentPos - 1, sc.state); | |
197 | styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); | |
198 | sc.ChangeState(SCE_GC_DEFAULT); | |
199 | sc.Forward(); | |
200 | colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); | |
201 | noforward = 1; // don't move forward - already positioned at next char.. | |
202 | } | |
203 | break; | |
204 | ||
205 | case '+': case '-': case '=': case '!': // operators.. | |
206 | case '<': case '>': case '&': case '|': case '$': | |
207 | if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && | |
208 | sc.state != SCE_GC_STRING) | |
209 | { | |
210 | styler.ColourTo(sc.currentPos - 1, sc.state); | |
211 | styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); | |
212 | sc.ChangeState(SCE_GC_DEFAULT); | |
213 | } | |
214 | break; | |
215 | ||
216 | case '\\': // escape - same as operator, but also mark in strings.. | |
217 | if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE) | |
218 | { | |
219 | oldstate = sc.state; | |
220 | styler.ColourTo(sc.currentPos - 1, sc.state); | |
221 | sc.Forward(); // mark also the next char.. | |
222 | styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); | |
223 | sc.ChangeState(oldstate); | |
224 | } | |
225 | break; | |
226 | ||
227 | case '\n': case '\r': | |
228 | ++currentline; | |
229 | if (sc.state == SCE_GC_COMMENTLINE) | |
230 | { styler.ColourTo(sc.currentPos, sc.state); | |
231 | sc.ChangeState (SCE_GC_DEFAULT); | |
232 | } | |
233 | else if (sc.state != SCE_GC_COMMENTBLOCK) | |
234 | { colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); | |
235 | noforward = 1; // don't move forward - already positioned at next char.. | |
236 | } | |
237 | break; | |
238 | ||
239 | // case ' ': case '\t': | |
240 | // default : | |
241 | } | |
242 | ||
243 | if (!noforward) sc.Forward(); | |
244 | ||
245 | } | |
1e9bafca | 246 | sc.Complete(); |
591d01be RD |
247 | } |
248 | ||
249 | // Main folding function called by Scintilla - (based on props (.ini) files function) | |
250 | static void FoldGui4Cli(unsigned int startPos, int length, int, | |
251 | WordList *[], Accessor &styler) | |
252 | { | |
253 | bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; | |
254 | ||
255 | unsigned int endPos = startPos + length; | |
256 | int visibleChars = 0; | |
257 | int lineCurrent = styler.GetLine(startPos); | |
258 | ||
259 | char chNext = styler[startPos]; | |
260 | int styleNext = styler.StyleAt(startPos); | |
261 | bool headerPoint = false; | |
262 | ||
263 | for (unsigned int i = startPos; i < endPos; i++) | |
264 | { | |
265 | char ch = chNext; | |
266 | chNext = styler[i+1]; | |
267 | ||
268 | int style = styleNext; | |
269 | styleNext = styler.StyleAt(i + 1); | |
270 | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); | |
271 | ||
272 | if (style == SCE_GC_EVENT || style == SCE_GC_GLOBAL) | |
273 | { headerPoint = true; // fold at events and globals | |
274 | } | |
275 | ||
276 | if (atEOL) | |
277 | { int lev = SC_FOLDLEVELBASE+1; | |
278 | ||
279 | if (headerPoint) | |
280 | lev = SC_FOLDLEVELBASE; | |
281 | ||
282 | if (visibleChars == 0 && foldCompact) | |
283 | lev |= SC_FOLDLEVELWHITEFLAG; | |
284 | ||
285 | if (headerPoint) | |
286 | lev |= SC_FOLDLEVELHEADERFLAG; | |
287 | ||
288 | if (lev != styler.LevelAt(lineCurrent)) // set level, if not already correct | |
289 | { styler.SetLevel(lineCurrent, lev); | |
290 | } | |
291 | ||
292 | lineCurrent++; // re-initialize our flags | |
293 | visibleChars = 0; | |
294 | headerPoint = false; | |
295 | } | |
296 | ||
297 | if (!(isspacechar(ch))) // || (style == SCE_GC_COMMENTLINE) || (style != SCE_GC_COMMENTBLOCK))) | |
298 | visibleChars++; | |
299 | } | |
300 | ||
301 | int lev = headerPoint ? SC_FOLDLEVELBASE : SC_FOLDLEVELBASE+1; | |
302 | int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; | |
303 | styler.SetLevel(lineCurrent, lev | flagsNext); | |
304 | } | |
305 | ||
306 | // I have no idea what these are for.. probably accessible by some message. | |
307 | static const char * const gui4cliWordListDesc[] = { | |
308 | "Globals", "Events", "Attributes", "Control", "Commands", | |
309 | 0 | |
310 | }; | |
311 | ||
312 | // Declare language & pass our function pointers to Scintilla | |
313 | LexerModule lmGui4Cli(SCLEX_GUI4CLI, ColouriseGui4CliDoc, "gui4cli", FoldGui4Cli, gui4cliWordListDesc); | |
314 | ||
315 | #undef debug | |
316 |