]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexAU3.cxx
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 // 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.
28 // Sep 5, 2004 - Added logic to handle colourizing words on the last line.
29 // Typed Characters now show as "default" till they match any table.
30 // Oct 10, 2004 - Added logic to show Comments in "Special" directives.
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.
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)
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.
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
61 #include "Scintilla.h"
65 #include "LexAccessor.h"
67 #include "StyleContext.h"
68 #include "CharacterSet.h"
69 #include "LexerModule.h"
72 using namespace Scintilla
;
75 static inline bool IsTypeCharacter(const int ch
)
79 static inline bool IsAWordChar(const int ch
)
81 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_');
84 static inline bool IsAWordStart(const int ch
)
86 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_' || ch
== '@' || ch
== '#' || ch
== '$' || ch
== '.');
89 static inline bool IsAOperator(char ch
) {
90 if (isascii(ch
) && isalnum(ch
))
92 if (ch
== '+' || ch
== '-' || ch
== '*' || ch
== '/' ||
93 ch
== '&' || ch
== '^' || ch
== '=' || ch
== '<' || ch
== '>' ||
94 ch
== '(' || ch
== ')' || ch
== '[' || ch
== ']' || ch
== ',' )
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 ///////////////////////////////////////////////////////////////////////////////
105 static int GetSendKey(const char *szLine
, char *szKey
)
116 // split the portion of the sendkey in the part before and after the spaces
117 while ( ( (cTemp
= szLine
[nPos
]) != '\0'))
119 // skip leading Ctrl/Shift/Alt state
124 if (nStartFound
== 1) {
125 if ((cTemp
== ' ') && (nFlag
== 0) ) // get the stuff till first space
128 // Add } to the end of the first bit for table lookup later.
129 szKey
[nKeyPos
++] = '}';
131 else if (cTemp
== ' ')
137 // save first portion into var till space or } is hit
138 szKey
[nKeyPos
++] = cTemp
;
140 else if ((nFlag
== 1) && (cTemp
!= '}'))
142 // Save second portion into var...
143 szSpecial
[nSpecPos
++] = cTemp
;
144 // check if Second portion is all numbers for repeat fuction
145 if (isdigit(cTemp
) == false) {nSpecNum
= 0;}
148 nPos
++; // skip to next char
153 // Check if the second portion is either a number or one of these keywords
154 szKey
[nKeyPos
] = '\0';
155 szSpecial
[nSpecPos
] = '\0';
156 if (strcmp(szSpecial
,"down")== 0 || strcmp(szSpecial
,"up")== 0 ||
157 strcmp(szSpecial
,"on")== 0 || strcmp(szSpecial
,"off")== 0 ||
158 strcmp(szSpecial
,"toggle")== 0 || nSpecNum
== 1 )
166 return nFlag
; // 1 is bad, 0 is good
171 // Routine to check the last "none comment" character on a line to see if its a continuation
173 static bool IsContinuationLine(unsigned int szLine
, Accessor
&styler
)
175 int nsPos
= styler
.LineStart(szLine
);
176 int nePos
= styler
.LineStart(szLine
+1) - 2;
177 //int stylech = styler.StyleAt(nsPos);
178 while (nsPos
< nePos
)
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
)) {
191 nePos
--; // skip to next char
194 } // IsContinuationLine()
197 // syntax highlighting logic
198 static void ColouriseAU3Doc(unsigned int startPos
,
199 int length
, int initStyle
,
200 WordList
*keywordlists
[],
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];
208 WordList
&keywords6
= *keywordlists
[5];
209 WordList
&keywords7
= *keywordlists
[6];
210 WordList
&keywords8
= *keywordlists
[7];
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
))) {
219 startPos
= styler
.LineStart(lineCurrent
); // get start position
220 initStyle
= 0; // reset the start style to 0
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
225 styler
.StartAt(startPos
);
227 StyleContext
sc(startPos
, length
, initStyle
, styler
);
228 char si
; // string indicator "=1 '=2
229 char ni
; // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 Enot=3
230 char ci
; // comment indicator 0=not linecomment(;)
236 for (; sc
.More(); sc
.Forward()) {
238 sc
.GetCurrentLowered(s
, sizeof(s
));
239 // **********************************************
240 // save the total current word for eof processing
241 if (IsAWordChar(sc
.ch
) || sc
.ch
== '}')
244 int tp
= static_cast<int>(strlen(s_save
));
246 s_save
[tp
] = static_cast<char>(tolower(sc
.ch
));
250 // **********************************************
254 case SCE_AU3_COMMENTBLOCK
:
259 if (strcmp(s
, "#ce")== 0 || strcmp(s
, "#comments-end")== 0) {
261 sc
.SetState(SCE_AU3_DEFAULT
);
263 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
267 //skip rest of line when a ; is encountered
268 if (sc
.chPrev
== ';') {
270 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
272 // skip rest of the line
275 // check when first character is detected on the line
277 if (IsAWordStart(static_cast<char>(sc
.ch
)) || IsAOperator(static_cast<char>(sc
.ch
))) {
279 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
283 if (!(IsAWordChar(sc
.ch
) || (sc
.ch
== '-' && strcmp(s
, "#comments") == 0))) {
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
287 ci
=2; // line doesn't begin with #CE so skip the rest of the line
291 case SCE_AU3_COMMENT
:
293 if (sc
.atLineEnd
) {sc
.SetState(SCE_AU3_DEFAULT
);}
296 case SCE_AU3_OPERATOR
:
298 // check if its a COMobject
299 if (sc
.chPrev
== '.' && IsAWordChar(sc
.ch
)) {
300 sc
.SetState(SCE_AU3_COMOBJ
);
303 sc
.SetState(SCE_AU3_DEFAULT
);
307 case SCE_AU3_SPECIAL
:
309 if (sc
.ch
== ';') {sc
.SetState(SCE_AU3_COMMENT
);}
310 if (sc
.atLineEnd
) {sc
.SetState(SCE_AU3_DEFAULT
);}
313 case SCE_AU3_KEYWORD
:
315 if (!(IsAWordChar(sc
.ch
) || (sc
.ch
== '-' && (strcmp(s
, "#comments") == 0 || strcmp(s
, "#include") == 0))))
317 if (!IsTypeCharacter(sc
.ch
))
319 if (strcmp(s
, "#cs")== 0 || strcmp(s
, "#comments-start")== 0 )
321 sc
.ChangeState(SCE_AU3_COMMENTBLOCK
);
322 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
325 else if (keywords
.InList(s
)) {
326 sc
.ChangeState(SCE_AU3_KEYWORD
);
327 sc
.SetState(SCE_AU3_DEFAULT
);
329 else if (keywords2
.InList(s
)) {
330 sc
.ChangeState(SCE_AU3_FUNCTION
);
331 sc
.SetState(SCE_AU3_DEFAULT
);
333 else if (keywords3
.InList(s
)) {
334 sc
.ChangeState(SCE_AU3_MACRO
);
335 sc
.SetState(SCE_AU3_DEFAULT
);
337 else if (keywords5
.InList(s
)) {
338 sc
.ChangeState(SCE_AU3_PREPROCESSOR
);
339 sc
.SetState(SCE_AU3_DEFAULT
);
340 if (strcmp(s
, "#include")== 0)
342 si
= 3; // use to determine string start for #inlude <>
345 else if (keywords6
.InList(s
)) {
346 sc
.ChangeState(SCE_AU3_SPECIAL
);
347 sc
.SetState(SCE_AU3_SPECIAL
);
349 else if ((keywords7
.InList(s
)) && (!IsAOperator(static_cast<char>(sc
.ch
)))) {
350 sc
.ChangeState(SCE_AU3_EXPAND
);
351 sc
.SetState(SCE_AU3_DEFAULT
);
353 else if (keywords8
.InList(s
)) {
354 sc
.ChangeState(SCE_AU3_UDF
);
355 sc
.SetState(SCE_AU3_DEFAULT
);
357 else if (strcmp(s
, "_") == 0) {
358 sc
.ChangeState(SCE_AU3_OPERATOR
);
359 sc
.SetState(SCE_AU3_DEFAULT
);
361 else if (!IsAWordChar(sc
.ch
)) {
362 sc
.ChangeState(SCE_AU3_DEFAULT
);
363 sc
.SetState(SCE_AU3_DEFAULT
);
368 sc
.SetState(SCE_AU3_DEFAULT
);}
373 // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 E-not=3
375 // test for Hex notation
376 if (strcmp(s
, "0") == 0 && (sc
.ch
== 'x' || sc
.ch
== 'X') && ni
== 0)
381 // test for E notation
382 if (IsADigit(sc
.chPrev
) && (sc
.ch
== 'e' || sc
.ch
== 'E') && ni
<= 1)
387 // Allow Hex characters inside hex numeric strings
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' ))
394 // test for 1 dec point only
407 // end of numeric string ?
408 if (!(IsADigit(sc
.ch
)))
412 sc
.ChangeState(SCE_AU3_DEFAULT
);
414 sc
.SetState(SCE_AU3_DEFAULT
);
418 case SCE_AU3_VARIABLE
:
420 // Check if its a COMObject
421 if (sc
.ch
== '.' && !IsADigit(sc
.chNext
)) {
422 sc
.SetState(SCE_AU3_OPERATOR
);
424 else if (!IsAWordChar(sc
.ch
)) {
425 sc
.SetState(SCE_AU3_DEFAULT
);
431 if (!(IsAWordChar(sc
.ch
))) {
432 sc
.SetState(SCE_AU3_DEFAULT
);
438 // check for " to end a double qouted string or
439 // check for ' to end a single qouted string
440 if ((si
== 1 && sc
.ch
== '\"') || (si
== 2 && sc
.ch
== '\'') || (si
== 3 && sc
.ch
== '>'))
442 sc
.ForwardSetState(SCE_AU3_DEFAULT
);
449 // at line end and not found a continuation char then reset to default
450 int lineCurrent
= styler
.GetLine(sc
.currentPos
);
451 if (!IsContinuationLine(lineCurrent
,styler
))
453 sc
.SetState(SCE_AU3_DEFAULT
);
457 // find Sendkeys in a STRING
458 if (sc
.ch
== '{' || sc
.ch
== '+' || sc
.ch
== '!' || sc
.ch
== '^' || sc
.ch
== '#' ) {
459 sc
.SetState(SCE_AU3_SENT
);}
465 // Send key string ended
466 if (sc
.chPrev
== '}' && sc
.ch
!= '}')
468 // set color to SENDKEY when valid sendkey .. else set back to regular string
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
472 if (GetSendKey(s
,sk
))
474 sc
.ChangeState(SCE_AU3_STRING
);
476 // if single char between {?} then its ok as sendkey for a single character
477 else if (strlen(sk
) == 3)
479 sc
.ChangeState(SCE_AU3_SENT
);
481 // if sendkey {111} is in table then ok as sendkey
482 else if (keywords4
.InList(sk
))
484 sc
.ChangeState(SCE_AU3_SENT
);
488 sc
.ChangeState(SCE_AU3_STRING
);
490 sc
.SetState(SCE_AU3_STRING
);
494 // check if the start is a valid SendKey start
498 while (!(nState
== 2) && ((cTemp
= s
[nPos
]) != '\0'))
500 if (cTemp
== '{' && nState
== 1)
504 if (nState
== 1 && !(cTemp
== '+' || cTemp
== '!' || cTemp
== '^' || cTemp
== '#' ))
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
);
515 // If invalid character found then assume its a regular string
517 sc
.ChangeState(SCE_AU3_STRING
);
518 sc
.SetState(SCE_AU3_STRING
);
521 // check if next portion is again a sendkey
524 sc
.ChangeState(SCE_AU3_STRING
);
525 sc
.SetState(SCE_AU3_DEFAULT
);
526 si
= 0; // reset string indicator
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
);}
532 // check to see if the string ended...
533 // Sendkey string isn't complete but the string ended....
534 if ((si
== 1 && sc
.ch
== '\"') || (si
== 2 && sc
.ch
== '\''))
536 sc
.ChangeState(SCE_AU3_STRING
);
537 sc
.ForwardSetState(SCE_AU3_DEFAULT
);
541 } //switch (sc.state)
543 // Determine if a new state should be entered:
545 if (sc
.state
== SCE_AU3_DEFAULT
)
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
);}
550 else if (sc
.ch
== '.' && !IsADigit(sc
.chNext
)) {sc
.SetState(SCE_AU3_OPERATOR
);}
551 else if (sc
.ch
== '@') {sc
.SetState(SCE_AU3_KEYWORD
);}
552 //else if (sc.ch == '_') {sc.SetState(SCE_AU3_KEYWORD);}
553 else if (sc
.ch
== '<' && si
==3) {sc
.SetState(SCE_AU3_STRING
);} // string after #include
554 else if (sc
.ch
== '\"') {
555 sc
.SetState(SCE_AU3_STRING
);
557 else if (sc
.ch
== '\'') {
558 sc
.SetState(SCE_AU3_STRING
);
560 else if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
)))
562 sc
.SetState(SCE_AU3_NUMBER
);
565 else if (IsAWordStart(sc
.ch
)) {sc
.SetState(SCE_AU3_KEYWORD
);}
566 else if (IsAOperator(static_cast<char>(sc
.ch
))) {sc
.SetState(SCE_AU3_OPERATOR
);}
567 else if (sc
.atLineEnd
) {sc
.SetState(SCE_AU3_DEFAULT
);}
569 } //for (; sc.More(); sc.Forward())
571 //*************************************
572 // Colourize the last word correctly
573 //*************************************
574 if (sc
.state
== SCE_AU3_KEYWORD
)
576 if (strcmp(s_save
, "#cs")== 0 || strcmp(s_save
, "#comments-start")== 0 )
578 sc
.ChangeState(SCE_AU3_COMMENTBLOCK
);
579 sc
.SetState(SCE_AU3_COMMENTBLOCK
);
581 else if (keywords
.InList(s_save
)) {
582 sc
.ChangeState(SCE_AU3_KEYWORD
);
583 sc
.SetState(SCE_AU3_KEYWORD
);
585 else if (keywords2
.InList(s_save
)) {
586 sc
.ChangeState(SCE_AU3_FUNCTION
);
587 sc
.SetState(SCE_AU3_FUNCTION
);
589 else if (keywords3
.InList(s_save
)) {
590 sc
.ChangeState(SCE_AU3_MACRO
);
591 sc
.SetState(SCE_AU3_MACRO
);
593 else if (keywords5
.InList(s_save
)) {
594 sc
.ChangeState(SCE_AU3_PREPROCESSOR
);
595 sc
.SetState(SCE_AU3_PREPROCESSOR
);
597 else if (keywords6
.InList(s_save
)) {
598 sc
.ChangeState(SCE_AU3_SPECIAL
);
599 sc
.SetState(SCE_AU3_SPECIAL
);
601 else if (keywords7
.InList(s_save
) && sc
.atLineEnd
) {
602 sc
.ChangeState(SCE_AU3_EXPAND
);
603 sc
.SetState(SCE_AU3_EXPAND
);
605 else if (keywords8
.InList(s_save
)) {
606 sc
.ChangeState(SCE_AU3_UDF
);
607 sc
.SetState(SCE_AU3_UDF
);
610 sc
.ChangeState(SCE_AU3_DEFAULT
);
611 sc
.SetState(SCE_AU3_DEFAULT
);
614 if (sc
.state
== SCE_AU3_SENT
)
616 // Send key string ended
617 if (sc
.chPrev
== '}' && sc
.ch
!= '}')
619 // set color to SENDKEY when valid sendkey .. else set back to regular string
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
623 if (GetSendKey(s_save
,sk
))
625 sc
.ChangeState(SCE_AU3_STRING
);
627 // if single char between {?} then its ok as sendkey for a single character
628 else if (strlen(sk
) == 3)
630 sc
.ChangeState(SCE_AU3_SENT
);
632 // if sendkey {111} is in table then ok as sendkey
633 else if (keywords4
.InList(sk
))
635 sc
.ChangeState(SCE_AU3_SENT
);
639 sc
.ChangeState(SCE_AU3_STRING
);
641 sc
.SetState(SCE_AU3_STRING
);
643 // check if next portion is again a sendkey
646 sc
.ChangeState(SCE_AU3_STRING
);
647 sc
.SetState(SCE_AU3_DEFAULT
);
650 //*************************************
655 static bool IsStreamCommentStyle(int style
) {
656 return style
== SCE_AU3_COMMENT
|| style
== SCE_AU3_COMMENTBLOCK
;
660 // Routine to find first none space on the current line and return its Style
661 // needed for comment lines not starting on pos 1
662 static int GetStyleFirstWord(unsigned int szLine
, Accessor
&styler
)
664 int nsPos
= styler
.LineStart(szLine
);
665 int nePos
= styler
.LineStart(szLine
+1) - 1;
666 while (isspacechar(styler
.SafeGetCharAt(nsPos
)) && nsPos
< nePos
)
668 nsPos
++; // skip to next char
671 return styler
.StyleAt(nsPos
);
673 } // GetStyleFirstWord()
677 static void FoldAU3Doc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
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;
685 // Backtrack to previous line in case need to fix its fold status
686 int lineCurrent
= styler
.GetLine(startPos
);
688 if (lineCurrent
> 0) {
690 startPos
= styler
.LineStart(lineCurrent
);
693 // vars for style of previous/current/next lines
694 int style
= GetStyleFirstWord(lineCurrent
,styler
);
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
))) {
700 startPos
= styler
.LineStart(lineCurrent
);
702 if (lineCurrent
> 0) {
703 stylePrev
= GetStyleFirstWord(lineCurrent
-1,styler
);
705 // vars for getting first word to check for keywords
706 bool FirstWordStart
= false;
707 bool FirstWordEnd
= false;
708 char szKeyword
[11]="";
709 int szKeywordlen
= 0;
712 bool ThenFoundLast
= false;
713 // var for indentlevel
714 int levelCurrent
= SC_FOLDLEVELBASE
;
716 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
717 int levelNext
= levelCurrent
;
719 int visibleChars
= 0;
720 char chNext
= styler
.SafeGetCharAt(startPos
);
723 for (int i
= startPos
; i
< endPos
; i
++) {
725 chNext
= styler
.SafeGetCharAt(i
+ 1);
726 if (IsAWordChar(ch
)) {
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
)) {
735 szKeyword
[szKeywordlen
] = '\0';
738 if (szKeywordlen
< 10) {
739 szKeyword
[szKeywordlen
++] = static_cast<char>(tolower(ch
));
743 // start the capture of the first word
744 if (!(FirstWordStart
)) {
745 if (IsAWordChar(ch
) || IsAWordStart(ch
) || ch
== ';') {
746 FirstWordStart
= true;
747 szKeyword
[szKeywordlen
++] = static_cast<char>(tolower(ch
));
750 // only process this logic when not in comment section
751 if (!(stylech
== SCE_AU3_COMMENT
)) {
753 if (IsAWordChar(ch
)) {
754 ThenFoundLast
= false;
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;
769 szThen
[szThenlen
++] = static_cast<char>(tolower(ch
));
770 if (szThenlen
== 5) {
776 // End of Line found so process the information
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.
783 if (szKeywordlen
> 0 && (!(chPrev
== '_')) &&
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
) {
790 // create new fold for these words
791 if (strcmp(szKeyword
,"do") == 0 || strcmp(szKeyword
,"for") == 0 ||
792 strcmp(szKeyword
,"func") == 0 || strcmp(szKeyword
,"while") == 0||
793 strcmp(szKeyword
,"with") == 0 || strcmp(szKeyword
,"#region") == 0 ) {
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) {
801 // end the fold for these words before the current line
802 if (strcmp(szKeyword
,"endfunc") == 0 || strcmp(szKeyword
,"endif") == 0 ||
803 strcmp(szKeyword
,"next") == 0 || strcmp(szKeyword
,"until") == 0 ||
804 strcmp(szKeyword
,"endwith") == 0 ||strcmp(szKeyword
,"wend") == 0){
808 // end the fold for these words before the current line and Start new fold
809 if (strcmp(szKeyword
,"case") == 0 || strcmp(szKeyword
,"else") == 0 ||
810 strcmp(szKeyword
,"elseif") == 0 ) {
813 // end the double fold for this word before the current line
814 if (strcmp(szKeyword
,"endselect") == 0 || strcmp(szKeyword
,"endswitch") == 0 ) {
820 // end the fold for these words on the current line
821 if (strcmp(szKeyword
,"#endregion") == 0 ) {
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
)) {
835 // fold till the last line for normal comment lines
836 else if (stylePrev
== SCE_AU3_PREPROCESSOR
&& !(styleNext
== SCE_AU3_PREPROCESSOR
)) {
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
) {
848 // fold till the last line for normal comment lines
849 else if (IsStreamCommentStyle(stylePrev
)
850 && !(styleNext
== SCE_AU3_COMMENT
)
851 && stylePrev
== SCE_AU3_COMMENT
852 && style
== SCE_AU3_COMMENT
) {
855 // fold till the one but last line for Blockcomment lines
856 else if (IsStreamCommentStyle(stylePrev
)
857 && !(styleNext
== SCE_AU3_COMMENTBLOCK
)
858 && style
== SCE_AU3_COMMENTBLOCK
) {
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
;
870 if (lev
!= styler
.LevelAt(lineCurrent
)) {
871 styler
.SetLevel(lineCurrent
, lev
);
873 // reset values for the next line
877 levelCurrent
= levelNext
;
879 // if the last character is an Underscore then don't reset since the line continues on the next line.
880 if (!(chPrev
== '_')) {
883 FirstWordStart
= false;
884 FirstWordEnd
= false;
885 ThenFoundLast
= false;
888 // save the last processed character
889 if (!isspacechar(ch
)) {
899 static const char * const AU3WordLists
[] = {
904 "#autoit Pre-processors",
910 LexerModule
lmAU3(SCLEX_AU3
, ColouriseAU3Doc
, "au3", FoldAU3Doc
, AU3WordLists
);