summaryrefslogtreecommitdiffstats
path: root/src/LexAU3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/LexAU3.cpp')
-rwxr-xr-xsrc/LexAU3.cpp891
1 files changed, 891 insertions, 0 deletions
diff --git a/src/LexAU3.cpp b/src/LexAU3.cpp
new file mode 100755
index 0000000..2bc2e0f
--- /dev/null
+++ b/src/LexAU3.cpp
@@ -0,0 +1,891 @@
+// Scintilla source code edit control
+// @file LexAU3.cxx
+// Lexer for AutoIt3 http://www.hiddensoft.com/autoit3
+// by Jos van der Zande, jvdzande@yahoo.com
+//
+// Changes:
+// March 28, 2004 - Added the standard Folding code
+// April 21, 2004 - Added Preprosessor Table + Syntax Highlighting
+// Fixed Number highlighting
+// Changed default isoperator to IsAOperator to have a better match to AutoIt3
+// Fixed "#comments_start" -> "#comments-start"
+// Fixed "#comments_end" -> "#comments-end"
+// Fixed Sendkeys in Strings when not terminated with }
+// Added support for Sendkey strings that have second parameter e.g. {UP 5} or {a down}
+// April 26, 2004 - Fixed # pre-processor statement inside of comment block would invalidly change the color.
+// Added logic for #include <xyz.au3> to treat the <> as string
+// Added underscore to IsAOperator.
+// May 17, 2004 - Changed the folding logic from indent to keyword folding.
+// Added Folding logic for blocks of single-commentlines or commentblock.
+// triggered by: fold.comment=1
+// Added Folding logic for preprocessor blocks triggered by fold.preprocessor=1
+// Added Special for #region - #endregion syntax highlight and folding.
+// May 30, 2004 - Fixed issue with continuation lines on If statements.
+// June 5, 2004 - Added comma to Operators for better readability.
+// Added fold.compact support set with fold.compact=1
+// Changed folding inside of #cs-#ce. Default is no keyword folding inside comment blocks when fold.comment=1
+// it will now only happen when fold.comment=2.
+// Sep 5, 2004 - Added logic to handle colourizing words on the last line.
+// Typed Characters now show as "default" till they match any table.
+// Oct 10, 2004 - Added logic to show Comments in "Special" directives.
+// Nov 1, 2004 - Added better testing for Numbers supporting x and e notation.
+// Nov 28, 2004 - Added logic to handle continuation lines for syntax highlighting.
+// Jan 10, 2005 - Added Abbreviations Keyword used for expansion
+// Mar 24, 2005 - Updated Abbreviations Keywords to fix when followed by Operator.
+// Apr 18, 2005 - Updated #CE/#Comment-End logic to take a linecomment ";" into account
+// - Added folding support for With...EndWith
+// - Added support for a DOT in variable names
+// - Fixed Underscore in CommentBlock
+// May 23, 2005 - Fixed the SentKey lexing in case of a missing }
+// Aug 11, 2005 - Fixed possible bug with s_save length > 100.
+// Aug 23, 2005 - Added Switch/endswitch support to the folding logic.
+// Sep 27, 2005 - Fixed the SentKey lexing logic in case of multiple sentkeys.
+// Mar 12, 2006 - Fixed issue with <> coloring as String in stead of Operator in rare occasions.
+// Apr 8, 2006 - Added support for AutoIt3 Standard UDF library (SCE_AU3_UDF)
+//
+// Copyright for Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+// Scintilla source code edit control
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "Platform.h"
+
+#include "PropSet.h"
+#include "Accessor.h"
+#include "StyleContext.h"
+#include "KeyWords.h"
+#include "Scintilla.h"
+#include "SciLexer.h"
+
+static inline bool IsTypeCharacter(const int ch)
+{
+ return ch == '$';
+}
+static inline bool IsAWordChar(const int ch)
+{
+ return (ch < 0x80) && (isalnum(ch) || ch == '_');
+}
+
+static inline bool IsAWordStart(const int ch)
+{
+ return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '@' || ch == '#' || ch == '$' || ch == '.');
+}
+
+static inline bool IsAOperator(char ch) {
+ if (isascii(ch) && isalnum(ch))
+ return false;
+ if (ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
+ ch == '&' || ch == '^' || ch == '=' || ch == '<' || ch == '>' ||
+ ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == ',' )
+ return true;
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GetSendKey() filters the portion before and after a/multiple space(s)
+// and return the first portion to be looked-up in the table
+// also check if the second portion is valid... (up,down.on.off,toggle or a number)
+///////////////////////////////////////////////////////////////////////////////
+
+static int GetSendKey(const char *szLine, char *szKey)
+{
+ int nFlag = 0;
+ int nStartFound = 0;
+ int nKeyPos = 0;
+ int nSpecPos= 0;
+ int nSpecNum= 1;
+ int nPos = 0;
+ char cTemp;
+ char szSpecial[100];
+
+ // split the portion of the sendkey in the part before and after the spaces
+ while ( ( (cTemp = szLine[nPos]) != '\0'))
+ {
+ // skip leading Ctrl/Shift/Alt state
+ if (cTemp == '{') {
+ nStartFound = 1;
+ }
+ //
+ if (nStartFound == 1) {
+ if ((cTemp == ' ') && (nFlag == 0) ) // get the stuff till first space
+ {
+ nFlag = 1;
+ // Add } to the end of the first bit for table lookup later.
+ szKey[nKeyPos++] = '}';
+ }
+ else if (cTemp == ' ')
+ {
+ // skip other spaces
+ }
+ else if (nFlag == 0)
+ {
+ // save first portion into var till space or } is hit
+ szKey[nKeyPos++] = cTemp;
+ }
+ else if ((nFlag == 1) && (cTemp != '}'))
+ {
+ // Save second portion into var...
+ szSpecial[nSpecPos++] = cTemp;
+ // check if Second portion is all numbers for repeat fuction
+ if (isdigit(cTemp) == false) {nSpecNum = 0;}
+ }
+ }
+ nPos++; // skip to next char
+
+ } // End While
+
+
+ // Check if the second portion is either a number or one of these keywords
+ szKey[nKeyPos] = '\0';
+ szSpecial[nSpecPos] = '\0';
+ if (strcmp(szSpecial,"down")== 0 || strcmp(szSpecial,"up")== 0 ||
+ strcmp(szSpecial,"on")== 0 || strcmp(szSpecial,"off")== 0 ||
+ strcmp(szSpecial,"toggle")== 0 || nSpecNum == 1 )
+ {
+ nFlag = 0;
+ }
+ else
+ {
+ nFlag = 1;
+ }
+ return nFlag; // 1 is bad, 0 is good
+
+} // GetSendKey()
+
+//
+// Routine to check the last "none comment" character on a line to see if its a continuation
+//
+static bool IsContinuationLine(unsigned int szLine, Accessor &styler)
+{
+ int nsPos = styler.LineStart(szLine);
+ int nePos = styler.LineStart(szLine+1) - 2;
+ //int stylech = styler.StyleAt(nsPos);
+ while (nsPos < nePos)
+ {
+ //stylech = styler.StyleAt(nePos);
+ int stylech = styler.StyleAt(nsPos);
+ if (!(stylech == SCE_AU3_COMMENT)) {
+ char ch = styler.SafeGetCharAt(nePos);
+ if (!isspacechar(ch)) {
+ if (ch == '_')
+ return true;
+ else
+ return false;
+ }
+ }
+ nePos--; // skip to next char
+ } // End While
+ return false;
+} // IsContinuationLine()
+
+//
+// syntax highlighting logic
+static void ColouriseAU3Doc(unsigned int startPos,
+ int length, int initStyle,
+ WordList *keywordlists[],
+ Accessor &styler) {
+
+ WordList &keywords = *keywordlists[0];
+ WordList &keywords2 = *keywordlists[1];
+ WordList &keywords3 = *keywordlists[2];
+ WordList &keywords4 = *keywordlists[3];
+ WordList &keywords5 = *keywordlists[4];
+ WordList &keywords6 = *keywordlists[5];
+ WordList &keywords7 = *keywordlists[6];
+ WordList &keywords8 = *keywordlists[7];
+ // find the first previous line without continuation character at the end
+ int lineCurrent = styler.GetLine(startPos);
+ int s_startPos = startPos;
+ // When not inside a Block comment: find First line without _
+ if (!(initStyle==SCE_AU3_COMMENTBLOCK)) {
+ while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) ||
+ (lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) {
+ lineCurrent--;
+ startPos = styler.LineStart(lineCurrent); // get start position
+ initStyle = 0; // reset the start style to 0
+ }
+ }
+ // Set the new length to include it from the start and set the start position
+ length = length + s_startPos - startPos; // correct the total length to process
+ styler.StartAt(startPos);
+
+ StyleContext sc(startPos, length, initStyle, styler);
+ char si; // string indicator "=1 '=2
+ char ni; // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 Enot=3
+ char ci; // comment indicator 0=not linecomment(;)
+ char s_save[100];
+ si=0;
+ ni=0;
+ ci=0;
+ //$$$
+ for (; sc.More(); sc.Forward()) {
+ char s[100];
+ sc.GetCurrentLowered(s, sizeof(s));
+ // **********************************************
+ // save the total current word for eof processing
+ if (IsAWordChar(sc.ch) || sc.ch == '}')
+ {
+ strcpy(s_save,s);
+ int tp = strlen(s_save);
+ if (tp < 99) {
+ s_save[tp] = static_cast<char>(tolower(sc.ch));
+ s_save[tp+1] = '\0';
+ }
+ }
+ // **********************************************
+ //
+ switch (sc.state)
+ {
+ case SCE_AU3_COMMENTBLOCK:
+ {
+ //Reset at line end
+ if (sc.atLineEnd) {
+ ci=0;
+ sc.SetState(SCE_AU3_COMMENTBLOCK);
+ }
+ //skip rest of line when a ; is encountered
+ if (sc.chPrev == ';') {
+ ci=2;
+ sc.SetState(SCE_AU3_COMMENTBLOCK);
+ }
+ // skip rest of the line
+ if (ci==2)
+ break;
+ // check when first character is detected on the line
+ if (ci==0) {
+ if (IsAWordStart(static_cast<char>(sc.ch)) || IsAOperator(static_cast<char>(sc.ch))) {
+ ci=1;
+ sc.SetState(SCE_AU3_COMMENTBLOCK);
+ }
+ break;
+ }
+ if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && strcmp(s, "#comments") == 0))) {
+ if ((strcmp(s, "#ce")== 0 || strcmp(s, "#comments-end")== 0))
+ sc.SetState(SCE_AU3_COMMENT); // set to comment line for the rest of the line
+ else
+ ci=2; // line doesn't begin with #CE so skip the rest of the line
+ }
+ break;
+ }
+ case SCE_AU3_COMMENT:
+ {
+ if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
+ break;
+ }
+ case SCE_AU3_OPERATOR:
+ {
+ // check if its a COMobject
+ if (sc.chPrev == '.' && IsAWordChar(sc.ch)) {
+ sc.SetState(SCE_AU3_COMOBJ);
+ }
+ else {
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ break;
+ }
+ case SCE_AU3_SPECIAL:
+ {
+ if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
+ if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
+ break;
+ }
+ case SCE_AU3_KEYWORD:
+ {
+ if (!(IsAWordChar(sc.ch) || (sc.ch == '-' && (strcmp(s, "#comments") == 0 || strcmp(s, "#include") == 0))))
+ {
+ if (!IsTypeCharacter(sc.ch))
+ {
+ if (strcmp(s, "#cs")== 0 || strcmp(s, "#comments-start")== 0 )
+ {
+ sc.ChangeState(SCE_AU3_COMMENTBLOCK);
+ sc.SetState(SCE_AU3_COMMENTBLOCK);
+ }
+ else if (keywords.InList(s)) {
+ sc.ChangeState(SCE_AU3_KEYWORD);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (keywords2.InList(s)) {
+ sc.ChangeState(SCE_AU3_FUNCTION);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (keywords3.InList(s)) {
+ sc.ChangeState(SCE_AU3_MACRO);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (keywords5.InList(s)) {
+ sc.ChangeState(SCE_AU3_PREPROCESSOR);
+ sc.SetState(SCE_AU3_DEFAULT);
+ if (strcmp(s, "#include")== 0)
+ {
+ si = 3; // use to determine string start for #inlude <>
+ }
+ }
+ else if (keywords6.InList(s)) {
+ sc.ChangeState(SCE_AU3_SPECIAL);
+ sc.SetState(SCE_AU3_SPECIAL);
+ }
+ else if ((keywords7.InList(s)) && (!IsAOperator(static_cast<char>(sc.ch)))) {
+ sc.ChangeState(SCE_AU3_EXPAND);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (keywords8.InList(s)) {
+ sc.ChangeState(SCE_AU3_UDF);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (strcmp(s, "_") == 0) {
+ sc.ChangeState(SCE_AU3_OPERATOR);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ else if (!IsAWordChar(sc.ch)) {
+ sc.ChangeState(SCE_AU3_DEFAULT);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ }
+ }
+ if (sc.atLineEnd) {
+ sc.SetState(SCE_AU3_DEFAULT);}
+ break;
+ }
+ case SCE_AU3_NUMBER:
+ {
+ // Numeric indicator error=9 normal=0 normal+dec=1 hex=2 E-not=3
+ //
+ // test for Hex notation
+ if (strcmp(s, "0") == 0 && (sc.ch == 'x' || sc.ch == 'X') && ni == 0)
+ {
+ ni = 2;
+ break;
+ }
+ // test for E notation
+ if (IsADigit(sc.chPrev) && (sc.ch == 'e' || sc.ch == 'E') && ni <= 1)
+ {
+ ni = 3;
+ break;
+ }
+ // Allow Hex characters inside hex numeric strings
+ if ((ni == 2) &&
+ (sc.ch == 'a' || sc.ch == 'b' || sc.ch == 'c' || sc.ch == 'd' || sc.ch == 'e' || sc.ch == 'f' ||
+ sc.ch == 'A' || sc.ch == 'B' || sc.ch == 'C' || sc.ch == 'D' || sc.ch == 'E' || sc.ch == 'F' ))
+ {
+ break;
+ }
+ // test for 1 dec point only
+ if (sc.ch == '.')
+ {
+ if (ni==0)
+ {
+ ni=1;
+ }
+ else
+ {
+ ni=9;
+ }
+ break;
+ }
+ // end of numeric string ?
+ if (!(IsADigit(sc.ch)))
+ {
+ if (ni==9)
+ {
+ sc.ChangeState(SCE_AU3_DEFAULT);
+ }
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ break;
+ }
+ case SCE_AU3_VARIABLE:
+ {
+ // Check if its a COMObject
+ if (sc.ch == '.' && !IsADigit(sc.chNext)) {
+ sc.SetState(SCE_AU3_OPERATOR);
+ }
+ else if (!IsAWordChar(sc.ch)) {
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ break;
+ }
+ case SCE_AU3_COMOBJ:
+ {
+ if (!(IsAWordChar(sc.ch))) {
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ break;
+ }
+ case SCE_AU3_STRING:
+ {
+ // check for " to end a double qouted string or
+ // check for ' to end a single qouted string
+ if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\'') || (si == 3 && sc.ch == '>'))
+ {
+ sc.ForwardSetState(SCE_AU3_DEFAULT);
+ si=0;
+ }
+ if (sc.atLineEnd)
+ {
+ si=0;
+ // at line end and not found a continuation char then reset to default
+ int lineCurrent = styler.GetLine(sc.currentPos);
+ if (!IsContinuationLine(lineCurrent,styler))
+ {
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ }
+ // find Sendkeys in a STRING
+ if (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ) {
+ sc.SetState(SCE_AU3_SENT);}
+ break;
+ }
+
+ case SCE_AU3_SENT:
+ {
+ // Send key string ended
+ if (sc.chPrev == '}' && sc.ch != '}')
+ {
+ // set color to SENDKEY when valid sendkey .. else set back to regular string
+ char sk[100];
+ // split {111 222} and return {111} and check if 222 is valid.
+ // if return code = 1 then invalid 222 so must be string
+ if (GetSendKey(s,sk))
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ }
+ // if single char between {?} then its ok as sendkey for a single character
+ else if (strlen(sk) == 3)
+ {
+ sc.ChangeState(SCE_AU3_SENT);
+ }
+ // if sendkey {111} is in table then ok as sendkey
+ else if (keywords4.InList(sk))
+ {
+ sc.ChangeState(SCE_AU3_SENT);
+ }
+ else
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ }
+ sc.SetState(SCE_AU3_STRING);
+ }
+ else
+ {
+ // check if the start is a valid SendKey start
+ int nPos = 0;
+ int nState = 1;
+ char cTemp;
+ while (!(nState == 2) && ((cTemp = s[nPos]) != '\0'))
+ {
+ if (cTemp == '{' && nState == 1)
+ {
+ nState = 2;
+ }
+ if (nState == 1 && !(cTemp == '+' || cTemp == '!' || cTemp == '^' || cTemp == '#' ))
+ {
+ nState = 0;
+ }
+ nPos++;
+ }
+ //Verify characters infront of { ... if not assume regular string
+ if (nState == 1 && (!(sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' ))) {
+ sc.ChangeState(SCE_AU3_STRING);
+ sc.SetState(SCE_AU3_STRING);
+ }
+ // If invalid character found then assume its a regular string
+ if (nState == 0) {
+ sc.ChangeState(SCE_AU3_STRING);
+ sc.SetState(SCE_AU3_STRING);
+ }
+ }
+ // check if next portion is again a sendkey
+ if (sc.atLineEnd)
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ sc.SetState(SCE_AU3_DEFAULT);
+ si = 0; // reset string indicator
+ }
+ //* check in next characters following a sentkey are again a sent key
+ // Need this test incase of 2 sentkeys like {F1}{ENTER} but not detect {{}
+ if (sc.state == SCE_AU3_STRING && (sc.ch == '{' || sc.ch == '+' || sc.ch == '!' || sc.ch == '^' || sc.ch == '#' )) {
+ sc.SetState(SCE_AU3_SENT);}
+ // check to see if the string ended...
+ // Sendkey string isn't complete but the string ended....
+ if ((si == 1 && sc.ch == '\"') || (si == 2 && sc.ch == '\''))
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ sc.ForwardSetState(SCE_AU3_DEFAULT);
+ }
+ break;
+ }
+ } //switch (sc.state)
+
+ // Determine if a new state should be entered:
+
+ if (sc.state == SCE_AU3_DEFAULT)
+ {
+ if (sc.ch == ';') {sc.SetState(SCE_AU3_COMMENT);}
+ else if (sc.ch == '#') {sc.SetState(SCE_AU3_KEYWORD);}
+ else if (sc.ch == '$') {sc.SetState(SCE_AU3_VARIABLE);}
+ else if (sc.ch == '.' && !IsADigit(sc.chNext)) {sc.SetState(SCE_AU3_OPERATOR);}
+ else if (sc.ch == '@') {sc.SetState(SCE_AU3_KEYWORD);}
+ //else if (sc.ch == '_') {sc.SetState(SCE_AU3_KEYWORD);}
+ else if (sc.ch == '<' && si==3) {sc.SetState(SCE_AU3_STRING);} // string after #include
+ else if (sc.ch == '\"') {
+ sc.SetState(SCE_AU3_STRING);
+ si = 1; }
+ else if (sc.ch == '\'') {
+ sc.SetState(SCE_AU3_STRING);
+ si = 2; }
+ else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)))
+ {
+ sc.SetState(SCE_AU3_NUMBER);
+ ni = 0;
+ }
+ else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_AU3_KEYWORD);}
+ else if (IsAOperator(static_cast<char>(sc.ch))) {sc.SetState(SCE_AU3_OPERATOR);}
+ else if (sc.atLineEnd) {sc.SetState(SCE_AU3_DEFAULT);}
+ }
+ } //for (; sc.More(); sc.Forward())
+
+ //*************************************
+ // Colourize the last word correctly
+ //*************************************
+ if (sc.state == SCE_AU3_KEYWORD)
+ {
+ if (strcmp(s_save, "#cs")== 0 || strcmp(s_save, "#comments-start")== 0 )
+ {
+ sc.ChangeState(SCE_AU3_COMMENTBLOCK);
+ sc.SetState(SCE_AU3_COMMENTBLOCK);
+ }
+ else if (keywords.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_KEYWORD);
+ sc.SetState(SCE_AU3_KEYWORD);
+ }
+ else if (keywords2.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_FUNCTION);
+ sc.SetState(SCE_AU3_FUNCTION);
+ }
+ else if (keywords3.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_MACRO);
+ sc.SetState(SCE_AU3_MACRO);
+ }
+ else if (keywords5.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_PREPROCESSOR);
+ sc.SetState(SCE_AU3_PREPROCESSOR);
+ }
+ else if (keywords6.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_SPECIAL);
+ sc.SetState(SCE_AU3_SPECIAL);
+ }
+ else if (keywords7.InList(s_save) && sc.atLineEnd) {
+ sc.ChangeState(SCE_AU3_EXPAND);
+ sc.SetState(SCE_AU3_EXPAND);
+ }
+ else if (keywords8.InList(s_save)) {
+ sc.ChangeState(SCE_AU3_UDF);
+ sc.SetState(SCE_AU3_UDF);
+ }
+ else {
+ sc.ChangeState(SCE_AU3_DEFAULT);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ }
+ if (sc.state == SCE_AU3_SENT)
+ {
+ // Send key string ended
+ if (sc.chPrev == '}' && sc.ch != '}')
+ {
+ // set color to SENDKEY when valid sendkey .. else set back to regular string
+ char sk[100];
+ // split {111 222} and return {111} and check if 222 is valid.
+ // if return code = 1 then invalid 222 so must be string
+ if (GetSendKey(s_save,sk))
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ }
+ // if single char between {?} then its ok as sendkey for a single character
+ else if (strlen(sk) == 3)
+ {
+ sc.ChangeState(SCE_AU3_SENT);
+ }
+ // if sendkey {111} is in table then ok as sendkey
+ else if (keywords4.InList(sk))
+ {
+ sc.ChangeState(SCE_AU3_SENT);
+ }
+ else
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ }
+ sc.SetState(SCE_AU3_STRING);
+ }
+ // check if next portion is again a sendkey
+ if (sc.atLineEnd)
+ {
+ sc.ChangeState(SCE_AU3_STRING);
+ sc.SetState(SCE_AU3_DEFAULT);
+ }
+ }
+ //*************************************
+ sc.Complete();
+}
+
+//
+static bool IsStreamCommentStyle(int style) {
+ return style == SCE_AU3_COMMENT || style == SCE_AU3_COMMENTBLOCK;
+}
+
+//
+// Routine to find first none space on the current line and return its Style
+// needed for comment lines not starting on pos 1
+static int GetStyleFirstWord(unsigned int szLine, Accessor &styler)
+{
+ int nsPos = styler.LineStart(szLine);
+ int nePos = styler.LineStart(szLine+1) - 1;
+ while (isspacechar(styler.SafeGetCharAt(nsPos)) && nsPos < nePos)
+ {
+ nsPos++; // skip to next char
+
+ } // End While
+ return styler.StyleAt(nsPos);
+
+} // GetStyleFirstWord()
+
+
+//
+static void FoldAU3Doc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
+{
+ int endPos = startPos + length;
+ // get settings from the config files for folding comments and preprocessor lines
+ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
+ bool foldInComment = styler.GetPropertyInt("fold.comment") == 2;
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
+ bool foldpreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
+ // Backtrack to previous line in case need to fix its fold status
+ int lineCurrent = styler.GetLine(startPos);
+ if (startPos > 0) {
+ if (lineCurrent > 0) {
+ lineCurrent--;
+ startPos = styler.LineStart(lineCurrent);
+ }
+ }
+ // vars for style of previous/current/next lines
+ int style = GetStyleFirstWord(lineCurrent,styler);
+ int stylePrev = 0;
+ // find the first previous line without continuation character at the end
+ while ((lineCurrent > 0 && IsContinuationLine(lineCurrent,styler)) ||
+ (lineCurrent > 1 && IsContinuationLine(lineCurrent-1,styler))) {
+ lineCurrent--;
+ startPos = styler.LineStart(lineCurrent);
+ }
+ if (lineCurrent > 0) {
+ stylePrev = GetStyleFirstWord(lineCurrent-1,styler);
+ }
+ // vars for getting first word to check for keywords
+ bool FirstWordStart = false;
+ bool FirstWordEnd = false;
+ char szKeyword[10]="";
+ int szKeywordlen = 0;
+ char szThen[5]="";
+ int szThenlen = 0;
+ bool ThenFoundLast = false;
+ // var for indentlevel
+ int levelCurrent = SC_FOLDLEVELBASE;
+ if (lineCurrent > 0)
+ levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
+ int levelNext = levelCurrent;
+ //
+ int visibleChars = 0;
+ char chNext = styler.SafeGetCharAt(startPos);
+ char chPrev = ' ';
+ //
+ for (int i = startPos; i < endPos; i++) {
+ char ch = chNext;
+ chNext = styler.SafeGetCharAt(i + 1);
+ if (IsAWordChar(ch)) {
+ visibleChars++;
+ }
+ // get the syle for the current character neede to check in comment
+ int stylech = styler.StyleAt(i);
+ // get first word for the line for indent check max 9 characters
+ if (FirstWordStart && (!(FirstWordEnd))) {
+ if (!IsAWordChar(ch)) {
+ FirstWordEnd = true;
+ szKeyword[szKeywordlen] = '\0';
+ }
+ else {
+ if (szKeywordlen < 10) {
+ szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
+ }
+ }
+ }
+ // start the capture of the first word
+ if (!(FirstWordStart)) {
+ if (IsAWordChar(ch) || IsAWordStart(ch) || ch == ';') {
+ FirstWordStart = true;
+ szKeyword[szKeywordlen++] = static_cast<char>(tolower(ch));
+ }
+ }
+ // only process this logic when not in comment section
+ if (!(stylech == SCE_AU3_COMMENT)) {
+ if (ThenFoundLast) {
+ if (IsAWordChar(ch)) {
+ ThenFoundLast = false;
+ }
+ }
+ // find out if the word "then" is the last on a "if" line
+ if (FirstWordEnd && strcmp(szKeyword,"if") == 0) {
+ if (szThenlen == 4) {
+ szThen[0] = szThen[1];
+ szThen[1] = szThen[2];
+ szThen[2] = szThen[3];
+ szThen[3] = static_cast<char>(tolower(ch));
+ if (strcmp(szThen,"then") == 0 ) {
+ ThenFoundLast = true;
+ }
+ }
+ else {
+ szThen[szThenlen++] = static_cast<char>(tolower(ch));
+ if (szThenlen == 5) {
+ szThen[4] = '\0';
+ }
+ }
+ }
+ }
+ // End of Line found so process the information
+ if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
+ // **************************
+ // Folding logic for Keywords
+ // **************************
+ // if a keyword is found on the current line and the line doesn't end with _ (continuation)
+ // and we are not inside a commentblock.
+ if (szKeywordlen > 0 && (!(chPrev == '_')) &&
+ ((!(IsStreamCommentStyle(style)) || foldInComment)) ) {
+ szKeyword[szKeywordlen] = '\0';
+ // only fold "if" last keyword is "then" (else its a one line if)
+ if (strcmp(szKeyword,"if") == 0 && ThenFoundLast) {
+ levelNext++;
+ }
+ // create new fold for these words
+ if (strcmp(szKeyword,"do") == 0 || strcmp(szKeyword,"for") == 0 ||
+ strcmp(szKeyword,"func") == 0 || strcmp(szKeyword,"while") == 0||
+ strcmp(szKeyword,"with") == 0 || strcmp(szKeyword,"#region") == 0 ) {
+ levelNext++;
+ }
+ // create double Fold for select&switch because Case will subtract one of the current level
+ if (strcmp(szKeyword,"select") == 0 || strcmp(szKeyword,"switch") == 0) {
+ levelNext++;
+ levelNext++;
+ }
+ // end the fold for these words before the current line
+ if (strcmp(szKeyword,"endfunc") == 0 || strcmp(szKeyword,"endif") == 0 ||
+ strcmp(szKeyword,"next") == 0 || strcmp(szKeyword,"until") == 0 ||
+ strcmp(szKeyword,"endwith") == 0 ||strcmp(szKeyword,"wend") == 0){
+ levelNext--;
+ levelCurrent--;
+ }
+ // end the fold for these words before the current line and Start new fold
+ if (strcmp(szKeyword,"case") == 0 || strcmp(szKeyword,"else") == 0 ||
+ strcmp(szKeyword,"elseif") == 0 ) {
+ levelCurrent--;
+ }
+ // end the double fold for this word before the current line
+ if (strcmp(szKeyword,"endselect") == 0 || strcmp(szKeyword,"endswitch") == 0 ) {
+ levelNext--;
+ levelNext--;
+ levelCurrent--;
+ levelCurrent--;
+ }
+ // end the fold for these words on the current line
+ if (strcmp(szKeyword,"#endregion") == 0 ) {
+ levelNext--;
+ }
+ }
+ // Preprocessor and Comment folding
+ int styleNext = GetStyleFirstWord(lineCurrent + 1,styler);
+ // *************************************
+ // Folding logic for preprocessor blocks
+ // *************************************
+ // process preprosessor line
+ if (foldpreprocessor && style == SCE_AU3_PREPROCESSOR) {
+ if (!(stylePrev == SCE_AU3_PREPROCESSOR) && (styleNext == SCE_AU3_PREPROCESSOR)) {
+ levelNext++;
+ }
+ // fold till the last line for normal comment lines
+ else if (stylePrev == SCE_AU3_PREPROCESSOR && !(styleNext == SCE_AU3_PREPROCESSOR)) {
+ levelNext--;
+ }
+ }
+ // *********************************
+ // Folding logic for Comment blocks
+ // *********************************
+ if (foldComment && IsStreamCommentStyle(style)) {
+ // Start of a comment block
+ if (!(stylePrev==style) && IsStreamCommentStyle(styleNext) && styleNext==style) {
+ levelNext++;
+ }
+ // fold till the last line for normal comment lines
+ else if (IsStreamCommentStyle(stylePrev)
+ && !(styleNext == SCE_AU3_COMMENT)
+ && stylePrev == SCE_AU3_COMMENT
+ && style == SCE_AU3_COMMENT) {
+ levelNext--;
+ }
+ // fold till the one but last line for Blockcomment lines
+ else if (IsStreamCommentStyle(stylePrev)
+ && !(styleNext == SCE_AU3_COMMENTBLOCK)
+ && style == SCE_AU3_COMMENTBLOCK) {
+ levelNext--;
+ levelCurrent--;
+ }
+ }
+ int levelUse = levelCurrent;
+ int lev = levelUse | levelNext << 16;
+ if (visibleChars == 0 && foldCompact)
+ lev |= SC_FOLDLEVELWHITEFLAG;
+ if (levelUse < levelNext) {
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ }
+ if (lev != styler.LevelAt(lineCurrent)) {
+ styler.SetLevel(lineCurrent, lev);
+ }
+ // reset values for the next line
+ lineCurrent++;
+ stylePrev = style;
+ style = styleNext;
+ levelCurrent = levelNext;
+ visibleChars = 0;
+ // if the last character is an Underscore then don't reset since the line continues on the next line.
+ if (!(chPrev == '_')) {
+ szKeywordlen = 0;
+ szThenlen = 0;
+ FirstWordStart = false;
+ FirstWordEnd = false;
+ ThenFoundLast = false;
+ }
+ }
+ // save the last processed character
+ if (!isspacechar(ch)) {
+ chPrev = ch;
+ visibleChars++;
+ }
+ }
+}
+
+
+//
+
+static const char * const AU3WordLists[] = {
+ "#autoit keywords",
+ "#autoit functions",
+ "#autoit macros",
+ "#autoit Sent keys",
+ "#autoit Pre-processors",
+ "#autoit Special",
+ "#autoit Expand",
+ "#autoit UDF",
+ 0
+};
+LexerModule lmAU3(SCLEX_AU3, ColouriseAU3Doc, "au3", FoldAU3Doc , AU3WordLists);