]>
Commit | Line | Data |
---|---|---|
591d01be RD |
1 | // Scintilla source code edit control |
2 | // @file LexAU3.cxx | |
3 | // Lexer for AutoIt3 http://www.hiddensoft.com/autoit3 | |
1dcf666d | 4 | // by Jos van der Zande, jvdzande@yahoo.com |
591d01be RD |
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 | |
1dcf666d RD |
11 | // Fixed "#comments_start" -> "#comments-start" |
12 | // Fixed "#comments_end" -> "#comments-end" | |
591d01be RD |
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} | |
a33203cb | 15 | // April 26, 2004 - Fixed # pre-processor statement inside of comment block would invalidly change the color. |
591d01be RD |
16 | // Added logic for #include <xyz.au3> to treat the <> as string |
17 | // Added underscore to IsAOperator. | |
a33203cb RD |
18 | // May 17, 2004 - Changed the folding logic from indent to keyword folding. |
19 | // Added Folding logic for blocks of single-commentlines or commentblock. | |
20 | // triggered by: fold.comment=1 | |
21 | // Added Folding logic for preprocessor blocks triggered by fold.preprocessor=1 | |
22 | // Added Special for #region - #endregion syntax highlight and folding. | |
23 | // May 30, 2004 - Fixed issue with continuation lines on If statements. | |
24 | // June 5, 2004 - Added comma to Operators for better readability. | |
25 | // Added fold.compact support set with fold.compact=1 | |
26 | // Changed folding inside of #cs-#ce. Default is no keyword folding inside comment blocks when fold.comment=1 | |
27 | // it will now only happen when fold.comment=2. | |
1dcf666d | 28 | // Sep 5, 2004 - Added logic to handle colourizing words on the last line. |
1e9bafca | 29 | // Typed Characters now show as "default" till they match any table. |
1dcf666d | 30 | // Oct 10, 2004 - Added logic to show Comments in "Special" directives. |
1e9bafca RD |
31 | // Nov 1, 2004 - Added better testing for Numbers supporting x and e notation. |
32 | // Nov 28, 2004 - Added logic to handle continuation lines for syntax highlighting. | |
33 | // Jan 10, 2005 - Added Abbreviations Keyword used for expansion | |
34 | // Mar 24, 2005 - Updated Abbreviations Keywords to fix when followed by Operator. | |
35 | // Apr 18, 2005 - Updated #CE/#Comment-End logic to take a linecomment ";" into account | |
36 | // - Added folding support for With...EndWith | |
37 | // - Added support for a DOT in variable names | |
38 | // - Fixed Underscore in CommentBlock | |
39 | // May 23, 2005 - Fixed the SentKey lexing in case of a missing } | |
40 | // Aug 11, 2005 - Fixed possible bug with s_save length > 100. | |
41 | // Aug 23, 2005 - Added Switch/endswitch support to the folding logic. | |
b8193d80 RD |
42 | // Sep 27, 2005 - Fixed the SentKey lexing logic in case of multiple sentkeys. |
43 | // Mar 12, 2006 - Fixed issue with <> coloring as String in stead of Operator in rare occasions. | |
44 | // Apr 8, 2006 - Added support for AutoIt3 Standard UDF library (SCE_AU3_UDF) | |
7e0c58e9 RD |
45 | // Mar 9, 2007 - Fixed bug with + following a String getting the wrong Color. |
46 | // Jun 20, 2007 - Fixed Commentblock issue when LF's are used as EOL. | |
47 | // Jul 26, 2007 - Fixed #endregion undetected bug. | |
1e9bafca | 48 | // |
591d01be RD |
49 | // Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org> |
50 | // The License.txt file describes the conditions under which this software may be distributed. | |
51 | // Scintilla source code edit control | |
52 | ||
53 | #include <stdlib.h> | |
54 | #include <string.h> | |
591d01be RD |
55 | #include <stdio.h> |
56 | #include <stdarg.h> | |
1dcf666d RD |
57 | #include <assert.h> |
58 | #include <ctype.h> | |
591d01be | 59 | |
1dcf666d RD |
60 | #include "ILexer.h" |
61 | #include "Scintilla.h" | |
62 | #include "SciLexer.h" | |
591d01be | 63 | |
1dcf666d RD |
64 | #include "WordList.h" |
65 | #include "LexAccessor.h" | |
591d01be RD |
66 | #include "Accessor.h" |
67 | #include "StyleContext.h" | |
1dcf666d RD |
68 | #include "CharacterSet.h" |
69 | #include "LexerModule.h" | |
591d01be | 70 | |
7e0c58e9 RD |
71 | #ifdef SCI_NAMESPACE |
72 | using namespace Scintilla; | |
73 | #endif | |
74 | ||
591d01be RD |
75 | static inline bool IsTypeCharacter(const int ch) |
76 | { | |
77 | return ch == '$'; | |
78 | } | |
79 | static inline bool IsAWordChar(const int ch) | |
80 | { | |
a33203cb | 81 | return (ch < 0x80) && (isalnum(ch) || ch == '_'); |
591d01be RD |
82 | } |
83 | ||
84 | static inline bool IsAWordStart(const int ch) | |
85 | { | |
1e9bafca | 86 | return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '$' || ch == '.'); |
591d01be RD |
87 | } |
88 | ||
89 | static inline bool IsAOperator(char ch) { | |
90 | if (isascii(ch) && isalnum(ch)) | |
91 | return false; | |
92 | if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || | |
93 | ch == '&' || ch == '^' || ch == '=' || ch == '<' || ch == '>' || | |
a33203cb | 94 | ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == ',' ) |
591d01be RD |
95 | return true; |
96 | return false; | |
97 | } | |
98 | ||
99 | /////////////////////////////////////////////////////////////////////////////// | |
100 | // GetSendKey() filters the portion before and after a/multiple space(s) | |
101 | // and return the first portion to be looked-up in the table | |
102 | // also check if the second portion is valid... (up,down.on.off,toggle or a number) | |
103 | /////////////////////////////////////////////////////////////////////////////// | |
104 | ||
105 | static int GetSendKey(const char *szLine, char *szKey) | |
106 | { | |
107 | int nFlag = 0; | |
b8193d80 | 108 | int nStartFound = 0; |
591d01be RD |
109 | int nKeyPos = 0; |
110 | int nSpecPos= 0; | |
111 | int nSpecNum= 1; | |
112 | int nPos = 0; | |
113 | char cTemp; | |
114 | char szSpecial[100]; | |
115 | ||
116 | // split the portion of the sendkey in the part before and after the spaces | |
117 | while ( ( (cTemp = szLine[nPos]) != '\0')) | |
118 | { | |
b8193d80 RD |
119 | // skip leading Ctrl/Shift/Alt state |
120 | if (cTemp == '{') { | |
121 | nStartFound = 1; | |
591d01be | 122 | } |
b8193d80 RD |
123 | // |
124 | if (nStartFound == 1) { | |
125 | if ((cTemp == ' ') && (nFlag == 0) ) // get the stuff till first space | |
126 | { | |
127 | nFlag = 1; | |
128 | // Add } to the end of the first bit for table lookup later. | |
129 | szKey[nKeyPos++] = '}'; | |
130 | } | |
131 | else if (cTemp == ' ') | |
132 | { | |
1dcf666d | 133 | // skip other spaces |
b8193d80 RD |
134 | } |
135 | else if (nFlag == 0) | |
136 | { | |
137 | // save first portion into var till space or } is hit | |
138 | szKey[nKeyPos++] = cTemp; | |
139 | } | |
140 | else if ((nFlag == 1) && (cTemp != '}')) | |
141 | { | |
142 | // Save second portion into var... | |
143 | szSpecial[nSpecPos++] = cTemp; | |
144 | // check if Second portion is all numbers for repeat fuction | |
1dcf666d | 145 | if (isdigit(cTemp) == false) {nSpecNum = 0;} |
b8193d80 | 146 | } |
591d01be RD |
147 | } |
148 | nPos++; // skip to next char | |
149 | ||
150 | } // End While | |
151 | ||
152 | ||
153 | // Check if the second portion is either a number or one of these keywords | |
154 | szKey[nKeyPos] = '\0'; | |
155 | szSpecial[nSpecPos] = '\0'; | |
a33203cb | 156 | if (strcmp(szSpecial,"down")== 0 || strcmp(szSpecial,"up")== 0 || |
1dcf666d | 157 | strcmp(szSpecial,"on")== 0 || strcmp(szSpecial,"off")== 0 || |
a33203cb | 158 | strcmp(szSpecial,"toggle")== 0 || nSpecNum == 1 ) |
591d01be RD |
159 | { |
160 | nFlag = 0; | |
161 | } | |
162 | else | |
163 | { | |
164 | nFlag = 1; | |
165 | } | |
1dcf666d | 166 | return nFlag; // 1 is bad, 0 is good |
591d01be | 167 | |
1dcf666d | 168 | } // GetSendKey() |
591d01be | 169 | |
1e9bafca RD |
170 | // |
171 | // Routine to check the last "none comment" character on a line to see if its a continuation | |
1dcf666d | 172 | // |
1e9bafca RD |
173 | static bool IsContinuationLine(unsigned int szLine, Accessor &styler) |
174 | { | |
175 | int nsPos = styler.LineStart(szLine); | |
176 | int nePos = styler.LineStart(szLine+1) - 2; | |
177 | //int stylech = styler.StyleAt(nsPos); | |
178 | while (nsPos < nePos) | |
179 | { | |
180 | //stylech = styler.StyleAt(nePos); | |
181 | int stylech = styler.StyleAt(nsPos); | |
182 | if (!(stylech == SCE_AU3_COMMENT)) { | |
183 | char ch = styler.SafeGetCharAt(nePos); | |
184 | if (!isspacechar(ch)) { | |
185 | if (ch == '_') | |
186 | return true; | |
187 | else | |
188 | return false; | |
189 | } | |
190 | } | |
191 | nePos--; // skip to next char | |
192 | } // End While | |
193 | return false; | |
194 | } // IsContinuationLine() | |
195 | ||
196 | // | |
197 | // syntax highlighting logic | |
1dcf666d | 198 | static void ColouriseAU3Doc(unsigned int startPos, |
591d01be RD |
199 | int length, int initStyle, |
200 | WordList *keywordlists[], | |
201 | Accessor &styler) { | |
202 | ||
203 | WordList &keywords = *keywordlists[0]; | |
204 | WordList &keywords2 = *keywordlists[1]; | |
205 | WordList &keywords3 = *keywordlists[2]; | |
206 | WordList &keywords4 = *keywordlists[3]; | |
207 | WordList &keywords5 = *keywordlists[4]; | |
a33203cb | 208 | WordList &keywords6 = *keywordlists[5]; |
1e9bafca | 209 | WordList &keywords7 = *keywordlists[6]; |
b8193d80 | 210 | WordList &keywords8 = *keywordlists[7]; |
1e9bafca RD |
211 | // find the first previous line without continuation character at the end |
212 | int lineCurrent = styler.GetLine(startPos); | |
213 | int s_startPos = startPos; | |
214 | // When not inside a Block comment: find First line without _ | |
215 | if (!(initStyle==SCE_AU3_COMMENTBLOCK)) { | |
216 | while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) || | |
217 | (lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) { | |
218 | lineCurrent--; | |
219 | startPos = styler.LineStart(lineCurrent); // get start position | |
1dcf666d | 220 | initStyle = 0; // reset the start style to 0 |
1e9bafca RD |
221 | } |
222 | } | |
223 | // Set the new length to include it from the start and set the start position | |
224 | length = length + s_startPos - startPos; // correct the total length to process | |
591d01be | 225 | styler.StartAt(startPos); |
1dcf666d | 226 | |
591d01be RD |
227 | StyleContext sc(startPos, length, initStyle, styler); |
228 | char si; // string indicator "=1 '=2 | |
1e9bafca | 229 | char ni; // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 Enot=3 |
1dcf666d | 230 | char ci; // comment indicator 0=not linecomment(;) |
1e9bafca | 231 | char s_save[100]; |
1dcf666d | 232 | si=0; |
1e9bafca RD |
233 | ni=0; |
234 | ci=0; | |
591d01be RD |
235 | //$$$ |
236 | for (; sc.More(); sc.Forward()) { | |
237 | char s[100]; | |
238 | sc.GetCurrentLowered(s, sizeof(s)); | |
1e9bafca | 239 | // ********************************************** |
1dcf666d RD |
240 | // save the total current word for eof processing |
241 | if (IsAWordChar(sc.ch) || sc.ch == '}') | |
1e9bafca RD |
242 | { |
243 | strcpy(s_save,s); | |
1dcf666d | 244 | int tp = static_cast<int>(strlen(s_save)); |
1e9bafca RD |
245 | if (tp < 99) { |
246 | s_save[tp] = static_cast<char>(tolower(sc.ch)); | |
247 | s_save[tp+1] = '\0'; | |
248 | } | |
249 | } | |
250 | // ********************************************** | |
251 | // | |
591d01be RD |
252 | switch (sc.state) |
253 | { | |
254 | case SCE_AU3_COMMENTBLOCK: | |
255 | { | |
1e9bafca RD |
256 | //Reset at line end |
257 | if (sc.atLineEnd) { | |
258 | ci=0; | |
9e96e16f | 259 | if (strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0) { |
1dcf666d | 260 | if (sc.atLineEnd) |
7e0c58e9 | 261 | sc.SetState(SCE_AU3_DEFAULT); |
1dcf666d | 262 | else |
7e0c58e9 | 263 | sc.SetState(SCE_AU3_COMMENTBLOCK); |
9e96e16f | 264 | } |
7e0c58e9 | 265 | break; |
1e9bafca RD |
266 | } |
267 | //skip rest of line when a ; is encountered | |
268 | if (sc.chPrev == ';') { | |
269 | ci=2; | |
270 | sc.SetState(SCE_AU3_COMMENTBLOCK); | |
271 | } | |
272 | // skip rest of the line | |
1dcf666d | 273 | if (ci==2) |
1e9bafca | 274 | break; |
1dcf666d | 275 | // check when first character is detected on the line |
1e9bafca RD |
276 | if (ci==0) { |
277 | if (IsAWordStart(static_cast<char>(sc.ch)) || IsAOperator(static_cast<char>(sc.ch))) { | |
278 | ci=1; | |
279 | sc.SetState(SCE_AU3_COMMENTBLOCK); | |
280 | } | |
281 | break; | |
282 | } | |
283 | if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && strcmp(s, "#comments") == 0))) { | |
7e0c58e9 RD |
284 | if ((strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0)) |
285 | sc.SetState(SCE_AU3_COMMENT); // set to comment line for the rest of the line | |
591d01be | 286 | else |
1e9bafca | 287 | ci=2; // line doesn't begin with #CE so skip the rest of the line |
591d01be | 288 | } |
7e0c58e9 | 289 | break; |
591d01be RD |
290 | } |
291 | case SCE_AU3_COMMENT: | |
292 | { | |
293 | if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);} | |
294 | break; | |
295 | } | |
296 | case SCE_AU3_OPERATOR: | |
297 | { | |
1dcf666d | 298 | // check if its a COMobject |
1e9bafca RD |
299 | if (sc.chPrev == '.' && IsAWordChar(sc.ch)) { |
300 | sc.SetState(SCE_AU3_COMOBJ); | |
1dcf666d | 301 | } |
1e9bafca RD |
302 | else { |
303 | sc.SetState(SCE_AU3_DEFAULT); | |
304 | } | |
591d01be RD |
305 | break; |
306 | } | |
a33203cb RD |
307 | case SCE_AU3_SPECIAL: |
308 | { | |
1e9bafca RD |
309 | if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);} |
310 | if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);} | |
a33203cb RD |
311 | break; |
312 | } | |
591d01be RD |
313 | case SCE_AU3_KEYWORD: |
314 | { | |
a33203cb | 315 | if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && (strcmp(s, "#comments") == 0 || strcmp(s, "#include") == 0)))) |
591d01be RD |
316 | { |
317 | if (!IsTypeCharacter(sc.ch)) | |
318 | { | |
a33203cb | 319 | if (strcmp(s, "#cs")== 0 || strcmp(s, "#comments-start")== 0 ) |
591d01be RD |
320 | { |
321 | sc.ChangeState(SCE_AU3_COMMENTBLOCK); | |
322 | sc.SetState(SCE_AU3_COMMENTBLOCK); | |
7e0c58e9 | 323 | break; |
591d01be RD |
324 | } |
325 | else if (keywords.InList(s)) { | |
326 | sc.ChangeState(SCE_AU3_KEYWORD); | |
327 | sc.SetState(SCE_AU3_DEFAULT); | |
328 | } | |
329 | else if (keywords2.InList(s)) { | |
330 | sc.ChangeState(SCE_AU3_FUNCTION); | |
331 | sc.SetState(SCE_AU3_DEFAULT); | |
332 | } | |
333 | else if (keywords3.InList(s)) { | |
334 | sc.ChangeState(SCE_AU3_MACRO); | |
335 | sc.SetState(SCE_AU3_DEFAULT); | |
336 | } | |
337 | else if (keywords5.InList(s)) { | |
338 | sc.ChangeState(SCE_AU3_PREPROCESSOR); | |
339 | sc.SetState(SCE_AU3_DEFAULT); | |
a33203cb | 340 | if (strcmp(s, "#include")== 0) |
591d01be RD |
341 | { |
342 | si = 3; // use to determine string start for #inlude <> | |
343 | } | |
344 | } | |
a33203cb RD |
345 | else if (keywords6.InList(s)) { |
346 | sc.ChangeState(SCE_AU3_SPECIAL); | |
347 | sc.SetState(SCE_AU3_SPECIAL); | |
348 | } | |
1e9bafca RD |
349 | else if ((keywords7.InList(s)) && (!IsAOperator(static_cast<char>(sc.ch)))) { |
350 | sc.ChangeState(SCE_AU3_EXPAND); | |
351 | sc.SetState(SCE_AU3_DEFAULT); | |
352 | } | |
b8193d80 RD |
353 | else if (keywords8.InList(s)) { |
354 | sc.ChangeState(SCE_AU3_UDF); | |
355 | sc.SetState(SCE_AU3_DEFAULT); | |
356 | } | |
a33203cb RD |
357 | else if (strcmp(s, "_") == 0) { |
358 | sc.ChangeState(SCE_AU3_OPERATOR); | |
359 | sc.SetState(SCE_AU3_DEFAULT); | |
360 | } | |
591d01be RD |
361 | else if (!IsAWordChar(sc.ch)) { |
362 | sc.ChangeState(SCE_AU3_DEFAULT); | |
363 | sc.SetState(SCE_AU3_DEFAULT); | |
364 | } | |
365 | } | |
1dcf666d | 366 | } |
1e9bafca RD |
367 | if (sc.atLineEnd) { |
368 | sc.SetState(SCE_AU3_DEFAULT);} | |
591d01be RD |
369 | break; |
370 | } | |
1e9bafca | 371 | case SCE_AU3_NUMBER: |
591d01be | 372 | { |
1e9bafca RD |
373 | // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 E-not=3 |
374 | // | |
375 | // test for Hex notation | |
376 | if (strcmp(s, "0") == 0 && (sc.ch == 'x' || sc.ch == 'X') && ni == 0) | |
377 | { | |
378 | ni = 2; | |
379 | break; | |
380 | } | |
381 | // test for E notation | |
382 | if (IsADigit(sc.chPrev) && (sc.ch == 'e' || sc.ch == 'E') && ni <= 1) | |
383 | { | |
384 | ni = 3; | |
385 | break; | |
386 | } | |
387 | // Allow Hex characters inside hex numeric strings | |
388 | if ((ni == 2) && | |
389 | (sc.ch == 'a' || sc.ch == 'b' || sc.ch == 'c' || sc.ch == 'd' || sc.ch == 'e' || sc.ch == 'f' || | |
390 | sc.ch == 'A' || sc.ch == 'B' || sc.ch == 'C' || sc.ch == 'D' || sc.ch == 'E' || sc.ch == 'F' )) | |
391 | { | |
392 | break; | |
393 | } | |
394 | // test for 1 dec point only | |
395 | if (sc.ch == '.') | |
396 | { | |
397 | if (ni==0) | |
398 | { | |
399 | ni=1; | |
400 | } | |
401 | else | |
402 | { | |
403 | ni=9; | |
404 | } | |
405 | break; | |
406 | } | |
407 | // end of numeric string ? | |
408 | if (!(IsADigit(sc.ch))) | |
409 | { | |
410 | if (ni==9) | |
411 | { | |
412 | sc.ChangeState(SCE_AU3_DEFAULT); | |
413 | } | |
414 | sc.SetState(SCE_AU3_DEFAULT); | |
415 | } | |
416 | break; | |
417 | } | |
418 | case SCE_AU3_VARIABLE: | |
419 | { | |
420 | // Check if its a COMObject | |
421 | if (sc.ch == '.' && !IsADigit(sc.chNext)) { | |
422 | sc.SetState(SCE_AU3_OPERATOR); | |
423 | } | |
424 | else if (!IsAWordChar(sc.ch)) { | |
425 | sc.SetState(SCE_AU3_DEFAULT); | |
426 | } | |
427 | break; | |
591d01be | 428 | } |
1e9bafca RD |
429 | case SCE_AU3_COMOBJ: |
430 | { | |
431 | if (!(IsAWordChar(sc.ch))) { | |
432 | sc.SetState(SCE_AU3_DEFAULT); | |
433 | } | |
434 | break; | |
591d01be RD |
435 | } |
436 | case SCE_AU3_STRING: | |
437 | { | |
438 | // check for " to end a double qouted string or | |
1dcf666d | 439 | // check for ' to end a single qouted string |
591d01be RD |
440 | if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'') || (si == 3 && sc.ch == '>')) |
441 | { | |
442 | sc.ForwardSetState(SCE_AU3_DEFAULT); | |
b8193d80 | 443 | si=0; |
7e0c58e9 | 444 | break; |
591d01be | 445 | } |
1e9bafca RD |
446 | if (sc.atLineEnd) |
447 | { | |
b8193d80 | 448 | si=0; |
1e9bafca RD |
449 | // at line end and not found a continuation char then reset to default |
450 | int lineCurrent = styler.GetLine(sc.currentPos); | |
1dcf666d | 451 | if (!IsContinuationLine(lineCurrent,styler)) |
1e9bafca RD |
452 | { |
453 | sc.SetState(SCE_AU3_DEFAULT); | |
7e0c58e9 | 454 | break; |
1e9bafca RD |
455 | } |
456 | } | |
591d01be | 457 | // find Sendkeys in a STRING |
b8193d80 RD |
458 | if (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ) { |
459 | sc.SetState(SCE_AU3_SENT);} | |
591d01be RD |
460 | break; |
461 | } | |
1dcf666d | 462 | |
591d01be RD |
463 | case SCE_AU3_SENT: |
464 | { | |
1dcf666d RD |
465 | // Send key string ended |
466 | if (sc.chPrev == '}' && sc.ch != '}') | |
591d01be RD |
467 | { |
468 | // set color to SENDKEY when valid sendkey .. else set back to regular string | |
469 | char sk[100]; | |
470 | // split {111 222} and return {111} and check if 222 is valid. | |
471 | // if return code = 1 then invalid 222 so must be string | |
1dcf666d | 472 | if (GetSendKey(s,sk)) |
591d01be RD |
473 | { |
474 | sc.ChangeState(SCE_AU3_STRING); | |
475 | } | |
476 | // if single char between {?} then its ok as sendkey for a single character | |
1dcf666d | 477 | else if (strlen(sk) == 3) |
591d01be RD |
478 | { |
479 | sc.ChangeState(SCE_AU3_SENT); | |
480 | } | |
481 | // if sendkey {111} is in table then ok as sendkey | |
1dcf666d | 482 | else if (keywords4.InList(sk)) |
591d01be RD |
483 | { |
484 | sc.ChangeState(SCE_AU3_SENT); | |
485 | } | |
486 | else | |
487 | { | |
488 | sc.ChangeState(SCE_AU3_STRING); | |
489 | } | |
490 | sc.SetState(SCE_AU3_STRING); | |
491 | } | |
b8193d80 RD |
492 | else |
493 | { | |
494 | // check if the start is a valid SendKey start | |
495 | int nPos = 0; | |
496 | int nState = 1; | |
497 | char cTemp; | |
1dcf666d | 498 | while (!(nState == 2) && ((cTemp = s[nPos]) != '\0')) |
b8193d80 | 499 | { |
1dcf666d | 500 | if (cTemp == '{' && nState == 1) |
b8193d80 RD |
501 | { |
502 | nState = 2; | |
503 | } | |
504 | if (nState == 1 && !(cTemp == '+' || cTemp == '!' || cTemp == '^' || cTemp == '#' )) | |
505 | { | |
506 | nState = 0; | |
507 | } | |
508 | nPos++; | |
509 | } | |
510 | //Verify characters infront of { ... if not assume regular string | |
511 | if (nState == 1 && (!(sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ))) { | |
512 | sc.ChangeState(SCE_AU3_STRING); | |
513 | sc.SetState(SCE_AU3_STRING); | |
514 | } | |
1dcf666d | 515 | // If invalid character found then assume its a regular string |
b8193d80 RD |
516 | if (nState == 0) { |
517 | sc.ChangeState(SCE_AU3_STRING); | |
518 | sc.SetState(SCE_AU3_STRING); | |
519 | } | |
520 | } | |
591d01be | 521 | // check if next portion is again a sendkey |
1dcf666d | 522 | if (sc.atLineEnd) |
591d01be | 523 | { |
1e9bafca | 524 | sc.ChangeState(SCE_AU3_STRING); |
591d01be RD |
525 | sc.SetState(SCE_AU3_DEFAULT); |
526 | si = 0; // reset string indicator | |
527 | } | |
b8193d80 RD |
528 | //* check in next characters following a sentkey are again a sent key |
529 | // Need this test incase of 2 sentkeys like {F1}{ENTER} but not detect {{} | |
530 | if (sc.state == SCE_AU3_STRING && (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' )) { | |
531 | sc.SetState(SCE_AU3_SENT);} | |
591d01be | 532 | // check to see if the string ended... |
b8193d80 | 533 | // Sendkey string isn't complete but the string ended.... |
591d01be RD |
534 | if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'')) |
535 | { | |
536 | sc.ChangeState(SCE_AU3_STRING); | |
537 | sc.ForwardSetState(SCE_AU3_DEFAULT); | |
538 | } | |
539 | break; | |
540 | } | |
541 | } //switch (sc.state) | |
542 | ||
543 | // Determine if a new state should be entered: | |
544 | ||
545 | if (sc.state == SCE_AU3_DEFAULT) | |
546 | { | |
547 | if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);} | |
548 | else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);} | |
549 | else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);} | |
1e9bafca | 550 | else if (sc.ch == '.' && !IsADigit(sc.chNext)) {sc.SetState(SCE_AU3_OPERATOR);} |
591d01be | 551 | else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);} |
b8193d80 | 552 | //else if (sc.ch == '_') {sc.SetState(SCE_AU3_KEYWORD);} |
1dcf666d | 553 | else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include |
591d01be RD |
554 | else if (sc.ch == '\"') { |
555 | sc.SetState(SCE_AU3_STRING); | |
556 | si = 1; } | |
557 | else if (sc.ch == '\'') { | |
558 | sc.SetState(SCE_AU3_STRING); | |
559 | si = 2; } | |
1dcf666d | 560 | else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) |
1e9bafca RD |
561 | { |
562 | sc.SetState(SCE_AU3_NUMBER); | |
563 | ni = 0; | |
564 | } | |
591d01be | 565 | else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);} |
a33203cb | 566 | else if (IsAOperator(static_cast<char>(sc.ch))) {sc.SetState(SCE_AU3_OPERATOR);} |
591d01be RD |
567 | else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);} |
568 | } | |
569 | } //for (; sc.More(); sc.Forward()) | |
1e9bafca RD |
570 | |
571 | //************************************* | |
1dcf666d | 572 | // Colourize the last word correctly |
1e9bafca RD |
573 | //************************************* |
574 | if (sc.state == SCE_AU3_KEYWORD) | |
575 | { | |
576 | if (strcmp(s_save, "#cs")== 0 || strcmp(s_save, "#comments-start")== 0 ) | |
577 | { | |
578 | sc.ChangeState(SCE_AU3_COMMENTBLOCK); | |
579 | sc.SetState(SCE_AU3_COMMENTBLOCK); | |
580 | } | |
581 | else if (keywords.InList(s_save)) { | |
582 | sc.ChangeState(SCE_AU3_KEYWORD); | |
583 | sc.SetState(SCE_AU3_KEYWORD); | |
584 | } | |
585 | else if (keywords2.InList(s_save)) { | |
586 | sc.ChangeState(SCE_AU3_FUNCTION); | |
587 | sc.SetState(SCE_AU3_FUNCTION); | |
588 | } | |
589 | else if (keywords3.InList(s_save)) { | |
590 | sc.ChangeState(SCE_AU3_MACRO); | |
591 | sc.SetState(SCE_AU3_MACRO); | |
592 | } | |
593 | else if (keywords5.InList(s_save)) { | |
594 | sc.ChangeState(SCE_AU3_PREPROCESSOR); | |
595 | sc.SetState(SCE_AU3_PREPROCESSOR); | |
596 | } | |
597 | else if (keywords6.InList(s_save)) { | |
598 | sc.ChangeState(SCE_AU3_SPECIAL); | |
599 | sc.SetState(SCE_AU3_SPECIAL); | |
600 | } | |
601 | else if (keywords7.InList(s_save) && sc.atLineEnd) { | |
602 | sc.ChangeState(SCE_AU3_EXPAND); | |
603 | sc.SetState(SCE_AU3_EXPAND); | |
604 | } | |
b8193d80 RD |
605 | else if (keywords8.InList(s_save)) { |
606 | sc.ChangeState(SCE_AU3_UDF); | |
607 | sc.SetState(SCE_AU3_UDF); | |
608 | } | |
1e9bafca RD |
609 | else { |
610 | sc.ChangeState(SCE_AU3_DEFAULT); | |
611 | sc.SetState(SCE_AU3_DEFAULT); | |
612 | } | |
613 | } | |
614 | if (sc.state == SCE_AU3_SENT) | |
615 | { | |
1dcf666d RD |
616 | // Send key string ended |
617 | if (sc.chPrev == '}' && sc.ch != '}') | |
1e9bafca RD |
618 | { |
619 | // set color to SENDKEY when valid sendkey .. else set back to regular string | |
620 | char sk[100]; | |
621 | // split {111 222} and return {111} and check if 222 is valid. | |
622 | // if return code = 1 then invalid 222 so must be string | |
1dcf666d | 623 | if (GetSendKey(s_save,sk)) |
1e9bafca RD |
624 | { |
625 | sc.ChangeState(SCE_AU3_STRING); | |
626 | } | |
627 | // if single char between {?} then its ok as sendkey for a single character | |
1dcf666d | 628 | else if (strlen(sk) == 3) |
1e9bafca RD |
629 | { |
630 | sc.ChangeState(SCE_AU3_SENT); | |
631 | } | |
632 | // if sendkey {111} is in table then ok as sendkey | |
1dcf666d | 633 | else if (keywords4.InList(sk)) |
1e9bafca RD |
634 | { |
635 | sc.ChangeState(SCE_AU3_SENT); | |
636 | } | |
637 | else | |
638 | { | |
639 | sc.ChangeState(SCE_AU3_STRING); | |
640 | } | |
641 | sc.SetState(SCE_AU3_STRING); | |
642 | } | |
643 | // check if next portion is again a sendkey | |
1dcf666d | 644 | if (sc.atLineEnd) |
1e9bafca RD |
645 | { |
646 | sc.ChangeState(SCE_AU3_STRING); | |
647 | sc.SetState(SCE_AU3_DEFAULT); | |
648 | } | |
649 | } | |
650 | //************************************* | |
651 | sc.Complete(); | |
591d01be RD |
652 | } |
653 | ||
654 | // | |
a33203cb RD |
655 | static bool IsStreamCommentStyle(int style) { |
656 | return style == SCE_AU3_COMMENT || style == SCE_AU3_COMMENTBLOCK; | |
657 | } | |
658 | ||
591d01be | 659 | // |
a33203cb | 660 | // Routine to find first none space on the current line and return its Style |
1dcf666d | 661 | // needed for comment lines not starting on pos 1 |
a33203cb | 662 | static int GetStyleFirstWord(unsigned int szLine, Accessor &styler) |
591d01be | 663 | { |
a33203cb RD |
664 | int nsPos = styler.LineStart(szLine); |
665 | int nePos = styler.LineStart(szLine+1) - 1; | |
666 | while (isspacechar(styler.SafeGetCharAt(nsPos)) && nsPos < nePos) | |
667 | { | |
668 | nsPos++; // skip to next char | |
669 | ||
670 | } // End While | |
671 | return styler.StyleAt(nsPos); | |
591d01be | 672 | |
a33203cb RD |
673 | } // GetStyleFirstWord() |
674 | ||
a33203cb RD |
675 | |
676 | // | |
677 | static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) | |
678 | { | |
679 | int endPos = startPos + length; | |
680 | // get settings from the config files for folding comments and preprocessor lines | |
681 | bool foldComment = styler.GetPropertyInt("fold.comment") != 0; | |
682 | bool foldInComment = styler.GetPropertyInt("fold.comment") == 2; | |
683 | bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; | |
684 | bool foldpreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; | |
591d01be RD |
685 | // Backtrack to previous line in case need to fix its fold status |
686 | int lineCurrent = styler.GetLine(startPos); | |
687 | if (startPos > 0) { | |
688 | if (lineCurrent > 0) { | |
689 | lineCurrent--; | |
690 | startPos = styler.LineStart(lineCurrent); | |
691 | } | |
692 | } | |
1dcf666d | 693 | // vars for style of previous/current/next lines |
a33203cb RD |
694 | int style = GetStyleFirstWord(lineCurrent,styler); |
695 | int stylePrev = 0; | |
696 | // find the first previous line without continuation character at the end | |
697 | while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) || | |
698 | (lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) { | |
699 | lineCurrent--; | |
700 | startPos = styler.LineStart(lineCurrent); | |
701 | } | |
702 | if (lineCurrent > 0) { | |
703 | stylePrev = GetStyleFirstWord(lineCurrent-1,styler); | |
704 | } | |
705 | // vars for getting first word to check for keywords | |
706 | bool FirstWordStart = false; | |
707 | bool FirstWordEnd = false; | |
7e0c58e9 | 708 | char szKeyword[11]=""; |
a33203cb RD |
709 | int szKeywordlen = 0; |
710 | char szThen[5]=""; | |
711 | int szThenlen = 0; | |
712 | bool ThenFoundLast = false; | |
713 | // var for indentlevel | |
714 | int levelCurrent = SC_FOLDLEVELBASE; | |
715 | if (lineCurrent > 0) | |
716 | levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; | |
717 | int levelNext = levelCurrent; | |
1dcf666d | 718 | // |
a33203cb RD |
719 | int visibleChars = 0; |
720 | char chNext = styler.SafeGetCharAt(startPos); | |
721 | char chPrev = ' '; | |
722 | // | |
591d01be RD |
723 | for (int i = startPos; i < endPos; i++) { |
724 | char ch = chNext; | |
725 | chNext = styler.SafeGetCharAt(i + 1); | |
a33203cb RD |
726 | if (IsAWordChar(ch)) { |
727 | visibleChars++; | |
728 | } | |
729 | // get the syle for the current character neede to check in comment | |
730 | int stylech = styler.StyleAt(i); | |
731 | // get first word for the line for indent check max 9 characters | |
732 | if (FirstWordStart && (!(FirstWordEnd))) { | |
733 | if (!IsAWordChar(ch)) { | |
734 | FirstWordEnd = true; | |
735 | szKeyword[szKeywordlen] = '\0'; | |
736 | } | |
737 | else { | |
738 | if (szKeywordlen < 10) { | |
739 | szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch)); | |
740 | } | |
741 | } | |
742 | } | |
1dcf666d | 743 | // start the capture of the first word |
a33203cb RD |
744 | if (!(FirstWordStart)) { |
745 | if (IsAWordChar(ch) || IsAWordStart(ch) || ch == ';') { | |
746 | FirstWordStart = true; | |
747 | szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch)); | |
748 | } | |
749 | } | |
750 | // only process this logic when not in comment section | |
751 | if (!(stylech == SCE_AU3_COMMENT)) { | |
752 | if (ThenFoundLast) { | |
753 | if (IsAWordChar(ch)) { | |
754 | ThenFoundLast = false; | |
1dcf666d | 755 | } |
a33203cb RD |
756 | } |
757 | // find out if the word "then" is the last on a "if" line | |
758 | if (FirstWordEnd && strcmp(szKeyword,"if") == 0) { | |
759 | if (szThenlen == 4) { | |
760 | szThen[0] = szThen[1]; | |
761 | szThen[1] = szThen[2]; | |
762 | szThen[2] = szThen[3]; | |
763 | szThen[3] = static_cast<char>(tolower(ch)); | |
764 | if (strcmp(szThen,"then") == 0 ) { | |
765 | ThenFoundLast = true; | |
766 | } | |
767 | } | |
768 | else { | |
769 | szThen[szThenlen++] = static_cast<char>(tolower(ch)); | |
770 | if (szThenlen == 5) { | |
771 | szThen[4] = '\0'; | |
591d01be RD |
772 | } |
773 | } | |
774 | } | |
a33203cb | 775 | } |
1dcf666d | 776 | // End of Line found so process the information |
a33203cb RD |
777 | if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) { |
778 | // ************************** | |
779 | // Folding logic for Keywords | |
780 | // ************************** | |
781 | // if a keyword is found on the current line and the line doesn't end with _ (continuation) | |
782 | // and we are not inside a commentblock. | |
1dcf666d | 783 | if (szKeywordlen > 0 && (!(chPrev == '_')) && |
a33203cb RD |
784 | ((!(IsStreamCommentStyle(style)) || foldInComment)) ) { |
785 | szKeyword[szKeywordlen] = '\0'; | |
786 | // only fold "if" last keyword is "then" (else its a one line if) | |
787 | if (strcmp(szKeyword,"if") == 0 && ThenFoundLast) { | |
788 | levelNext++; | |
789 | } | |
1dcf666d | 790 | // create new fold for these words |
a33203cb RD |
791 | if (strcmp(szKeyword,"do") == 0 || strcmp(szKeyword,"for") == 0 || |
792 | strcmp(szKeyword,"func") == 0 || strcmp(szKeyword,"while") == 0|| | |
1e9bafca | 793 | strcmp(szKeyword,"with") == 0 || strcmp(szKeyword,"#region") == 0 ) { |
a33203cb RD |
794 | levelNext++; |
795 | } | |
1e9bafca RD |
796 | // create double Fold for select&switch because Case will subtract one of the current level |
797 | if (strcmp(szKeyword,"select") == 0 || strcmp(szKeyword,"switch") == 0) { | |
a33203cb RD |
798 | levelNext++; |
799 | levelNext++; | |
800 | } | |
801 | // end the fold for these words before the current line | |
802 | if (strcmp(szKeyword,"endfunc") == 0 || strcmp(szKeyword,"endif") == 0 || | |
1dcf666d | 803 | strcmp(szKeyword,"next") == 0 || strcmp(szKeyword,"until") == 0 || |
1e9bafca | 804 | strcmp(szKeyword,"endwith") == 0 ||strcmp(szKeyword,"wend") == 0){ |
a33203cb RD |
805 | levelNext--; |
806 | levelCurrent--; | |
807 | } | |
1dcf666d | 808 | // end the fold for these words before the current line and Start new fold |
a33203cb RD |
809 | if (strcmp(szKeyword,"case") == 0 || strcmp(szKeyword,"else") == 0 || |
810 | strcmp(szKeyword,"elseif") == 0 ) { | |
811 | levelCurrent--; | |
812 | } | |
813 | // end the double fold for this word before the current line | |
1e9bafca | 814 | if (strcmp(szKeyword,"endselect") == 0 || strcmp(szKeyword,"endswitch") == 0 ) { |
a33203cb RD |
815 | levelNext--; |
816 | levelNext--; | |
817 | levelCurrent--; | |
818 | levelCurrent--; | |
819 | } | |
820 | // end the fold for these words on the current line | |
821 | if (strcmp(szKeyword,"#endregion") == 0 ) { | |
822 | levelNext--; | |
823 | } | |
824 | } | |
825 | // Preprocessor and Comment folding | |
826 | int styleNext = GetStyleFirstWord(lineCurrent + 1,styler); | |
827 | // ************************************* | |
828 | // Folding logic for preprocessor blocks | |
829 | // ************************************* | |
830 | // process preprosessor line | |
831 | if (foldpreprocessor && style == SCE_AU3_PREPROCESSOR) { | |
832 | if (!(stylePrev == SCE_AU3_PREPROCESSOR) && (styleNext == SCE_AU3_PREPROCESSOR)) { | |
833 | levelNext++; | |
834 | } | |
835 | // fold till the last line for normal comment lines | |
836 | else if (stylePrev == SCE_AU3_PREPROCESSOR && !(styleNext == SCE_AU3_PREPROCESSOR)) { | |
837 | levelNext--; | |
838 | } | |
839 | } | |
840 | // ********************************* | |
841 | // Folding logic for Comment blocks | |
842 | // ********************************* | |
843 | if (foldComment && IsStreamCommentStyle(style)) { | |
844 | // Start of a comment block | |
845 | if (!(stylePrev==style) && IsStreamCommentStyle(styleNext) && styleNext==style) { | |
846 | levelNext++; | |
1dcf666d | 847 | } |
a33203cb | 848 | // fold till the last line for normal comment lines |
1dcf666d | 849 | else if (IsStreamCommentStyle(stylePrev) |
a33203cb | 850 | && !(styleNext == SCE_AU3_COMMENT) |
1dcf666d | 851 | && stylePrev == SCE_AU3_COMMENT |
a33203cb RD |
852 | && style == SCE_AU3_COMMENT) { |
853 | levelNext--; | |
854 | } | |
855 | // fold till the one but last line for Blockcomment lines | |
1dcf666d | 856 | else if (IsStreamCommentStyle(stylePrev) |
a33203cb RD |
857 | && !(styleNext == SCE_AU3_COMMENTBLOCK) |
858 | && style == SCE_AU3_COMMENTBLOCK) { | |
859 | levelNext--; | |
860 | levelCurrent--; | |
861 | } | |
862 | } | |
863 | int levelUse = levelCurrent; | |
864 | int lev = levelUse | levelNext << 16; | |
865 | if (visibleChars == 0 && foldCompact) | |
866 | lev |= SC_FOLDLEVELWHITEFLAG; | |
867 | if (levelUse < levelNext) { | |
868 | lev |= SC_FOLDLEVELHEADERFLAG; | |
869 | } | |
870 | if (lev != styler.LevelAt(lineCurrent)) { | |
871 | styler.SetLevel(lineCurrent, lev); | |
872 | } | |
873 | // reset values for the next line | |
591d01be | 874 | lineCurrent++; |
a33203cb RD |
875 | stylePrev = style; |
876 | style = styleNext; | |
877 | levelCurrent = levelNext; | |
878 | visibleChars = 0; | |
879 | // if the last character is an Underscore then don't reset since the line continues on the next line. | |
880 | if (!(chPrev == '_')) { | |
881 | szKeywordlen = 0; | |
882 | szThenlen = 0; | |
883 | FirstWordStart = false; | |
884 | FirstWordEnd = false; | |
885 | ThenFoundLast = false; | |
886 | } | |
887 | } | |
888 | // save the last processed character | |
889 | if (!isspacechar(ch)) { | |
890 | chPrev = ch; | |
891 | visibleChars++; | |
591d01be RD |
892 | } |
893 | } | |
591d01be RD |
894 | } |
895 | ||
896 | ||
897 | // | |
898 | ||
899 | static const char * const AU3WordLists[] = { | |
900 | "#autoit keywords", | |
901 | "#autoit functions", | |
902 | "#autoit macros", | |
903 | "#autoit Sent keys", | |
904 | "#autoit Pre-processors", | |
a33203cb | 905 | "#autoit Special", |
1e9bafca | 906 | "#autoit Expand", |
b8193d80 | 907 | "#autoit UDF", |
591d01be RD |
908 | 0 |
909 | }; | |
910 | LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", FoldAU3Doc , AU3WordLists); |