1
// Scintilla source code edit control
5
// By Filip Yaghob <fyaghob@gmail.com>
6
// The License.txt file describes the conditions under which this software may be distributed.
19
#include "Scintilla.h"
23
using namespace Scintilla;
26
#define KW_MSSQL_STATEMENTS 0
27
#define KW_MSSQL_DATA_TYPES 1
28
#define KW_MSSQL_SYSTEM_TABLES 2
29
#define KW_MSSQL_GLOBAL_VARIABLES 3
30
#define KW_MSSQL_FUNCTIONS 4
31
#define KW_MSSQL_STORED_PROCEDURES 5
32
#define KW_MSSQL_OPERATORS 6
34
static bool isMSSQLOperator(char ch) {
35
if (isascii(ch) && isalnum(ch))
37
// '.' left out as it is used to make up numbers
38
if (ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
39
ch == '-' || ch == '+' || ch == '=' || ch == '|' ||
40
ch == '<' || ch == '>' || ch == '/' ||
41
ch == '!' || ch == '~' || ch == '(' || ch == ')' ||
47
static char classifyWordSQL(unsigned int start,
49
WordList *keywordlists[],
51
unsigned int actualState,
52
unsigned int prevState) {
54
bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
56
WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS];
57
WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES];
58
WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES];
59
WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES];
60
WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS];
61
WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES];
62
WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS];
64
for (unsigned int i = 0; i < end - start + 1 && i < 128; i++) {
65
s[i] = static_cast<char>(tolower(styler[start + i]));
68
char chAttr = SCE_MSSQL_IDENTIFIER;
70
if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) {
72
if (kwGlobalVariables.InList(&s[2]))
73
chAttr = SCE_MSSQL_GLOBAL_VARIABLE;
75
} else if (wordIsNumber) {
76
chAttr = SCE_MSSQL_NUMBER;
78
} else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
79
// Look first in datatypes
80
if (kwDataTypes.InList(s))
81
chAttr = SCE_MSSQL_DATATYPE;
82
else if (kwOperators.InList(s))
83
chAttr = SCE_MSSQL_OPERATOR;
84
else if (kwStatements.InList(s))
85
chAttr = SCE_MSSQL_STATEMENT;
86
else if (kwSystemTables.InList(s))
87
chAttr = SCE_MSSQL_SYSTABLE;
88
else if (kwFunctions.InList(s))
89
chAttr = SCE_MSSQL_FUNCTION;
90
else if (kwStoredProcedures.InList(s))
91
chAttr = SCE_MSSQL_STORED_PROCEDURE;
94
if (kwOperators.InList(s))
95
chAttr = SCE_MSSQL_OPERATOR;
96
else if (kwStatements.InList(s))
97
chAttr = SCE_MSSQL_STATEMENT;
98
else if (kwSystemTables.InList(s))
99
chAttr = SCE_MSSQL_SYSTABLE;
100
else if (kwFunctions.InList(s))
101
chAttr = SCE_MSSQL_FUNCTION;
102
else if (kwStoredProcedures.InList(s))
103
chAttr = SCE_MSSQL_STORED_PROCEDURE;
104
else if (kwDataTypes.InList(s))
105
chAttr = SCE_MSSQL_DATATYPE;
108
styler.ColourTo(end, chAttr);
113
static void ColouriseMSSQLDoc(unsigned int startPos, int length,
114
int initStyle, WordList *keywordlists[], Accessor &styler) {
117
styler.StartAt(startPos);
119
bool fold = styler.GetPropertyInt("fold") != 0;
120
int lineCurrent = styler.GetLine(startPos);
123
int state = initStyle;
124
int prevState = initStyle;
126
char chNext = styler[startPos];
127
styler.StartSegment(startPos);
128
unsigned int lengthDoc = startPos + length;
129
for (unsigned int i = startPos; i < lengthDoc; i++) {
131
chNext = styler.SafeGetCharAt(i + 1);
133
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
134
int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
135
int lev = indentCurrent;
136
if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
137
// Only non whitespace lines can be headers
138
int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
139
if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
140
lev |= SC_FOLDLEVELHEADERFLAG;
144
styler.SetLevel(lineCurrent, lev);
148
if (styler.IsLeadByte(ch)) {
149
chNext = styler.SafeGetCharAt(i + 2);
155
// When the last char isn't part of the state (have to deal with it too)...
156
if ( (state == SCE_MSSQL_IDENTIFIER) ||
157
(state == SCE_MSSQL_STORED_PROCEDURE) ||
158
(state == SCE_MSSQL_DATATYPE) ||
159
//~ (state == SCE_MSSQL_COLUMN_NAME) ||
160
(state == SCE_MSSQL_FUNCTION) ||
161
//~ (state == SCE_MSSQL_GLOBAL_VARIABLE) ||
162
(state == SCE_MSSQL_VARIABLE)) {
163
if (!iswordchar(ch)) {
166
if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) {
167
styler.ColourTo(i - 1, state);
170
stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
174
if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE)
175
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
177
state = SCE_MSSQL_DEFAULT;
179
} else if (state == SCE_MSSQL_LINE_COMMENT) {
180
if (ch == '\r' || ch == '\n') {
181
styler.ColourTo(i - 1, state);
183
state = SCE_MSSQL_DEFAULT;
185
} else if (state == SCE_MSSQL_GLOBAL_VARIABLE) {
186
if ((ch != '@') && !iswordchar(ch)) {
187
classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
189
state = SCE_MSSQL_DEFAULT;
193
// If is the default or one of the above succeeded
194
if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
195
if (iswordstart(ch)) {
196
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
198
state = SCE_MSSQL_IDENTIFIER;
199
} else if (ch == '/' && chNext == '*') {
200
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
202
state = SCE_MSSQL_COMMENT;
203
} else if (ch == '-' && chNext == '-') {
204
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
206
state = SCE_MSSQL_LINE_COMMENT;
207
} else if (ch == '\'') {
208
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
210
state = SCE_MSSQL_STRING;
211
} else if (ch == '"') {
212
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
214
state = SCE_MSSQL_COLUMN_NAME;
215
} else if (ch == '[') {
216
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
218
state = SCE_MSSQL_COLUMN_NAME_2;
219
} else if (isMSSQLOperator(ch)) {
220
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
221
styler.ColourTo(i, SCE_MSSQL_OPERATOR);
222
//~ style = SCE_MSSQL_DEFAULT;
224
state = SCE_MSSQL_DEFAULT;
225
} else if (ch == '@') {
226
styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
229
state = SCE_MSSQL_GLOBAL_VARIABLE;
232
state = SCE_MSSQL_VARIABLE;
236
// When the last char is part of the state...
237
} else if (state == SCE_MSSQL_COMMENT) {
238
if (ch == '/' && chPrev == '*') {
239
if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) &&
240
(styler.GetStartSegment() == startPos)))) {
241
styler.ColourTo(i, state);
242
//~ state = SCE_MSSQL_COMMENT;
244
state = SCE_MSSQL_DEFAULT;
247
} else if (state == SCE_MSSQL_STRING) {
249
if ( chNext == '\'' ) {
252
chNext = styler.SafeGetCharAt(i + 1);
254
styler.ColourTo(i, state);
256
state = SCE_MSSQL_DEFAULT;
260
//chNext = styler.SafeGetCharAt(i + 1);
262
} else if (state == SCE_MSSQL_COLUMN_NAME) {
267
chNext = styler.SafeGetCharAt(i + 1);
269
styler.ColourTo(i, state);
271
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
275
} else if (state == SCE_MSSQL_COLUMN_NAME_2) {
277
styler.ColourTo(i, state);
279
state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
286
styler.ColourTo(lengthDoc - 1, state);
289
static void FoldMSSQLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
290
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
291
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
292
unsigned int endPos = startPos + length;
293
int visibleChars = 0;
294
int lineCurrent = styler.GetLine(startPos);
295
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
296
int levelCurrent = levelPrev;
297
char chNext = styler[startPos];
298
bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT);
300
for (unsigned int i = startPos; i < endPos; i++) {
302
chNext = styler.SafeGetCharAt(i + 1);
303
int style = styler.StyleAt(i);
304
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
307
if (!inComment && (style == SCE_MSSQL_COMMENT))
309
else if (inComment && (style != SCE_MSSQL_COMMENT))
311
inComment = (style == SCE_MSSQL_COMMENT);
313
if (style == SCE_MSSQL_STATEMENT) {
314
// Folding between begin or case and end
315
if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') {
316
for (unsigned int j = 0; j < 5; j++) {
317
if (!iswordchar(styler[i + j])) {
320
s[j] = static_cast<char>(tolower(styler[i + j]));
323
if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 0)) {
326
if (strcmp(s, "end") == 0) {
333
if (visibleChars == 0 && foldCompact)
334
lev |= SC_FOLDLEVELWHITEFLAG;
335
if ((levelCurrent > levelPrev) && (visibleChars > 0))
336
lev |= SC_FOLDLEVELHEADERFLAG;
337
if (lev != styler.LevelAt(lineCurrent)) {
338
styler.SetLevel(lineCurrent, lev);
341
levelPrev = levelCurrent;
344
if (!isspacechar(ch))
347
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
348
int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
349
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
352
static const char * const sqlWordListDesc[] = {
358
"System Stored Procedures",
363
LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc);