]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexAU3.cxx
8bc1f062eb473016f9a680ffe762a280c328de5a
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexAU3.cxx
1 // Scintilla source code edit control
2 // @file LexAU3.cxx
3 // Lexer for AutoIt3 http://www.hiddensoft.com/autoit3
4 // by Jos van der Zande, jvdzande@yahoo.com
5 //
6 // Changes:
7 // March 28, 2004 - Added the standard Folding code
8 // April 21, 2004 - Added Preprosessor Table + Syntax Highlighting
9 // Fixed Number highlighting
10 // Changed default isoperator to IsAOperator to have a better match to AutoIt3
11 // Fixed "#comments_start" -> "#comments-start"
12 // Fixed "#comments_end" -> "#comments-end"
13 // Fixed Sendkeys in Strings when not terminated with }
14 // Added support for Sendkey strings that have second parameter e.g. {UP 5} or {a down}
15 // April 26, 2004 Fixed # pre-processor statement inside of comment block would invalidly change the color.
16 // Added logic for #include <xyz.au3> to treat the <> as string
17 // Added underscore to IsAOperator.
18 // Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
19 // The License.txt file describes the conditions under which this software may be distributed.
20 // Scintilla source code edit control
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27
28 #include "Platform.h"
29
30 #include "PropSet.h"
31 #include "Accessor.h"
32 #include "StyleContext.h"
33 #include "KeyWords.h"
34 #include "Scintilla.h"
35 #include "SciLexer.h"
36
37 static bool IsAU3Comment(Accessor &styler, int pos, int len) {
38 return len>0 && styler[pos]==';';
39 }
40
41 static inline bool IsTypeCharacter(const int ch)
42 {
43 return ch == '$';
44 }
45 static inline bool IsAWordChar(const int ch)
46 {
47 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '-');
48 }
49
50 static inline bool IsAWordStart(const int ch)
51 {
52 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '$');
53 }
54
55 static inline bool IsAOperator(char ch) {
56 if (isascii(ch) && isalnum(ch))
57 return false;
58 if (ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
59 ch == '&' || ch == '^' || ch == '=' || ch == '<' || ch == '>' ||
60 ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '_' )
61 return true;
62 return false;
63 }
64
65 ///////////////////////////////////////////////////////////////////////////////
66 // GetSendKey() filters the portion before and after a/multiple space(s)
67 // and return the first portion to be looked-up in the table
68 // also check if the second portion is valid... (up,down.on.off,toggle or a number)
69 ///////////////////////////////////////////////////////////////////////////////
70
71 static int GetSendKey(const char *szLine, char *szKey)
72 {
73 int nFlag = 0;
74 int nKeyPos = 0;
75 int nSpecPos= 0;
76 int nSpecNum= 1;
77 int nPos = 0;
78 char cTemp;
79 char szSpecial[100];
80
81 // split the portion of the sendkey in the part before and after the spaces
82 while ( ( (cTemp = szLine[nPos]) != '\0'))
83 {
84 if ((cTemp == ' ') && (nFlag == 0) ) // get the stuff till first space
85 {
86 nFlag = 1;
87 // Add } to the end of the first bit for table lookup later.
88 szKey[nKeyPos++] = '}';
89 }
90 else if (cTemp == ' ')
91 {
92 // skip other spaces
93 }
94 else if (nFlag == 0)
95 {
96 // save first portion into var till space or } is hit
97 szKey[nKeyPos++] = cTemp;
98 }
99 else if ((nFlag == 1) && (cTemp != '}'))
100 {
101 // Save second portion into var...
102 szSpecial[nSpecPos++] = cTemp;
103 // check if Second portion is all numbers for repeat fuction
104 if (isdigit(cTemp) == false) {nSpecNum = 0;}
105 }
106 nPos++; // skip to next char
107
108 } // End While
109
110
111 // Check if the second portion is either a number or one of these keywords
112 szKey[nKeyPos] = '\0';
113 szSpecial[nSpecPos] = '\0';
114 if (strcmp(szSpecial,"down")==0 || strcmp(szSpecial,"up")==0 ||
115 strcmp(szSpecial,"on")==0 || strcmp(szSpecial,"off")==0 ||
116 strcmp(szSpecial,"toggle")==0 || nSpecNum == 1 )
117 {
118 nFlag = 0;
119 }
120 else
121 {
122 nFlag = 1;
123 }
124 return nFlag; // 1 is bad, 0 is good
125
126 } // GetSendKey()
127
128 static void ColouriseAU3Doc(unsigned int startPos,
129 int length, int initStyle,
130 WordList *keywordlists[],
131 Accessor &styler) {
132
133 WordList &keywords = *keywordlists[0];
134 WordList &keywords2 = *keywordlists[1];
135 WordList &keywords3 = *keywordlists[2];
136 WordList &keywords4 = *keywordlists[3];
137 WordList &keywords5 = *keywordlists[4];
138 styler.StartAt(startPos);
139
140 StyleContext sc(startPos, length, initStyle, styler);
141 char si; // string indicator "=1 '=2
142 si=0;
143 //$$$
144 for (; sc.More(); sc.Forward()) {
145 char s[100];
146 sc.GetCurrentLowered(s, sizeof(s));
147 switch (sc.state)
148 {
149 case SCE_AU3_COMMENTBLOCK:
150 {
151 if (!IsAWordChar(sc.ch))
152 {
153 if ((strcmp(s, "#ce")==0 || strcmp(s, "#comments-end")==0))
154 {sc.SetState(SCE_AU3_COMMENT);} // set to comment line for the rest of the line
155 else
156 {sc.SetState(SCE_AU3_COMMENTBLOCK);}
157 }
158 break;
159 }
160 case SCE_AU3_COMMENT:
161 {
162 if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
163 break;
164 }
165 case SCE_AU3_OPERATOR:
166 {
167 sc.SetState(SCE_AU3_DEFAULT);
168 break;
169 }
170 case SCE_AU3_KEYWORD:
171 {
172 if (!IsAWordChar(sc.ch))
173 {
174 if (!IsTypeCharacter(sc.ch))
175 {
176 if (strcmp(s, "#cs")==0 || strcmp(s, "#comments-start")==0 )
177 {
178 sc.ChangeState(SCE_AU3_COMMENTBLOCK);
179 sc.SetState(SCE_AU3_COMMENTBLOCK);
180 }
181 else if (keywords.InList(s)) {
182 sc.ChangeState(SCE_AU3_KEYWORD);
183 sc.SetState(SCE_AU3_DEFAULT);
184 }
185 else if (keywords2.InList(s)) {
186 sc.ChangeState(SCE_AU3_FUNCTION);
187 sc.SetState(SCE_AU3_DEFAULT);
188 }
189 else if (keywords3.InList(s)) {
190 sc.ChangeState(SCE_AU3_MACRO);
191 sc.SetState(SCE_AU3_DEFAULT);
192 }
193 else if (keywords5.InList(s)) {
194 sc.ChangeState(SCE_AU3_PREPROCESSOR);
195 sc.SetState(SCE_AU3_DEFAULT);
196 if (strcmp(s, "#include")==0)
197 {
198 si = 3; // use to determine string start for #inlude <>
199 }
200 }
201 else if (!IsAWordChar(sc.ch)) {
202 sc.ChangeState(SCE_AU3_DEFAULT);
203 sc.SetState(SCE_AU3_DEFAULT);
204 }
205 }
206 }
207 if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
208 break;
209 }
210 case SCE_AU3_NUMBER:
211 {
212 if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
213 break;
214 }
215 case SCE_AU3_VARIABLE:
216 {
217 if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_AU3_DEFAULT);}
218 break;
219 }
220 case SCE_AU3_STRING:
221 {
222 // check for " to end a double qouted string or
223 // check for ' to end a single qouted string
224 if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'') || (si == 3 && sc.ch == '>'))
225 {
226 sc.ForwardSetState(SCE_AU3_DEFAULT);
227 }
228 if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
229 // find Sendkeys in a STRING
230 if (sc.ch == '{') {sc.SetState(SCE_AU3_SENT);}
231 if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
232 if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
233 if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
234 if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
235 break;
236 }
237
238 case SCE_AU3_SENT:
239 {
240 // Send key string ended
241 if (sc.chPrev == '}' && sc.ch != '}')
242 {
243 // set color to SENDKEY when valid sendkey .. else set back to regular string
244 char sk[100];
245 // split {111 222} and return {111} and check if 222 is valid.
246 // if return code = 1 then invalid 222 so must be string
247 if (GetSendKey(s,sk))
248 {
249 sc.ChangeState(SCE_AU3_STRING);
250 }
251 // if single char between {?} then its ok as sendkey for a single character
252 else if (strlen(sk) == 3)
253 {
254 sc.ChangeState(SCE_AU3_SENT);
255 }
256 // if sendkey {111} is in table then ok as sendkey
257 else if (keywords4.InList(sk))
258 {
259 sc.ChangeState(SCE_AU3_SENT);
260 }
261 else
262 {
263 sc.ChangeState(SCE_AU3_STRING);
264 }
265 sc.SetState(SCE_AU3_STRING);
266 }
267 // check if next portion is again a sendkey
268 if (sc.atLineEnd)
269 {
270 sc.SetState(SCE_AU3_DEFAULT);
271 si = 0; // reset string indicator
272 }
273 if (sc.ch == '{' && sc.chPrev != '{') {sc.SetState(SCE_AU3_SENT);}
274 if (sc.ch == '+' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
275 if (sc.ch == '!' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
276 if (sc.ch == '^' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
277 if (sc.ch == '#' && sc.chNext == '{') {sc.SetState(SCE_AU3_SENT);}
278 // check to see if the string ended...
279 // Sentkey string isn't complete but the string ended....
280 if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\''))
281 {
282 sc.ChangeState(SCE_AU3_STRING);
283 sc.ForwardSetState(SCE_AU3_DEFAULT);
284 }
285 break;
286 }
287 } //switch (sc.state)
288
289 // Determine if a new state should be entered:
290
291 if (sc.state == SCE_AU3_DEFAULT)
292 {
293 if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
294 else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);}
295 else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);}
296 else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);}
297 else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include
298 else if (sc.ch == '\"') {
299 sc.SetState(SCE_AU3_STRING);
300 si = 1; }
301 else if (sc.ch == '\'') {
302 sc.SetState(SCE_AU3_STRING);
303 si = 2; }
304 else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {sc.SetState(SCE_AU3_NUMBER);}
305 else if (IsAOperator(static_cast<char>(sc.ch))) {sc.SetState(SCE_AU3_OPERATOR);}
306 else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
307 else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
308 }
309 } //for (; sc.More(); sc.Forward())
310 sc.Complete();
311 }
312
313 //
314 //
315 static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
316 {
317 int endPos = startPos + length;
318
319 // Backtrack to previous line in case need to fix its fold status
320 int lineCurrent = styler.GetLine(startPos);
321 if (startPos > 0) {
322 if (lineCurrent > 0) {
323 lineCurrent--;
324 startPos = styler.LineStart(lineCurrent);
325 }
326 }
327 int spaceFlags = 0;
328 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsAU3Comment);
329 char chNext = styler[startPos];
330 for (int i = startPos; i < endPos; i++) {
331 char ch = chNext;
332 chNext = styler.SafeGetCharAt(i + 1);
333
334 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
335 int lev = indentCurrent;
336 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsAU3Comment);
337 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
338 // Only non whitespace lines can be headers
339 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
340 lev |= SC_FOLDLEVELHEADERFLAG;
341 } else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
342 // Line after is blank so check the next - maybe should continue further?
343 int spaceFlags2 = 0;
344 int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsAU3Comment);
345 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
346 lev |= SC_FOLDLEVELHEADERFLAG;
347 }
348 }
349 }
350 indentCurrent = indentNext;
351 styler.SetLevel(lineCurrent, lev);
352 lineCurrent++;
353 }
354 }
355
356 }
357
358
359 //
360
361 static const char * const AU3WordLists[] = {
362 "#autoit keywords",
363 "#autoit functions",
364 "#autoit macros",
365 "#autoit Sent keys",
366 "#autoit Pre-processors",
367 0
368 };
369 LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", FoldAU3Doc , AU3WordLists);