aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/LexSQL.cxx302
1 files changed, 255 insertions, 47 deletions
diff --git a/src/LexSQL.cxx b/src/LexSQL.cxx
index bb8f128da..dc4c7a804 100644
--- a/src/LexSQL.cxx
+++ b/src/LexSQL.cxx
@@ -19,35 +19,92 @@
#include "Scintilla.h"
#include "SciLexer.h"
+
+static inline bool IsASpace(unsigned int ch) {
+ return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
+}
+
+static bool MatchIgnoreCaseSubstring(const char *s, Accessor &styler, unsigned int startPos) {
+ char ch = styler.SafeGetCharAt(startPos);
+ bool isSubword = false;
+ if (tolower(ch) != *s)
+ return false;
+ s++;
+ if (*s == '~')
+ {
+ isSubword = true;
+ s++;
+ }
+ int n;
+ for (n = 1; *s; n++) {
+ if (*s == '~')
+ {
+ isSubword = true;
+ s++;
+ }
+ if (isSubword && IsASpace(styler.SafeGetCharAt(startPos + n)))
+ return true;
+ if (*s != tolower((styler.SafeGetCharAt(startPos + n))))
+ return false;
+ s++;
+ }
+ return (IsASpace(styler.SafeGetCharAt(startPos + n))
+ || styler.SafeGetCharAt(startPos + n) == ';');
+}
+
+static void getCurrent(unsigned int start,
+ unsigned int end,
+ Accessor &styler,
+ char *s,
+ unsigned int len) {
+ for (unsigned int i = 0; i < end - start + 1 && i < len; i++) {
+ s[i] = static_cast<char>(tolower(styler[start + i]));
+ s[i + 1] = '\0';
+ }
+}
+
static void classifyWordSQL(unsigned int start, unsigned int end, WordList *keywordlists[], Accessor &styler) {
char s[100];
bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
- for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
+ for (unsigned int i = 0; i < end - start + 1 && i < 80; i++) {
s[i] = static_cast<char>(tolower(styler[start + i]));
s[i + 1] = '\0';
}
- WordList &keywords1 = *keywordlists[0];
- WordList &keywords2 = *keywordlists[1];
+ 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];
- char chAttr = SCE_C_IDENTIFIER;
+ char chAttr = SCE_SQL_IDENTIFIER;
if (wordIsNumber)
- chAttr = SCE_C_NUMBER;
- else {
- if (keywords1.InList(s)) {
- chAttr = SCE_C_WORD;
- }
+ chAttr = SCE_SQL_NUMBER;
+ else if (keywords1.InList(s))
+ chAttr = SCE_SQL_WORD;
+ else if (keywords2.InList(s))
+ chAttr = SCE_SQL_WORD2;
+ else if (kw_sqlplus.InListAbbreviated(s, '~'))
+ chAttr = SCE_SQL_SQLPLUS;
+ else if (kw_user1.InList(s))
+ chAttr = SCE_SQL_USER1;
+ else if (kw_user2.InList(s))
+ chAttr = SCE_SQL_USER2;
+ else if (kw_user3.InList(s))
+ chAttr = SCE_SQL_USER3;
+ else if (kw_user4.InList(s))
+ chAttr = SCE_SQL_USER4;
- if (keywords2.InList(s)) {
- chAttr = SCE_C_WORD2;
- }
- }
styler.ColourTo(end, chAttr);
}
static void ColouriseSQLDoc(unsigned int startPos, int length,
int initStyle, WordList *keywordlists[], Accessor &styler) {
+ WordList &kw_pldoc = *keywordlists[2];
styler.StartAt(startPos);
bool fold = styler.GetPropertyInt("fold") != 0;
@@ -86,62 +143,108 @@ static void ColouriseSQLDoc(unsigned int startPos, int length,
continue;
}
- if (state == SCE_C_DEFAULT) {
- if (iswordstart(ch)) {
+ if (state == SCE_SQL_DEFAULT) {
+ if (MatchIgnoreCaseSubstring("rem~ark", styler, i)) {
+ styler.ColourTo(i - 1, state);
+ state = SCE_SQL_SQLPLUS_COMMENT;
+ } else if (MatchIgnoreCaseSubstring("pro~mpt", styler, i)) {
styler.ColourTo(i - 1, state);
- state = SCE_C_WORD;
+ state = SCE_SQL_SQLPLUS_PROMPT;
+ } else if (iswordstart(ch)) {
+ styler.ColourTo(i - 1, state);
+ state = SCE_SQL_WORD;
} else if (ch == '/' && chNext == '*') {
styler.ColourTo(i - 1, state);
- state = SCE_C_COMMENT;
+ if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
+ state = SCE_SQL_COMMENTDOC;
+ } else {
+ state = SCE_SQL_COMMENT;
+ }
} else if (ch == '-' && chNext == '-') {
styler.ColourTo(i - 1, state);
- state = SCE_C_COMMENTLINE;
+ state = SCE_SQL_COMMENTLINE;
} else if (ch == '#') {
styler.ColourTo(i - 1, state);
- state = SCE_C_COMMENTLINEDOC;
+ state = SCE_SQL_COMMENTLINEDOC;
} else if (ch == '\'') {
styler.ColourTo(i - 1, state);
- state = SCE_C_CHARACTER;
+ state = SCE_SQL_CHARACTER;
} else if (ch == '"') {
styler.ColourTo(i - 1, state);
- state = SCE_C_STRING;
+ state = SCE_SQL_STRING;
} else if (isoperator(ch)) {
styler.ColourTo(i - 1, state);
- styler.ColourTo(i, SCE_C_OPERATOR);
+ styler.ColourTo(i, SCE_SQL_OPERATOR);
}
- } else if (state == SCE_C_WORD) {
+ } else if (state == SCE_SQL_WORD) {
if (!iswordchar(ch)) {
classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler);
- state = SCE_C_DEFAULT;
+ state = SCE_SQL_DEFAULT;
if (ch == '/' && chNext == '*') {
- state = SCE_C_COMMENT;
+ if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
+ state = SCE_SQL_COMMENTDOC;
+ } else {
+ state = SCE_SQL_COMMENT;
+ }
} else if (ch == '-' && chNext == '-') {
- state = SCE_C_COMMENTLINE;
+ state = SCE_SQL_COMMENTLINE;
} else if (ch == '#') {
- state = SCE_C_COMMENTLINEDOC;
+ state = SCE_SQL_COMMENTLINEDOC;
} else if (ch == '\'') {
- state = SCE_C_CHARACTER;
+ state = SCE_SQL_CHARACTER;
} else if (ch == '"') {
- state = SCE_C_STRING;
+ state = SCE_SQL_STRING;
} else if (isoperator(ch)) {
- styler.ColourTo(i, SCE_C_OPERATOR);
+ styler.ColourTo(i, SCE_SQL_OPERATOR);
}
}
} else {
- if (state == SCE_C_COMMENT) {
+ if (state == SCE_SQL_COMMENT) {
if (ch == '/' && chPrev == '*') {
if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_C_COMMENT) &&
(styler.GetStartSegment() == startPos)))) {
styler.ColourTo(i, state);
- state = SCE_C_DEFAULT;
+ state = SCE_SQL_DEFAULT;
+ }
+ }
+ } else if (state == SCE_SQL_COMMENTDOC) {
+ if (ch == '/' && chPrev == '*') {
+ if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_SQL_COMMENTDOC) &&
+ (styler.GetStartSegment() == startPos)))) {
+ styler.ColourTo(i, state);
+ state = SCE_SQL_DEFAULT;
+ }
+ } else if (ch == '@') {
+ // Verify that we have the conditions to mark a comment-doc-keyword
+ if ((IsASpace(chPrev) || chPrev == '*') && (!IsASpace(chNext))) {
+ styler.ColourTo(i - 1, state);
+ state = SCE_SQL_COMMENTDOCKEYWORD;
}
}
- } else if (state == SCE_C_COMMENTLINE || state == SCE_C_COMMENTLINEDOC) {
+ } else if (state == SCE_SQL_COMMENTLINE || state == SCE_SQL_COMMENTLINEDOC || state == SCE_SQL_SQLPLUS_COMMENT) {
if (ch == '\r' || ch == '\n') {
styler.ColourTo(i - 1, state);
- state = SCE_C_DEFAULT;
+ state = SCE_SQL_DEFAULT;
}
- } else if (state == SCE_C_CHARACTER) {
+ } else if (state == SCE_SQL_COMMENTDOCKEYWORD) {
+ if (ch == '/' && chPrev == '*') {
+ styler.ColourTo(i - 1, SCE_SQL_COMMENTDOCKEYWORDERROR);
+ state = SCE_SQL_DEFAULT;
+ } else if (!iswordchar(ch)) {
+ char s[100];
+ getCurrent(styler.GetStartSegment(), i - 1, styler, s, 30);
+ if (!kw_pldoc.InList(s + 1)) {
+ state = SCE_SQL_COMMENTDOCKEYWORDERROR;
+ }
+ styler.ColourTo(i - 1, state);
+ state = SCE_SQL_COMMENTDOC;
+ }
+ } else if (state == SCE_SQL_SQLPLUS_PROMPT) {
+ if (ch == '\r' || ch == '\n') {
+ styler.ColourTo(i - 1, state);
+ state = SCE_SQL_DEFAULT;
+ }
+ } else if (state == SCE_SQL_CHARACTER) {
if (sqlBackslashEscapes && ch == '\\') {
i++;
ch = chNext;
@@ -151,40 +254,48 @@ static void ColouriseSQLDoc(unsigned int startPos, int length,
i++;
} else {
styler.ColourTo(i, state);
- state = SCE_C_DEFAULT;
+ state = SCE_SQL_DEFAULT;
i++;
}
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
}
- } else if (state == SCE_C_STRING) {
+ } else if (state == SCE_SQL_STRING) {
if (ch == '"') {
if (chNext == '"') {
i++;
} else {
styler.ColourTo(i, state);
- state = SCE_C_DEFAULT;
+ state = SCE_SQL_DEFAULT;
i++;
}
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
}
}
- if (state == SCE_C_DEFAULT) { // One of the above succeeded
+ if (state == SCE_SQL_DEFAULT) { // One of the above succeeded
if (ch == '/' && chNext == '*') {
- state = SCE_C_COMMENT;
+ if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
+ state = SCE_SQL_COMMENTDOC;
+ } else {
+ state = SCE_SQL_COMMENT;
+ }
} else if (ch == '-' && chNext == '-') {
- state = SCE_C_COMMENTLINE;
+ state = SCE_SQL_COMMENTLINE;
} else if (ch == '#') {
- state = SCE_C_COMMENTLINEDOC;
+ state = SCE_SQL_COMMENTLINEDOC;
+ } else if (MatchIgnoreCaseSubstring("rem~ark", styler, i)) {
+ state = SCE_SQL_SQLPLUS_COMMENT;
+ } else if (MatchIgnoreCaseSubstring("pro~mpt", styler, i)) {
+ state = SCE_SQL_SQLPLUS_PROMPT;
} else if (ch == '\'') {
- state = SCE_C_CHARACTER;
+ state = SCE_SQL_CHARACTER;
} else if (ch == '"') {
- state = SCE_C_STRING;
+ state = SCE_SQL_STRING;
} else if (iswordstart(ch)) {
- state = SCE_C_WORD;
+ state = SCE_SQL_WORD;
} else if (isoperator(ch)) {
- styler.ColourTo(i, SCE_C_OPERATOR);
+ styler.ColourTo(i, SCE_SQL_OPERATOR);
}
}
}
@@ -193,10 +304,107 @@ static void ColouriseSQLDoc(unsigned int startPos, int length,
styler.ColourTo(lengthDoc - 1, state);
}
+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
+// and to make it possible to fiddle the current level for "} else {".
+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;
+ unsigned int endPos = startPos + length;
+ int visibleChars = 0;
+ int lineCurrent = styler.GetLine(startPos);
+ int levelCurrent = SC_FOLDLEVELBASE;
+ if (lineCurrent > 0)
+ levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
+ int levelNext = levelCurrent;
+ char chNext = styler[startPos];
+ int styleNext = styler.StyleAt(startPos);
+ int style = initStyle;
+ bool endFound = false;
+ for (unsigned int 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 (foldComment && IsStreamCommentStyle(style)) {
+ if (!IsStreamCommentStyle(stylePrev)) {
+ levelNext++;
+ } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
+ // Comments don't end at end of line and the next character may be unstyled.
+ levelNext--;
+ }
+ }
+ if (foldComment && (style == SCE_SQL_COMMENTLINE)) {
+ if ((ch == '-') && (chNext == '-')) {
+ char chNext2 = styler.SafeGetCharAt(i + 2);
+ if (chNext2 == '{') {
+ levelNext++;
+ } else if (chNext2 == '}') {
+ levelNext--;
+ }
+ }
+ }
+ if (style == SCE_SQL_WORD) {
+ if (MatchIgnoreCaseSubstring("elsif", styler, i)) {
+ // ignore elsif
+ i += 4;
+ } else if (MatchIgnoreCaseSubstring("if", styler, i)
+ || MatchIgnoreCaseSubstring("loop", styler, i)){
+ if (endFound){
+ // ignore
+ endFound = false;
+ } else {
+ levelNext++;
+ }
+ } else if (MatchIgnoreCaseSubstring("begin", styler, i)){
+ levelNext++;
+ } else if (MatchIgnoreCaseSubstring("end", styler, i)) {
+ endFound = true;
+ levelNext--;
+ if (levelNext < SC_FOLDLEVELBASE)
+ levelNext = SC_FOLDLEVELBASE;
+ }
+ }
+ if (atEOL) {
+ 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);
+ }
+ lineCurrent++;
+ levelCurrent = levelNext;
+ visibleChars = 0;
+ endFound = false;
+ }
+ if (!isspacechar(ch))
+ visibleChars++;
+ }
+}
+
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", 0, sqlWordListDesc);
+LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", FoldSQLDoc, sqlWordListDesc);