in ext/scintilla/lexers/LexProgress.cxx [217:492]
void SCI_METHOD LexerABL::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
LexAccessor styler(pAccess);
setWordStart = CharacterSet(CharacterSet::setAlpha, "_", 0x80, true);
int visibleChars = 0;
int visibleChars1 = 0;
int styleBeforeTaskMarker = SCE_ABL_DEFAULT;
bool continuationLine = false;
int commentNestingLevel = 0;
bool isSentenceStart = true;
bool possibleOOLChange = false;
Sci_Position lineCurrent = styler.GetLine(startPos);
if (initStyle == SCE_ABL_PREPROCESSOR) {
// Set continuationLine if last character of previous line is '~'
if (lineCurrent > 0) {
Sci_Position endLinePrevious = styler.LineEnd(lineCurrent-1);
if (endLinePrevious > 0) {
continuationLine = styler.SafeGetCharAt(endLinePrevious-1) == '~';
}
}
}
// Look back to set variables that are actually invisible secondary states. The reason to avoid formal states is to cut down on state's bits
if (startPos > 0) {
Sci_Position back = startPos;
bool checkCommentNestingLevel = (initStyle == SCE_ABL_COMMENT);
bool checkIsSentenceStart = (initStyle == SCE_ABL_DEFAULT || initStyle == SCE_ABL_IDENTIFIER);
char ch;
char st;
char chPrev;
char chPrev_1;
char chPrev_2;
char chPrev_3;
while (back >= 0 && (checkCommentNestingLevel || checkIsSentenceStart)) {
ch = styler.SafeGetCharAt(back);
styler.Flush(); // looking at styles so need to flush
st = styler.StyleAt(back);
chPrev = styler.SafeGetCharAt(back-1);
// isSentenceStart is a non-visible state, used to identify where statements and preprocessor declerations can start
if (checkIsSentenceStart && st != SCE_ABL_COMMENT && st != SCE_ABL_LINECOMMENT && st != SCE_ABL_CHARACTER && st != SCE_ABL_STRING ) {
chPrev_1 = styler.SafeGetCharAt(back-2);
chPrev_2 = styler.SafeGetCharAt(back-3);
chPrev_3 = styler.SafeGetCharAt(back-4);
if ((chPrev == '.' || chPrev == ':' || chPrev == '}' ||
(chPrev_3 == 'e' && chPrev_2 == 'l' && chPrev_1 == 's' && chPrev == 'e') ||
(chPrev_3 == 't' && chPrev_2 == 'h' && chPrev_1 == 'e' && chPrev == 'n')) &&
(IsASpace(ch) || (ch == '/' && styler.SafeGetCharAt(back+1) == '*'))
) {
checkIsSentenceStart = false;
isSentenceStart = true;
}
else if (IsASpace(chPrev) && ch == '{') {
checkIsSentenceStart = false;
isSentenceStart = false;
}
}
// commentNestingLevel is a non-visible state, used to identify the nesting level of a comment
if (checkCommentNestingLevel) {
if (chPrev == '/' && ch == '*') {
commentNestingLevel++;
// eat the '/' so we don't miscount a */ if we see /*/*
--back;
}
if (chPrev == '*' && ch == '/') {
commentNestingLevel--;
// eat the '*' so we don't miscount a /* if we see */*/
--back;
}
}
--back;
}
}
StyleContext sc(startPos, length, initStyle, styler, static_cast<unsigned char>(0xff));
Sci_Position lineEndNext = styler.LineEnd(lineCurrent);
for (; sc.More();) {
if (sc.atLineStart) {
visibleChars = 0;
visibleChars1 = 0;
}
if (sc.atLineEnd) {
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
}
// Handle line continuation generically.
if (sc.ch == '~') {
if (static_cast<Sci_Position>((sc.currentPos+1)) >= lineEndNext) {
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
sc.Forward();
if (sc.ch == '\r' && sc.chNext == '\n') {
sc.Forward();
}
continuationLine = true;
sc.Forward();
continue;
}
}
const bool atLineEndBeforeSwitch = sc.atLineEnd;
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_ABL_OPERATOR:
sc.SetState(SCE_ABL_DEFAULT);
break;
case SCE_ABL_NUMBER:
// We accept almost anything because of hex. and maybe number suffixes and scientific notations in the future
if (!(setWord.Contains(sc.ch)
|| ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E' ||
sc.chPrev == 'p' || sc.chPrev == 'P')))) {
sc.SetState(SCE_ABL_DEFAULT);
}
break;
case SCE_ABL_IDENTIFIER:
if (sc.atLineStart || sc.atLineEnd || (!setWord.Contains(sc.ch) && sc.ch != '-')) {
char s[1000];
sc.GetCurrentLowered(s, sizeof(s));
bool isLastWordEnd = (s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !IsAlphaNumeric(s[3]) && s[3] != '-'); // helps to identify "end trigger" phrase
if ((isSentenceStart && keywords2.InListAbbreviated (s,'(')) || (!isLastWordEnd && keywords3.InListAbbreviated (s,'('))) {
sc.ChangeState(SCE_ABL_BLOCK);
isSentenceStart = false;
}
else if (keywords1.InListAbbreviated (s,'(')) {
if (isLastWordEnd ||
(s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !IsAlphaNumeric(s[7]))) {
sc.ChangeState(SCE_ABL_END);
isSentenceStart = false;
}
else if ((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||
(s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {
sc.ChangeState(SCE_ABL_WORD);
isSentenceStart = true;
}
else {
sc.ChangeState(SCE_ABL_WORD);
isSentenceStart = false;
}
}
sc.SetState(SCE_ABL_DEFAULT);
}
break;
case SCE_ABL_PREPROCESSOR:
if (sc.atLineStart && !continuationLine) {
sc.SetState(SCE_ABL_DEFAULT);
// Force Scintilla to acknowledge changed stated even though this change might happen outside of the current line
possibleOOLChange = true;
isSentenceStart = true;
}
break;
case SCE_ABL_LINECOMMENT:
if (sc.atLineStart && !continuationLine) {
sc.SetState(SCE_ABL_DEFAULT);
isSentenceStart = true;
} else {
styleBeforeTaskMarker = SCE_ABL_LINECOMMENT;
highlightTaskMarker(sc, styler, keywords4);
}
break;
case SCE_ABL_TASKMARKER:
if (isoperator(sc.ch) || IsASpace(sc.ch)) {
sc.SetState(styleBeforeTaskMarker);
styleBeforeTaskMarker = SCE_ABL_DEFAULT;
}
// fall through
case SCE_ABL_COMMENT:
if (sc.Match('*', '/')) {
sc.Forward();
commentNestingLevel--;
if (commentNestingLevel == 0) {
sc.ForwardSetState(SCE_ABL_DEFAULT);
possibleOOLChange = true;
}
} else if (sc.Match('/', '*')) {
commentNestingLevel++;
sc.Forward();
}
if (commentNestingLevel > 0) {
styleBeforeTaskMarker = SCE_ABL_COMMENT;
possibleOOLChange = true;
highlightTaskMarker(sc, styler, keywords4);
}
break;
case SCE_ABL_STRING:
if (sc.ch == '~') {
sc.Forward(); // Skip a character after a tilde
} else if (sc.ch == '\"') {
sc.ForwardSetState(SCE_ABL_DEFAULT);
}
break;
case SCE_ABL_CHARACTER:
if (sc.ch == '~') {
sc.Forward(); // Skip a character after a tilde
} else if (sc.ch == '\'') {
sc.ForwardSetState(SCE_ABL_DEFAULT);
}
break;
}
if (sc.atLineEnd && !atLineEndBeforeSwitch) {
// State exit processing consumed characters up to end of line.
lineCurrent++;
lineEndNext = styler.LineEnd(lineCurrent);
}
// Determine if a new state should be entered.
if (sc.state == SCE_ABL_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_ABL_NUMBER);
isSentenceStart = false;
} else if (!sc.atLineEnd && (setWordStart.Contains(sc.ch)) && sc.chPrev != '&') {
sc.SetState(SCE_ABL_IDENTIFIER);
} else if (sc.Match('/', '*')) {
if (sc.chPrev == '.' || sc.chPrev == ':' || sc.chPrev == '}') {
isSentenceStart = true;
}
sc.SetState(SCE_ABL_COMMENT);
possibleOOLChange = true;
commentNestingLevel++;
sc.Forward(); // Eat the * so it isn't used for the end of the comment
} else if (sc.ch == '\"') {
sc.SetState(SCE_ABL_STRING);
isSentenceStart = false;
} else if (sc.ch == '\'') {
sc.SetState(SCE_ABL_CHARACTER);
isSentenceStart = false;
} else if (sc.ch == '&' && visibleChars1 == 0 && isSentenceStart) {
// Preprocessor commands are alone on their line
sc.SetState(SCE_ABL_PREPROCESSOR);
// Force Scintilla to acknowledge changed stated even though this change might happen outside of the current line
possibleOOLChange = true;
// Skip whitespace between & and preprocessor word
do {
sc.Forward();
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
if (sc.atLineEnd) {
sc.SetState(SCE_ABL_DEFAULT);
}
} else if (sc.Match('/','/') && (IsASpace(sc.chPrev) || isSentenceStart)) {
// Line comments are valid after a white space or EOL
sc.SetState(SCE_ABL_LINECOMMENT);
// Skip whitespace between // and preprocessor word
do {
sc.Forward();
} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
if (sc.atLineEnd) {
sc.SetState(SCE_ABL_DEFAULT);
}
} else if (isoperator(sc.ch)) {
sc.SetState(SCE_ABL_OPERATOR);
/* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function"
to be recognized as a BlockBegin */
isSentenceStart = false;
}
else if ((sc.chPrev == '.' || sc.chPrev == ':' || sc.chPrev == '}') && (IsASpace(sc.ch))) {
isSentenceStart = true;
}
}
if (!IsASpace(sc.ch)) {
visibleChars1++;
}
if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
visibleChars++;
}
continuationLine = false;
sc.Forward();
}
if (possibleOOLChange)
styler.ChangeLexerState(startPos, startPos + length);
sc.Complete();
}