]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexAU3.cxx
8bc1f062eb473016f9a680ffe762a280c328de5a
1 // Scintilla source code edit control
3 // Lexer for AutoIt3 http://www.hiddensoft.com/autoit3
4 // by Jos van der Zande, jvdzande@yahoo.com
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
32 #include "StyleContext.h"
34 #include "Scintilla.h"
37 static bool IsAU3Comment(Accessor
&styler
, int pos
, int len
) {
38 return len
>0 && styler
[pos
]==';';
41 static inline bool IsTypeCharacter(const int ch
)
45 static inline bool IsAWordChar(const int ch
)
47 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '-');
50 static inline bool IsAWordStart(const int ch
)
52 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '@' || ch
== '#' || ch
== '$');
55 static inline bool IsAOperator(char ch
) {
56 if (isascii(ch
) && isalnum(ch
))
58 if (ch
== '+' || ch
== '-' || ch
== '*' || ch
== '/' ||
59 ch
== '&' || ch
== '^' || ch
== '=' || ch
== '<' || ch
== '>' ||
60 ch
== '(' || ch
== ')' || ch
== '[' || ch
== ']' || ch
== '_' )
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 ///////////////////////////////////////////////////////////////////////////////
71 static int GetSendKey(const char *szLine
, char *szKey
)
81 // split the portion of the sendkey in the part before and after the spaces
82 while ( ( (cTemp
= szLine
[nPos
]) != '\0'))
84 if ((cTemp
== ' ') && (nFlag
== 0) ) // get the stuff till first space
87 // Add } to the end of the first bit for table lookup later.
88 szKey
[nKeyPos
++] = '}';
90 else if (cTemp
== ' ')
96 // save first portion into var till space or } is hit
97 szKey
[nKeyPos
++] = cTemp
;
99 else if ((nFlag
== 1) && (cTemp
!= '}'))
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;}
106 nPos
++; // skip to next char
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 )
124 return nFlag
; // 1 is bad, 0 is good
128 static void ColouriseAU3Doc(unsigned int startPos
,
129 int length
, int initStyle
,
130 WordList
*keywordlists
[],
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
);
140 StyleContext
sc(startPos
, length
, initStyle
, styler
);
141 char si
; // string indicator "=1 '=2
144 for (; sc
.More(); sc
.Forward()) {
146 sc
.GetCurrentLowered(s
, sizeof(s
));
149 case SCE_AU3_COMMENTBLOCK
:
151 if (!IsAWordChar(sc
.ch
))
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
156 {sc
.SetState(SCE_AU3_COMMENTBLOCK
);}
160 case SCE_AU3_COMMENT
:
162 if (sc
.atLineEnd
) {sc
.SetState(SCE_AU3_DEFAULT
);}
165 case SCE_AU3_OPERATOR
:
167 sc
.SetState(SCE_AU3_DEFAULT
);
170 case SCE_AU3_KEYWORD
:
172 if (!IsAWordChar(sc
.ch
))
174 if (!IsTypeCharacter(sc
.ch
))
176 if (strcmp(s
, "#cs")==0 || strcmp(s
, "#comments-start")==0 )
178 sc
.ChangeState(SCE_AU3_COMMENTBLOCK
);
179 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
181 else if (keywords
.InList(s
)) {
182 sc
.ChangeState(SCE_AU3_KEYWORD
);
183 sc
.SetState(SCE_AU3_DEFAULT
);
185 else if (keywords2
.InList(s
)) {
186 sc
.ChangeState(SCE_AU3_FUNCTION
);
187 sc
.SetState(SCE_AU3_DEFAULT
);
189 else if (keywords3
.InList(s
)) {
190 sc
.ChangeState(SCE_AU3_MACRO
);
191 sc
.SetState(SCE_AU3_DEFAULT
);
193 else if (keywords5
.InList(s
)) {
194 sc
.ChangeState(SCE_AU3_PREPROCESSOR
);
195 sc
.SetState(SCE_AU3_DEFAULT
);
196 if (strcmp(s
, "#include")==0)
198 si
= 3; // use to determine string start for #inlude <>
201 else if (!IsAWordChar(sc
.ch
)) {
202 sc
.ChangeState(SCE_AU3_DEFAULT
);
203 sc
.SetState(SCE_AU3_DEFAULT
);
207 if (sc
.atLineEnd
) {sc
.SetState(SCE_AU3_DEFAULT
);}
212 if (!IsAWordChar(sc
.ch
)) {sc
.SetState(SCE_AU3_DEFAULT
);}
215 case SCE_AU3_VARIABLE
:
217 if (!IsAWordChar(sc
.ch
)) {sc
.SetState(SCE_AU3_DEFAULT
);}
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
== '>'))
226 sc
.ForwardSetState(SCE_AU3_DEFAULT
);
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
);}
240 // Send key string ended
241 if (sc
.chPrev
== '}' && sc
.ch
!= '}')
243 // set color to SENDKEY when valid sendkey .. else set back to regular string
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
))
249 sc
.ChangeState(SCE_AU3_STRING
);
251 // if single char between {?} then its ok as sendkey for a single character
252 else if (strlen(sk
) == 3)
254 sc
.ChangeState(SCE_AU3_SENT
);
256 // if sendkey {111} is in table then ok as sendkey
257 else if (keywords4
.InList(sk
))
259 sc
.ChangeState(SCE_AU3_SENT
);
263 sc
.ChangeState(SCE_AU3_STRING
);
265 sc
.SetState(SCE_AU3_STRING
);
267 // check if next portion is again a sendkey
270 sc
.SetState(SCE_AU3_DEFAULT
);
271 si
= 0; // reset string indicator
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
== '\''))
282 sc
.ChangeState(SCE_AU3_STRING
);
283 sc
.ForwardSetState(SCE_AU3_DEFAULT
);
287 } //switch (sc.state)
289 // Determine if a new state should be entered:
291 if (sc
.state
== SCE_AU3_DEFAULT
)
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
);
301 else if (sc
.ch
== '\'') {
302 sc
.SetState(SCE_AU3_STRING
);
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
);}
309 } //for (; sc.More(); sc.Forward())
315 static void FoldAU3Doc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
317 int endPos
= startPos
+ length
;
319 // Backtrack to previous line in case need to fix its fold status
320 int lineCurrent
= styler
.GetLine(startPos
);
322 if (lineCurrent
> 0) {
324 startPos
= styler
.LineStart(lineCurrent
);
328 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsAU3Comment
);
329 char chNext
= styler
[startPos
];
330 for (int i
= startPos
; i
< endPos
; i
++) {
332 chNext
= styler
.SafeGetCharAt(i
+ 1);
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?
344 int indentNext2
= styler
.IndentAmount(lineCurrent
+ 2, &spaceFlags2
, IsAU3Comment
);
345 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext2
& SC_FOLDLEVELNUMBERMASK
)) {
346 lev
|= SC_FOLDLEVELHEADERFLAG
;
350 indentCurrent
= indentNext
;
351 styler
.SetLevel(lineCurrent
, lev
);
361 static const char * const AU3WordLists
[] = {
366 "#autoit Pre-processors",
369 LexerModule
lmAU3(SCLEX_AU3
, ColouriseAU3Doc
, "au3", FoldAU3Doc
, AU3WordLists
);