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
);