medit/scintilla/lexers/LexBaan.cxx
2016-10-22 12:38:14 -07:00

715 lines
21 KiB
C++

// Scintilla source code edit control
/** @file LexBaan.cxx
** Lexer for Baan.
** Based heavily on LexCPP.cxx
**/
// Copyright 2001- by Vamsi Potluru <vamsi@who.net> & Praveen Ambekar <ambekarpraveen@yahoo.com>
// The License.txt file describes the conditions under which this software may be distributed.
// C standard library
#include <stdlib.h>
#include <string.h>
// C++ wrappers of C standard library
#include <cassert>
// C++ standard library
#include <string>
#include <map>
// Scintilla headers
// Non-platform-specific headers
// include
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
// lexlib
#include "WordList.h"
#include "LexAccessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"
#include "OptionSet.h"
# ifdef SCI_NAMESPACE
using namespace Scintilla;
# endif
namespace {
// Use an unnamed namespace to protect the functions and classes from name conflicts
// Options used for LexerBaan
struct OptionsBaan {
bool fold;
bool foldComment;
bool foldPreprocessor;
bool foldCompact;
bool baanFoldSyntaxBased;
bool baanFoldKeywordsBased;
bool baanStylingWithinPreprocessor;
OptionsBaan() {
fold = false;
foldComment = false;
foldPreprocessor = false;
foldCompact = false;
baanFoldSyntaxBased = false;
baanFoldKeywordsBased = false;
baanStylingWithinPreprocessor = false;
}
};
const char *const baanWordLists[] = {
"Baan & BaanSQL Reserved Keywords ",
"Baan Standard functions",
"Baan Functions Abridged",
"Baan Main Sections ",
"Baan Sub Sections",
"PreDefined Variables",
"PreDefined Attributes",
"Enumerates",
0,
};
struct OptionSetBaan : public OptionSet<OptionsBaan> {
OptionSetBaan() {
DefineProperty("fold", &OptionsBaan::fold);
DefineProperty("fold.comment", &OptionsBaan::foldComment);
DefineProperty("fold.preprocessor", &OptionsBaan::foldPreprocessor);
DefineProperty("fold.compact", &OptionsBaan::foldCompact);
DefineProperty("fold.baan.syntax.based", &OptionsBaan::baanFoldSyntaxBased,
"Set this property to 0 to disable syntax based folding, which is folding based on '{' & '('.");
DefineProperty("fold.baan.keywords.based", &OptionsBaan::baanFoldKeywordsBased,
"Set this property to 0 to disable keywords based folding, which is folding based on "
" for, if, on (case), repeat, select, while and fold ends based on endfor, endif, endcase, until, endselect, endwhile respectively.");
DefineProperty("lexer.baan.styling.within.preprocessor", &OptionsBaan::baanStylingWithinPreprocessor,
"For Baan code, determines whether all preprocessor code is styled in the "
"preprocessor style (0, the default) or only from the initial # to the end "
"of the command word(1).");
DefineWordListSets(baanWordLists);
}
};
static inline bool IsAWordChar(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '$');
}
static inline bool IsAWordStart(const int ch) {
return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
static inline bool IsAnOperator(int ch) {
if (IsAlphaNumeric(ch))
return false;
if (ch == '#' || ch == '^' || ch == '&' || ch == '*' ||
ch == '(' || ch == ')' || ch == '-' || ch == '+' ||
ch == '=' || ch == '|' || ch == '{' || ch == '}' ||
ch == '[' || ch == ']' || ch == ':' || ch == ';' ||
ch == '<' || ch == '>' || ch == ',' || ch == '/' ||
ch == '?' || ch == '!' || ch == '"' || ch == '~' ||
ch == '\\')
return true;
return false;
}
static inline int IsAnyOtherIdentifier(char *s, int sLength) {
/* IsAnyOtherIdentifier uses standard templates used in baan.
The matching template is shown as comments just above the return condition.
^ - refers to any character [a-z].
# - refers to any number [0-9].
Other characters shown are compared as is.
Tried implementing with Regex... it was too complicated for me.
Any other implementation suggestion welcome.
*/
switch (sLength) {
case 8:
if (isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###
return(SCE_BAAN_TABLEDEF);
}
break;
case 9:
if (s[0] == 't' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8])) {
//t^^^^^###
return(SCE_BAAN_TABLEDEF);
}
else if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###.
return(SCE_BAAN_TABLESQL);
}
break;
case 13:
if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###.****
return(SCE_BAAN_TABLESQL);
}
else if (s[0] == 'r' && s[1] == 'c' && s[2] == 'd' && s[3] == '.' && s[4] == 't' && isalpha(s[5]) && isalpha(s[6]) && isalpha(s[7]) && isalpha(s[8]) && isalpha(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
//rcd.t^^^^^###
return(SCE_BAAN_TABLEDEF);
}
break;
case 14:
case 15:
if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
if (s[13] != ':') {
//^^^^^###.******
return(SCE_BAAN_TABLESQL);
}
}
break;
case 16:
case 17:
if (s[8] == '.' && s[9] == '_' && s[10] == 'i' && s[11] == 'n' && s[12] == 'd' && s[13] == 'e' && s[14] == 'x' && IsADigit(s[15]) && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###._index##
return(SCE_BAAN_TABLEDEF);
}
else if (s[8] == '.' && s[9] == '_' && s[10] == 'c' && s[11] == 'o' && s[12] == 'm' && s[13] == 'p' && s[14] == 'n' && s[15] == 'r' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
//^^^^^###._compnr
return(SCE_BAAN_TABLEDEF);
}
break;
default:
break;
}
if (sLength > 14 && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && s[13] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
//^^^^^.dll####.
return(SCE_BAAN_FUNCTION);
}
else if (sLength > 15 && s[2] == 'i' && s[3] == 'n' && s[4] == 't' && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[9]) && isalpha(s[10]) && isalpha(s[11]) && isalpha(s[12]) && isalpha(s[13])) {
//^^int.dll^^^^^.
return(SCE_BAAN_FUNCTION);
}
else if (sLength > 11 && s[0] == 'i' && s[10] == '.' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8]) && IsADigit(s[9])) {
//i^^^^^####.
return(SCE_BAAN_FUNCTION);
}
return(SCE_BAAN_DEFAULT);
}
static inline bool IsCommentLine(Sci_Position line, IDocument *pAccess) {
LexAccessor styler(pAccess);
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
if (ch == '|')
return true;
else if (ch != ' ' && ch != '\t')
return false;
}
return false;
}
static inline bool IsPreProcLine(Sci_Position line, IDocument *pAccess) {
LexAccessor styler(pAccess);
Sci_Position pos = styler.LineStart(line);
Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
for (Sci_Position i = pos; i < eol_pos; i++) {
char ch = styler[i];
if (ch == '#' || ch == '|' || ch == '^')
return true;
else if (ch != ' ' && ch != '\t')
return false;
}
return false;
}
static inline int ToLowerCase(int c) {
if (c >= 'A' && c <= 'Z')
return 'a' + c - 'A';
return c;
}
static inline bool wordInArray(const std::string& value, std::string *array, int length)
{
for (int i = 0; i < length; i++)
{
if (value == array[i])
{
return true;
}
}
return false;
}
class WordListAbridged : public WordList {
public:
WordListAbridged() {
kwAbridged = false;
kwHasSection = false;
};
~WordListAbridged() {
Clear();
};
bool kwAbridged;
bool kwHasSection;
bool Contains(const char *s) {
return kwAbridged ? InListAbridged(s, '~') : InList(s);
};
};
}
class LexerBaan : public ILexer {
WordListAbridged keywords;
WordListAbridged keywords2;
WordListAbridged keywords3;
WordListAbridged keywords4;
WordListAbridged keywords5;
WordListAbridged keywords6;
WordListAbridged keywords7;
WordListAbridged keywords8;
WordListAbridged keywords9;
OptionsBaan options;
OptionSetBaan osBaan;
public:
LexerBaan() {
}
virtual ~LexerBaan() {
}
int SCI_METHOD Version() const {
return lvOriginal;
}
void SCI_METHOD Release() {
delete this;
}
const char * SCI_METHOD PropertyNames() {
return osBaan.PropertyNames();
}
int SCI_METHOD PropertyType(const char * name) {
return osBaan.PropertyType(name);
}
const char * SCI_METHOD DescribeProperty(const char * name) {
return osBaan.DescribeProperty(name);
}
int SCI_METHOD PropertySet(const char *key, const char *val);
const char * SCI_METHOD DescribeWordListSets() {
return osBaan.DescribeWordListSets();
}
Sci_Position SCI_METHOD WordListSet(int n, const char *wl);
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
void * SCI_METHOD PrivateCall(int, void *) {
return NULL;
}
static ILexer * LexerFactoryBaan() {
return new LexerBaan();
}
};
Sci_Position SCI_METHOD LexerBaan::PropertySet(const char *key, const char *val) {
if (osBaan.PropertySet(&options, key, val)) {
return 0;
}
return -1;
}
Sci_Position SCI_METHOD LexerBaan::WordListSet(int n, const char *wl) {
WordListAbridged *WordListAbridgedN = 0;
switch (n) {
case 0:
WordListAbridgedN = &keywords;
break;
case 1:
WordListAbridgedN = &keywords2;
break;
case 2:
WordListAbridgedN = &keywords3;
break;
case 3:
WordListAbridgedN = &keywords4;
break;
case 4:
WordListAbridgedN = &keywords5;
break;
case 5:
WordListAbridgedN = &keywords6;
break;
case 6:
WordListAbridgedN = &keywords7;
break;
case 7:
WordListAbridgedN = &keywords8;
break;
case 8:
WordListAbridgedN = &keywords9;
break;
}
Sci_Position firstModification = -1;
if (WordListAbridgedN) {
WordListAbridged wlNew;
wlNew.Set(wl);
if (*WordListAbridgedN != wlNew) {
WordListAbridgedN->Set(wl);
WordListAbridgedN->kwAbridged = strchr(wl, '~') != NULL;
WordListAbridgedN->kwHasSection = strchr(wl, ':') != NULL;
firstModification = 0;
}
}
return firstModification;
}
void SCI_METHOD LexerBaan::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
if (initStyle == SCE_BAAN_STRINGEOL) // Does not leak onto next line
initStyle = SCE_BAAN_DEFAULT;
int visibleChars = 0;
bool lineHasDomain = false;
bool lineHasFunction = false;
bool lineHasPreProc = false;
bool lineIgnoreString = false;
bool lineHasDefines = false;
LexAccessor styler(pAccess);
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
// Determine if the current state should terminate.
switch (sc.state) {
case SCE_BAAN_OPERATOR:
sc.SetState(SCE_BAAN_DEFAULT);
break;
case SCE_BAAN_NUMBER:
if (!IsAWordChar(sc.ch)) {
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_IDENTIFIER:
if (!IsAWordChar(sc.ch)) {
char s[1000];
char s1[1000];
sc.GetCurrentLowered(s, sizeof(s));
if (sc.ch == ':') {
memcpy(s1, s, sizeof(s));
s1[sc.LengthCurrent()] = sc.ch;
s1[sc.LengthCurrent() + 1] = '\0';
}
if ((keywords.kwHasSection && (sc.ch == ':')) ? keywords.Contains(s1) : keywords.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD);
if (0 == strcmp(s, "domain")) {
lineHasDomain = true;
}
else if (0 == strcmp(s, "function")) {
lineHasFunction = true;
}
}
else if ((keywords2.kwHasSection && (sc.ch == ':')) ? keywords2.Contains(s1) : keywords2.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD2);
}
else if ((keywords3.kwHasSection && (sc.ch == ':')) ? keywords3.Contains(s1) : keywords3.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD3);
}
else if ((keywords4.kwHasSection && (sc.ch == ':')) ? keywords4.Contains(s1) : keywords4.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD4);
}
else if ((keywords5.kwHasSection && (sc.ch == ':')) ? keywords5.Contains(s1) : keywords5.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD5);
}
else if ((keywords6.kwHasSection && (sc.ch == ':')) ? keywords6.Contains(s1) : keywords6.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD6);
}
else if ((keywords7.kwHasSection && (sc.ch == ':')) ? keywords7.Contains(s1) : keywords7.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD7);
}
else if ((keywords8.kwHasSection && (sc.ch == ':')) ? keywords8.Contains(s1) : keywords8.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD8);
}
else if ((keywords9.kwHasSection && (sc.ch == ':')) ? keywords9.Contains(s1) : keywords9.Contains(s)) {
sc.ChangeState(SCE_BAAN_WORD9);
}
else if (lineHasDomain) {
sc.ChangeState(SCE_BAAN_DOMDEF);
lineHasDomain = false;
}
else if (lineHasFunction) {
sc.ChangeState(SCE_BAAN_FUNCDEF);
lineHasFunction = false;
}
else if (lineHasPreProc) {
sc.ChangeState(SCE_BAAN_OBJECTDEF);
lineHasPreProc = false;
}
else if (lineHasDefines) {
sc.ChangeState(SCE_BAAN_DEFINEDEF);
lineHasDefines = false;
}
else {
int state = IsAnyOtherIdentifier(s, sc.LengthCurrent());
if (state > 0) {
sc.ChangeState(state);
}
}
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_PREPROCESSOR:
if (options.baanStylingWithinPreprocessor) {
if (IsASpace(sc.ch) || IsAnOperator(sc.ch)) {
sc.SetState(SCE_BAAN_DEFAULT);
}
}
else {
if (sc.atLineEnd && (sc.chNext != '^')) {
sc.SetState(SCE_BAAN_DEFAULT);
}
}
break;
case SCE_BAAN_COMMENT:
if (sc.atLineEnd) {
sc.SetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_COMMENTDOC:
if (sc.MatchIgnoreCase("enddllusage")) {
for (unsigned int i = 0; i < 10; i++) {
sc.Forward();
}
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
else if (sc.MatchIgnoreCase("endfunctionusage")) {
for (unsigned int i = 0; i < 15; i++) {
sc.Forward();
}
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
break;
case SCE_BAAN_STRING:
if (sc.ch == '\"') {
sc.ForwardSetState(SCE_BAAN_DEFAULT);
}
else if ((sc.atLineEnd) && (sc.chNext != '^')) {
sc.ChangeState(SCE_BAAN_STRINGEOL);
sc.ForwardSetState(SCE_BAAN_DEFAULT);
visibleChars = 0;
}
break;
}
// Determine if a new state should be entered.
if (sc.state == SCE_BAAN_DEFAULT) {
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
sc.SetState(SCE_BAAN_NUMBER);
}
else if (sc.MatchIgnoreCase("dllusage") || sc.MatchIgnoreCase("functionusage")) {
sc.SetState(SCE_BAAN_COMMENTDOC);
do {
sc.Forward();
} while ((!sc.atLineEnd) && sc.More());
}
else if (IsAWordStart(sc.ch)) {
sc.SetState(SCE_BAAN_IDENTIFIER);
}
else if (sc.Match('|')) {
sc.SetState(SCE_BAAN_COMMENT);
}
else if (sc.ch == '\"' && !(lineIgnoreString)) {
sc.SetState(SCE_BAAN_STRING);
}
else if (sc.ch == '#' && visibleChars == 0) {
// Preprocessor commands are alone on their line
sc.SetState(SCE_BAAN_PREPROCESSOR);
// Skip whitespace between # and preprocessor word
do {
sc.Forward();
} while (IsASpace(sc.ch) && sc.More());
if (sc.MatchIgnoreCase("pragma") || sc.MatchIgnoreCase("include")) {
lineHasPreProc = true;
lineIgnoreString = true;
}
else if (sc.MatchIgnoreCase("define") || sc.MatchIgnoreCase("undef")) {
lineHasDefines = true;
lineIgnoreString = false;
}
}
else if (IsAnOperator(static_cast<char>(sc.ch))) {
sc.SetState(SCE_BAAN_OPERATOR);
}
}
if (sc.atLineEnd) {
// Reset states to begining of colourise so no surprises
// if different sets of lines lexed.
visibleChars = 0;
lineHasDomain = false;
lineHasFunction = false;
lineHasPreProc = false;
lineIgnoreString = false;
lineHasDefines = false;
}
if (!IsASpace(sc.ch)) {
visibleChars++;
}
}
sc.Complete();
}
void SCI_METHOD LexerBaan::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
char word[100];
bool foldStart = true;
bool foldNextSelect = true;
int wordlen = 0;
std::string startTags[6] = { "for", "if", "on", "repeat", "select", "while" };
std::string endTags[6] = { "endcase", "endfor", "endif", "endselect", "endwhile", "until" };
std::string selectCloseTags[5] = { "selectdo", "selecteos", "selectempty", "selecterror", "endselect" };
LexAccessor styler(pAccess);
Sci_PositionU endPos = startPos + length;
int visibleChars = 0;
Sci_Position lineCurrent = styler.GetLine(startPos);
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
int levelCurrent = levelPrev;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
for (Sci_PositionU i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
int stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (options.foldComment && style == SCE_BAAN_COMMENTDOC) {
if (style != stylePrev) {
levelCurrent++;
}
else if ((style != styleNext) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelCurrent--;
}
}
if (options.foldComment && atEOL && IsCommentLine(lineCurrent, pAccess)) {
if (!IsCommentLine(lineCurrent - 1, pAccess)
&& IsCommentLine(lineCurrent + 1, pAccess))
levelCurrent++;
else if (IsCommentLine(lineCurrent - 1, pAccess)
&& !IsCommentLine(lineCurrent + 1, pAccess))
levelCurrent--;
}
if (options.foldPreprocessor && atEOL && IsPreProcLine(lineCurrent, pAccess)) {
if (!IsPreProcLine(lineCurrent - 1, pAccess)
&& IsPreProcLine(lineCurrent + 1, pAccess))
levelCurrent++;
else if (IsPreProcLine(lineCurrent - 1, pAccess)
&& !IsPreProcLine(lineCurrent + 1, pAccess))
levelCurrent--;
}
if (options.baanFoldSyntaxBased && (style == SCE_BAAN_OPERATOR)) {
if (ch == '{' || ch == '(') {
levelCurrent++;
}
else if (ch == '}' || ch == ')') {
levelCurrent--;
}
}
if (options.baanFoldKeywordsBased && style == SCE_BAAN_WORD) {
word[wordlen++] = static_cast<char>(ToLowerCase(ch));
if (wordlen == 100) { // prevent overflow
word[0] = '\0';
wordlen = 1;
}
if (styleNext != SCE_BAAN_WORD) {
word[wordlen] = '\0';
wordlen = 0;
if (strcmp(word, "for") == 0) {
Sci_PositionU j = i + 1;
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
j++;
}
if (styler.Match(j, "update")) {
// Means this is a "for update" used by Select which is already folded.
foldStart = false;
}
}
else if (strcmp(word, "on") == 0) {
Sci_PositionU j = i + 1;
while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
j++;
}
if (!styler.Match(j, "case")) {
// Means this is not a "on Case" statement... could be "on" used by index.
foldStart = false;
}
}
else if (strcmp(word, "select") == 0) {
if (foldNextSelect) {
// Next Selects are sub-clause till reach of selectCloseTags[] array.
foldNextSelect = false;
foldStart = true;
}
else {
foldNextSelect = false;
foldStart = false;
}
}
else if (wordInArray(word, selectCloseTags, 5)) {
// select clause ends, next select clause can be folded.
foldNextSelect = true;
foldStart = true;
}
else {
foldStart = true;
}
if (foldStart) {
if (wordInArray(word, startTags, 6)) {
levelCurrent++;
}
else if (wordInArray(word, endTags, 6)) {
levelCurrent--;
}
}
}
}
if (atEOL) {
int lev = levelPrev;
if (visibleChars == 0 && options.foldCompact)
lev |= SC_FOLDLEVELWHITEFLAG;
if ((levelCurrent > levelPrev) && (visibleChars > 0))
lev |= SC_FOLDLEVELHEADERFLAG;
if (lev != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, lev);
}
lineCurrent++;
levelPrev = levelCurrent;
visibleChars = 0;
}
if (!isspacechar(ch))
visibleChars++;
}
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}
LexerModule lmBaan(SCLEX_BAAN, LexerBaan::LexerFactoryBaan, "baan", baanWordLists);