diff options
-rw-r--r-- | doc/ScintillaHistory.html | 1 | ||||
-rw-r--r-- | lexers/LexSQL.cxx | 485 |
2 files changed, 403 insertions, 83 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 0f698d635..eea01cabd 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -362,6 +362,7 @@ <td>Martial Demolins</td> </tr><tr> <td>Tino Weinkauf</td> + <td>Jérôme Laforge</td> </tr> </table> <p> diff --git a/lexers/LexSQL.cxx b/lexers/LexSQL.cxx index 9a5dc901d..927810e04 100644 --- a/lexers/LexSQL.cxx +++ b/lexers/LexSQL.cxx @@ -2,7 +2,7 @@ /** @file LexSQL.cxx ** Lexer for SQL, including PL/SQL and SQL*Plus. **/ -// Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org> +// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. #include <stdlib.h> @@ -12,6 +12,15 @@ #include <assert.h> #include <ctype.h> +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif + +#include <string> +#include <vector> +#include <map> +#include <algorithm> + #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" @@ -23,6 +32,7 @@ #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" +#include "OptionSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; @@ -47,36 +57,288 @@ static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && - (isdigit(ch) || toupper(ch) == 'E' || - ch == '.' || ch == '-' || ch == '+'); + (isdigit(ch) || toupper(ch) == 'E' || + ch == '.' || ch == '-' || ch == '+'); } -static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], - Accessor &styler) { - WordList &keywords1 = *keywordlists[0]; - WordList &keywords2 = *keywordlists[1]; - WordList &kw_pldoc = *keywordlists[2]; - WordList &kw_sqlplus = *keywordlists[3]; - WordList &kw_user1 = *keywordlists[4]; - WordList &kw_user2 = *keywordlists[5]; - WordList &kw_user3 = *keywordlists[6]; - WordList &kw_user4 = *keywordlists[7]; +class SQLStates { +public : + void Set(int lineNumber, unsigned short int sqlStatesLine) { + if (!sqlStatement.size() == 0 || !sqlStatesLine == 0) { + sqlStatement.resize(lineNumber + 1, 0); + sqlStatement[lineNumber] = sqlStatesLine; + } + } + + unsigned short int IgnoreWhen (unsigned short int sqlStatesLine, bool enable) { + if (enable) + sqlStatesLine |= MASK_IGNORE_WHEN; + else + sqlStatesLine &= ~MASK_IGNORE_WHEN; + + return sqlStatesLine; + } - StyleContext sc(startPos, length, initStyle, styler); + unsigned short int IntoCondition (unsigned short int sqlStatesLine, bool enable) { + if (enable) + sqlStatesLine |= MASK_INTO_CONDITION; + else + sqlStatesLine &= ~MASK_INTO_CONDITION; + + return sqlStatesLine; + } + + unsigned short int IntoExceptionBlock (unsigned short int sqlStatesLine, bool enable) { + if (enable) + sqlStatesLine |= MASK_INTO_EXCEPTION; + else + sqlStatesLine &= ~MASK_INTO_EXCEPTION; + + return sqlStatesLine; + } + + unsigned short int IntoDeclareBlock (unsigned short int sqlStatesLine, bool enable) { + if (enable) + sqlStatesLine |= MASK_INTO_DECLARE; + else + sqlStatesLine &= ~MASK_INTO_DECLARE; + + return sqlStatesLine; + } + + unsigned short int BeginCaseBlock (unsigned short int sqlStatesLine) { + if ((sqlStatesLine & MASK_NESTED_CASES) < MASK_NESTED_CASES) { + sqlStatesLine++; + } + return sqlStatesLine; + } + + unsigned short int EndCaseBlock (unsigned short int sqlStatesLine) { + if ((sqlStatesLine & MASK_NESTED_CASES) > 0) { + sqlStatesLine--; + } + return sqlStatesLine; + } + + bool IsIgnoreWhen (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_IGNORE_WHEN) != 0; + } + + bool IsIntoCondition (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_INTO_CONDITION) != 0; + } + + bool IsIntoCaseBlock (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_NESTED_CASES) != 0; + } + + bool IsIntoExceptionBlock (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_INTO_EXCEPTION) != 0; + } + + bool IsIntoDeclareBlock (unsigned short int sqlStatesLine) { + return (sqlStatesLine & MASK_INTO_DECLARE) != 0; + } + + unsigned short int ForLine(int lineNumber) { + if ((lineNumber > 0) && (sqlStatement.size() > static_cast<size_t>(lineNumber))) { + return sqlStatement[lineNumber]; + } else { + return 0; + } + } + + SQLStates() {} - // property sql.backslash.escapes - // Enables backslash as an escape character in SQL. - bool sqlBackslashEscapes = styler.GetPropertyInt("sql.backslash.escapes", 0) != 0; +private : + std::vector <unsigned short int> sqlStatement; + enum { + MASK_INTO_DECLARE = 0x1000, + MASK_INTO_EXCEPTION = 0x2000, + MASK_INTO_CONDITION = 0x4000, + MASK_IGNORE_WHEN = 0x8000, + MASK_NESTED_CASES = 0x0FFF + }; +}; + +// Options used for LexerSQL +struct OptionsSQL { + bool fold; + bool foldAtElse; + bool foldComment; + bool foldCompact; + bool foldOnlyBegin; + bool foldSqlExists; + bool sqlBackticksIdentifier; + bool sqlNumbersignComment; + bool sqlBackslashEscapes; + OptionsSQL() { + fold = false; + foldAtElse = false; + foldComment = false; + foldCompact = false; + foldOnlyBegin = false; + foldSqlExists = false; + sqlBackticksIdentifier = false; + sqlNumbersignComment = false; + sqlBackslashEscapes = false; + } +}; + +static const char * const sqlWordListDesc[] = { + "Keywords", + "Database Objects", + "PLDoc", + "SQL*Plus", + "User Keywords 1", + "User Keywords 2", + "User Keywords 3", + "User Keywords 4", + 0 +}; + +struct OptionSetSQL : public OptionSet<OptionsSQL> { + OptionSetSQL() { + DefineProperty("fold", &OptionsSQL::fold); + + DefineProperty("lexer.sql.fold.at.else", &OptionsSQL::foldAtElse, + "This option enables SQL folding on a \"ELSE\" and \"ELSIF\"line of an IF statement."); + + DefineProperty("fold.comment", &OptionsSQL::foldComment); - bool sqlBackticksIdentifier = styler.GetPropertyInt("lexer.sql.backticks.identifier", 0) != 0; + DefineProperty("fold.compact", &OptionsSQL::foldCompact); - // property lexer.sql.numbersign.comment - // If "lexer.sql.numbersign.comment" property is set to 0 a line beginning with '#' will not be a comment. - bool sqlNumbersignComment = styler.GetPropertyInt("lexer.sql.numbersign.comment", 1) != 0; + DefineProperty("fold.sql.only.begin", &OptionsSQL::foldOnlyBegin); + + DefineProperty("fold.sql.exists", &OptionsSQL::foldSqlExists, + "Enables \"EXISTS\" to end a fold as is started by \"IF\" in \"DROP TABLE IF EXISTS\"."); + + DefineProperty("lexer.sql.backticks.identifier", &OptionsSQL::sqlBackticksIdentifier); + + DefineProperty("lexer.sql.numbersign.comment", &OptionsSQL::sqlNumbersignComment, + "If \"lexer.sql.numbersign.comment\" property is set to 0 a line beginning with '#' will not be a comment."); + + DefineProperty("sql.backslash.escapes", &OptionsSQL::sqlBackslashEscapes, + "Enables backslash as an escape character in SQL."); + + DefineWordListSets(sqlWordListDesc); + } +}; + +class LexerSQL : public ILexer { +public : + LexerSQL() {} + + int SCI_METHOD Version () const { + return lvOriginal; + } + + void SCI_METHOD Release() { + delete this; + } + + const char * SCI_METHOD PropertyNames() { + return osSQL.PropertyNames(); + } + + int SCI_METHOD PropertyType(const char *name) { + return osSQL.PropertyType(name); + } + + const char * SCI_METHOD DescribeProperty(const char *name) { + return osSQL.DescribeProperty(name); + } + int SCI_METHOD PropertySet(const char *key, const char *val) { + if (osSQL.PropertySet(&options, key, val)) { + return 0; + } + return -1; + } + + const char * SCI_METHOD DescribeWordListSets() { + return osSQL.DescribeWordListSets(); + } + + int SCI_METHOD WordListSet(int n, const char *wl); + void SCI_METHOD Lex (unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); + void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); + + void * SCI_METHOD PrivateCall(int, void *) { + return 0; + } + + static ILexer *LexerFactorySQL() { + return new LexerSQL(); + } +private: + bool IsStreamCommentStyle(int style) { + return style == SCE_SQL_COMMENT || + style == SCE_SQL_COMMENTDOC || + style == SCE_SQL_COMMENTDOCKEYWORD || + style == SCE_SQL_COMMENTDOCKEYWORDERROR; + } + + OptionsSQL options; + OptionSetSQL osSQL; + SQLStates sqlStates; + + WordList keywords1; + WordList keywords2; + WordList kw_pldoc; + WordList kw_sqlplus; + WordList kw_user1; + WordList kw_user2; + WordList kw_user3; + WordList kw_user4; +}; + +int SCI_METHOD LexerSQL::WordListSet(int n, const char *wl) { + WordList *wordListN = 0; + switch (n) { + case 0: + wordListN = &keywords1; + break; + case 1: + wordListN = &keywords2; + break; + case 2: + wordListN = &kw_pldoc; + break; + case 3: + wordListN = &kw_sqlplus; + break; + case 4: + wordListN = &kw_user1; + break; + case 5: + wordListN = &kw_user2; + break; + case 6: + wordListN = &kw_user3; + break; + case 7: + wordListN = &kw_user4; + } + int firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +void SCI_METHOD LexerSQL::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + LexAccessor styler(pAccess); + StyleContext sc(startPos, length, initStyle, styler); int styleBeforeDCKeyword = SCE_SQL_DEFAULT; - for (; sc.More(); sc.Forward()) { + int offset = 0; + for (; sc.More(); sc.Forward(), offset++) { // Determine if the current state should terminate. switch (sc.state) { case SCE_SQL_OPERATOR: @@ -166,7 +428,7 @@ static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, Wo } break; case SCE_SQL_CHARACTER: - if (sqlBackslashEscapes && sc.ch == '\\') { + if (options.sqlBackslashEscapes && sc.ch == '\\') { sc.Forward(); } else if (sc.ch == '\'') { if (sc.chNext == '\"') { @@ -196,7 +458,7 @@ static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, Wo sc.SetState(SCE_SQL_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_SQL_IDENTIFIER); - } else if (sc.ch == 0x60 && sqlBackticksIdentifier) { + } else if (sc.ch == 0x60 && options.sqlBackticksIdentifier) { sc.SetState(SCE_SQL_QUOTEDIDENTIFIER); } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Doxygen doc. style @@ -209,9 +471,9 @@ static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, Wo // MySQL requires a space or control char after -- // http://dev.mysql.com/doc/mysql/en/ansi-diff-comments.html // Perhaps we should enforce that with proper property: -//~ } else if (sc.Match("-- ")) { + //~ } else if (sc.Match("-- ")) { sc.SetState(SCE_SQL_COMMENTLINE); - } else if (sc.ch == '#' && sqlNumbersignComment) { + } else if (sc.ch == '#' && options.sqlNumbersignComment) { sc.SetState(SCE_SQL_COMMENTLINEDOC); } else if (sc.ch == '\'') { sc.SetState(SCE_SQL_CHARACTER); @@ -225,26 +487,10 @@ static void ColouriseSQLDoc(unsigned int startPos, int length, int initStyle, Wo sc.Complete(); } -static bool IsStreamCommentStyle(int style) { - return style == SCE_SQL_COMMENT || - style == SCE_SQL_COMMENTDOC || - style == SCE_SQL_COMMENTDOCKEYWORD || - style == SCE_SQL_COMMENTDOCKEYWORDERROR; -} - -// Store both the current line's fold level and the next lines in the -// level store to make it easy to pick up with each increment. -static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, - WordList *[], Accessor &styler) { - bool foldComment = styler.GetPropertyInt("fold.comment") != 0; - bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; - bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0; - bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; - - // property fold.sql.exists - // Enables "EXISTS" to end a fold as is started by "IF" in "DROP TABLE IF EXISTS". - bool foldSqlExists = styler.GetPropertyInt("fold.sql.exists", 1) != 0; - +void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { + if (!options.fold) + return; + LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); @@ -261,6 +507,10 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, // this statementFound flag avoids to fold when the statement is on only one line by ignoring ELSE or ELSIF // eg. "IF condition1 THEN ... ELSIF condition2 THEN ... ELSE ... END IF;" bool statementFound = false; + unsigned short int sqlStatesCurrentLine = 0; + if (!options.foldOnlyBegin) { + sqlStatesCurrentLine = sqlStates.ForLine(lineCurrent); + } for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); @@ -269,12 +519,15 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (atEOL || (ch == ';')) { + if (endFound) { + //Maybe this is the end of "EXCEPTION" BLOCK (eg. "BEGIN ... EXCEPTION ... END;") + sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, false); + } // set endFound and isUnfoldingIgnored to false if EOL is reached or ';' is found endFound = false; isUnfoldingIgnored = false; } - - if (foldComment && IsStreamCommentStyle(style)) { + if (options.foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { @@ -282,7 +535,7 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, levelNext--; } } - if (foldComment && (style == SCE_SQL_COMMENTLINE)) { + if (options.foldComment && (style == SCE_SQL_COMMENTLINE)) { // MySQL needs -- comments to be followed by space or control char if ((ch == '-') && (chNext == '-')) { char chNext2 = styler.SafeGetCharAt(i + 2); @@ -299,11 +552,13 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, levelNext++; } else if (ch == ')') { levelNext--; + } else if ((!options.foldOnlyBegin) && ch == ';') { + sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, false); } } // If new keyword (cannot trigger on elseif or nullif, does less tests) if (style == SCE_SQL_WORD && stylePrev != SCE_SQL_WORD) { - const int MAX_KW_LEN = 6; // Maximum length of folding keywords + const int MAX_KW_LEN = 9; // Maximum length of folding keywords char s[MAX_KW_LEN + 2]; unsigned int j = 0; for (; j < MAX_KW_LEN + 1; j++) { @@ -318,57 +573,131 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, } else { s[j] = '\0'; } - if (strcmp(s, "if") == 0 || - strcmp(s, "loop") == 0 || - strcmp(s, "case") == 0) { + + if (strcmp(s, "if") == 0) { if (endFound) { endFound = false; - if (foldOnlyBegin && !isUnfoldingIgnored) { + if (options.foldOnlyBegin && !isUnfoldingIgnored) { // this end isn't for begin block, but for if block ("end if;") - // or loop block ("end loop;") or case block ("end case;") // so ignore previous "end" by increment levelNext. levelNext++; } - } else if (!foldOnlyBegin) { + } else { + if (!options.foldOnlyBegin) + sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); + if (levelCurrent > levelNext) { + // doesn't include this line into the folding block + // because doesn't hide IF (eg "END; IF") + levelCurrent = levelNext; + } + } + } else if (!options.foldOnlyBegin && + strcmp(s, "then") == 0 && + sqlStates.IsIntoCondition(sqlStatesCurrentLine)) { + sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, false); + if (!options.foldOnlyBegin) { + if (levelCurrent > levelNext) { + levelCurrent = levelNext; + } + if (!statementFound) + levelNext++; + statementFound = true; + } else if (levelCurrent > levelNext) { + // doesn't include this line into the folding block + // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") + levelCurrent = levelNext; + } + } else if (strcmp(s, "loop") == 0 || + strcmp(s, "case") == 0) { + if (endFound) { + endFound = false; + if (options.foldOnlyBegin && !isUnfoldingIgnored) { + // this end isn't for begin block, but for loop block ("end loop;") or case block ("end case;") + // so ignore previous "end" by increment levelNext. + levelNext++; + } + if ((!options.foldOnlyBegin) && strcmp(s, "case") == 0) { + sqlStatesCurrentLine = sqlStates.EndCaseBlock(sqlStatesCurrentLine); + levelNext--; //again for the "end case;" and block when + } + } else if (!options.foldOnlyBegin) { + if (strcmp(s, "case") == 0) { + sqlStatesCurrentLine = sqlStates.BeginCaseBlock(sqlStatesCurrentLine); + + //for case block increment 2 times + if (!statementFound) + levelNext++; + } + if (levelCurrent > levelNext) { levelCurrent = levelNext; } - levelNext++; + if (!statementFound) + levelNext++; + + statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block - // because doesn't hide IF, LOOP or CASE (eg "END; IF" or "END; LOOP" or "END; CASE") + // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") levelCurrent = levelNext; } - } else if ((!foldOnlyBegin) && ( - // folding for ELSE and ELSIF block only if foldAtElse is set - // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) - foldAtElse && !statementFound && (strcmp(s, "elsif") == 0 || strcmp(s, "else") == 0))) { - // prevent also ELSIF and ELSE are on the same line (eg. "ELSIF condition2 THEN ... ELSE ... END IF;") + } else if ((!options.foldOnlyBegin) && ( + // folding for ELSE and ELSIF block only if foldAtElse is set + // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) + options.foldAtElse && !statementFound) && strcmp(s, "elsif") == 0) { + sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); + levelCurrent--; + levelNext--; + } else if ((!options.foldOnlyBegin) && ( + // folding for ELSE and ELSIF block only if foldAtElse is set + // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) + options.foldAtElse && !statementFound) && strcmp(s, "else") == 0) { + // prevent also ELSE is on the same line (eg. "ELSE ... END IF;") statementFound = true; // we are in same case "} ELSE {" in C language levelCurrent--; + } else if (strcmp(s, "begin") == 0) { levelNext++; + sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, false); } else if ((strcmp(s, "end") == 0) || -// // DROP TABLE IF EXISTS or CREATE TABLE IF NOT EXISTS - (foldSqlExists && (strcmp(s, "exists") == 0)) || -// // SQL Anywhere permits IF ... ELSE ... ENDIF -// // will only be active if "endif" appears in the -// // keyword list. - (strcmp(s, "endif") == 0)) { + // DROP TABLE IF EXISTS or CREATE TABLE IF NOT EXISTS + (options.foldSqlExists && (strcmp(s, "exists") == 0)) || + // SQL Anywhere permits IF ... ELSE ... ENDIF + // will only be active if "endif" appears in the + // keyword list. + (strcmp(s, "endif") == 0)) { endFound = true; levelNext--; if (levelNext < SC_FOLDLEVELBASE) { levelNext = SC_FOLDLEVELBASE; isUnfoldingIgnored = true; } + } else if ((!options.foldOnlyBegin) && + strcmp(s, "when") == 0 && + !sqlStates.IsIgnoreWhen(sqlStatesCurrentLine) && + !sqlStates.IsIntoExceptionBlock(sqlStatesCurrentLine) && + sqlStates.IsIntoCaseBlock(sqlStatesCurrentLine)) { + sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); + + // Don't foldind when CASE and WHEN are on the same line (with flag statementFound) (eg. "CASE selector WHEN expression1 THEN sequence_of_statements1;\n") + if (!statementFound) { + levelCurrent--; + levelNext--; + } + } else if ((!options.foldOnlyBegin) && strcmp(s, "exit") == 0) { + sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, true); + } else if ((!options.foldOnlyBegin) && !sqlStates.IsIntoDeclareBlock(sqlStatesCurrentLine) && strcmp(s, "exception") == 0) { + sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, true); + } else if ((!options.foldOnlyBegin) && strcmp (s, "declare") == 0) { + sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, true); } } if (atEOL) { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; - if (visibleChars == 0 && foldCompact) + if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; @@ -379,6 +708,8 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, levelCurrent = levelNext; visibleChars = 0; statementFound = false; + if (!options.foldOnlyBegin) + sqlStates.Set(lineCurrent, sqlStatesCurrentLine); } if (!isspacechar(ch)) { visibleChars++; @@ -386,16 +717,4 @@ static void FoldSQLDoc(unsigned int startPos, int length, int initStyle, } } -static const char * const sqlWordListDesc[] = { - "Keywords", - "Database Objects", - "PLDoc", - "SQL*Plus", - "User Keywords 1", - "User Keywords 2", - "User Keywords 3", - "User Keywords 4", - 0 -}; - -LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", FoldSQLDoc, sqlWordListDesc); +LexerModule lmSQL(SCLEX_SQL, LexerSQL::LexerFactorySQL, "sql", sqlWordListDesc); |