1 // Scintilla source code edit control
5 // By Filip Yaghob <fyaghob@gmail.com>
19 #include "Scintilla.h"
22 #define KW_MSSQL_STATEMENTS 0
23 #define KW_MSSQL_DATA_TYPES 1
24 #define KW_MSSQL_SYSTEM_TABLES 2
25 #define KW_MSSQL_GLOBAL_VARIABLES 3
26 #define KW_MSSQL_FUNCTIONS 4
27 #define KW_MSSQL_STORED_PROCEDURES 5
28 #define KW_MSSQL_OPERATORS 6
30 static bool isMSSQLOperator(char ch
) {
31 if (isascii(ch
) && isalnum(ch
))
33 // '.' left out as it is used to make up numbers
34 if (ch
== '%' || ch
== '^' || ch
== '&' || ch
== '*' ||
35 ch
== '-' || ch
== '+' || ch
== '=' || ch
== '|' ||
36 ch
== '<' || ch
== '>' || ch
== '/' ||
37 ch
== '!' || ch
== '~' || ch
== '(' || ch
== ')' ||
43 static char classifyWordSQL(unsigned int start
,
45 WordList
*keywordlists
[],
47 unsigned int actualState
,
48 unsigned int prevState
) {
50 bool wordIsNumber
= isdigit(styler
[start
]) || (styler
[start
] == '.');
52 WordList
&kwStatements
= *keywordlists
[KW_MSSQL_STATEMENTS
];
53 WordList
&kwDataTypes
= *keywordlists
[KW_MSSQL_DATA_TYPES
];
54 WordList
&kwSystemTables
= *keywordlists
[KW_MSSQL_SYSTEM_TABLES
];
55 WordList
&kwGlobalVariables
= *keywordlists
[KW_MSSQL_GLOBAL_VARIABLES
];
56 WordList
&kwFunctions
= *keywordlists
[KW_MSSQL_FUNCTIONS
];
57 WordList
&kwStoredProcedures
= *keywordlists
[KW_MSSQL_STORED_PROCEDURES
];
58 WordList
&kwOperators
= *keywordlists
[KW_MSSQL_OPERATORS
];
60 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 128; i
++) {
61 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
64 char chAttr
= SCE_MSSQL_IDENTIFIER
;
66 if (actualState
== SCE_MSSQL_GLOBAL_VARIABLE
) {
68 if (kwGlobalVariables
.InList(&s
[2]))
69 chAttr
= SCE_MSSQL_GLOBAL_VARIABLE
;
71 } else if (wordIsNumber
) {
72 chAttr
= SCE_MSSQL_NUMBER
;
74 } else if (prevState
== SCE_MSSQL_DEFAULT_PREF_DATATYPE
) {
75 // Look first in datatypes
76 if (kwDataTypes
.InList(s
))
77 chAttr
= SCE_MSSQL_DATATYPE
;
78 else if (kwOperators
.InList(s
))
79 chAttr
= SCE_MSSQL_OPERATOR
;
80 else if (kwStatements
.InList(s
))
81 chAttr
= SCE_MSSQL_STATEMENT
;
82 else if (kwSystemTables
.InList(s
))
83 chAttr
= SCE_MSSQL_SYSTABLE
;
84 else if (kwFunctions
.InList(s
))
85 chAttr
= SCE_MSSQL_FUNCTION
;
86 else if (kwStoredProcedures
.InList(s
))
87 chAttr
= SCE_MSSQL_STORED_PROCEDURE
;
90 if (kwOperators
.InList(s
))
91 chAttr
= SCE_MSSQL_OPERATOR
;
92 else if (kwStatements
.InList(s
))
93 chAttr
= SCE_MSSQL_STATEMENT
;
94 else if (kwSystemTables
.InList(s
))
95 chAttr
= SCE_MSSQL_SYSTABLE
;
96 else if (kwFunctions
.InList(s
))
97 chAttr
= SCE_MSSQL_FUNCTION
;
98 else if (kwStoredProcedures
.InList(s
))
99 chAttr
= SCE_MSSQL_STORED_PROCEDURE
;
100 else if (kwDataTypes
.InList(s
))
101 chAttr
= SCE_MSSQL_DATATYPE
;
104 styler
.ColourTo(end
, chAttr
);
109 static void ColouriseMSSQLDoc(unsigned int startPos
, int length
,
110 int initStyle
, WordList
*keywordlists
[], Accessor
&styler
) {
113 styler
.StartAt(startPos
);
115 bool fold
= styler
.GetPropertyInt("fold") != 0;
116 int lineCurrent
= styler
.GetLine(startPos
);
119 int state
= initStyle
;
120 int prevState
= initStyle
;
122 char chNext
= styler
[startPos
];
123 styler
.StartSegment(startPos
);
124 unsigned int lengthDoc
= startPos
+ length
;
125 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
127 chNext
= styler
.SafeGetCharAt(i
+ 1);
129 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
130 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
);
131 int lev
= indentCurrent
;
132 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
)) {
133 // Only non whitespace lines can be headers
134 int indentNext
= styler
.IndentAmount(lineCurrent
+ 1, &spaceFlags
);
135 if (indentCurrent
< (indentNext
& ~SC_FOLDLEVELWHITEFLAG
)) {
136 lev
|= SC_FOLDLEVELHEADERFLAG
;
140 styler
.SetLevel(lineCurrent
, lev
);
144 if (styler
.IsLeadByte(ch
)) {
145 chNext
= styler
.SafeGetCharAt(i
+ 2);
151 // When the last char isn't part of the state (have to deal with it too)...
152 if ( (state
== SCE_MSSQL_IDENTIFIER
) ||
153 (state
== SCE_MSSQL_STORED_PROCEDURE
) ||
154 (state
== SCE_MSSQL_DATATYPE
) ||
155 //~ (state == SCE_MSSQL_COLUMN_NAME) ||
156 (state
== SCE_MSSQL_FUNCTION
) ||
157 //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) ||
158 (state
== SCE_MSSQL_VARIABLE
)) {
159 if (!iswordchar(ch
)) {
162 if ((state
== SCE_MSSQL_VARIABLE
) || (state
== SCE_MSSQL_COLUMN_NAME
)) {
163 styler
.ColourTo(i
- 1, state
);
166 stateTmp
= classifyWordSQL(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, state
, prevState
);
170 if (stateTmp
== SCE_MSSQL_IDENTIFIER
|| stateTmp
== SCE_MSSQL_VARIABLE
)
171 state
= SCE_MSSQL_DEFAULT_PREF_DATATYPE
;
173 state
= SCE_MSSQL_DEFAULT
;
175 } else if (state
== SCE_MSSQL_LINE_COMMENT
) {
176 if (ch
== '\r' || ch
== '\n') {
177 styler
.ColourTo(i
- 1, state
);
179 state
= SCE_MSSQL_DEFAULT
;
181 } else if (state
== SCE_MSSQL_GLOBAL_VARIABLE
) {
182 if ((ch
!= '@') && !iswordchar(ch
)) {
183 classifyWordSQL(styler
.GetStartSegment(), i
- 1, keywordlists
, styler
, state
, prevState
);
185 state
= SCE_MSSQL_DEFAULT
;
189 // If is the default or one of the above succeeded
190 if (state
== SCE_MSSQL_DEFAULT
|| state
== SCE_MSSQL_DEFAULT_PREF_DATATYPE
) {
191 if (iswordstart(ch
)) {
192 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
194 state
= SCE_MSSQL_IDENTIFIER
;
195 } else if (ch
== '/' && chNext
== '*') {
196 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
198 state
= SCE_MSSQL_COMMENT
;
199 } else if (ch
== '-' && chNext
== '-') {
200 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
202 state
= SCE_MSSQL_LINE_COMMENT
;
203 } else if (ch
== '\'') {
204 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
206 state
= SCE_MSSQL_STRING
;
207 } else if (ch
== '"') {
208 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
210 state
= SCE_MSSQL_COLUMN_NAME
;
211 } else if (ch
== '[') {
212 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
214 state
= SCE_MSSQL_COLUMN_NAME_2
;
215 } else if (isMSSQLOperator(ch
)) {
216 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
217 styler
.ColourTo(i
, SCE_MSSQL_OPERATOR
);
218 //~ style = SCE_MSSQL_DEFAULT;
220 state
= SCE_MSSQL_DEFAULT
;
221 } else if (ch
== '@') {
222 styler
.ColourTo(i
- 1, SCE_MSSQL_DEFAULT
);
225 state
= SCE_MSSQL_GLOBAL_VARIABLE
;
228 state
= SCE_MSSQL_VARIABLE
;
232 // When the last char is part of the state...
233 } else if (state
== SCE_MSSQL_COMMENT
) {
234 if (ch
== '/' && chPrev
== '*') {
235 if (((i
> (styler
.GetStartSegment() + 2)) || ((initStyle
== SCE_MSSQL_COMMENT
) &&
236 (styler
.GetStartSegment() == startPos
)))) {
237 styler
.ColourTo(i
, state
);
238 //~ state = SCE_MSSQL_COMMENT;
240 state
= SCE_MSSQL_DEFAULT
;
243 } else if (state
== SCE_MSSQL_STRING
) {
245 if ( chNext
== '\'' ) {
248 chNext
= styler
.SafeGetCharAt(i
+ 1);
250 styler
.ColourTo(i
, state
);
252 state
= SCE_MSSQL_DEFAULT
;
256 //chNext = styler.SafeGetCharAt(i + 1);
258 } else if (state
== SCE_MSSQL_COLUMN_NAME
) {
263 chNext
= styler
.SafeGetCharAt(i
+ 1);
265 styler
.ColourTo(i
, state
);
267 state
= SCE_MSSQL_DEFAULT_PREF_DATATYPE
;
271 } else if (state
== SCE_MSSQL_COLUMN_NAME_2
) {
273 styler
.ColourTo(i
, state
);
275 state
= SCE_MSSQL_DEFAULT_PREF_DATATYPE
;
282 styler
.ColourTo(lengthDoc
- 1, state
);
285 static void FoldMSSQLDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
286 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
287 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
288 unsigned int endPos
= startPos
+ length
;
289 int visibleChars
= 0;
290 int lineCurrent
= styler
.GetLine(startPos
);
291 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
292 int levelCurrent
= levelPrev
;
293 char chNext
= styler
[startPos
];
294 bool inComment
= (styler
.StyleAt(startPos
-1) == SCE_MSSQL_COMMENT
);
296 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
298 chNext
= styler
.SafeGetCharAt(i
+ 1);
299 int style
= styler
.StyleAt(i
);
300 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
303 if (!inComment
&& (style
== SCE_MSSQL_COMMENT
))
305 else if (inComment
&& (style
!= SCE_MSSQL_COMMENT
))
307 inComment
= (style
== SCE_MSSQL_COMMENT
);
309 if (style
== SCE_MSSQL_STATEMENT
) {
310 // Folding between begin and end
311 if (ch
== 'b' || ch
== 'e') {
312 for (unsigned int j
= 0; j
< 5; j
++) {
313 if (!iswordchar(styler
[i
+ j
])) {
316 s
[j
] = styler
[i
+ j
];
319 if (strcmp(s
, "begin") == 0) {
322 if (strcmp(s
, "end") == 0) {
329 if (visibleChars
== 0 && foldCompact
)
330 lev
|= SC_FOLDLEVELWHITEFLAG
;
331 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
332 lev
|= SC_FOLDLEVELHEADERFLAG
;
333 if (lev
!= styler
.LevelAt(lineCurrent
)) {
334 styler
.SetLevel(lineCurrent
, lev
);
337 levelPrev
= levelCurrent
;
340 if (!isspacechar(ch
))
343 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
344 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
345 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
348 static const char * const sqlWordListDesc
[] = {
354 "System Stored Procedures",
359 LexerModule
lmMSSQL(SCLEX_MSSQL
, ColouriseMSSQLDoc
, "mssql", FoldMSSQLDoc
, sqlWordListDesc
);