]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexHTML.cxx
d830a46439e822b5a0704ccbd29d27152a618b81
[wxWidgets.git] / src / stc / scintilla / src / LexHTML.cxx
1 // Scintilla source code edit control
2 /** @file LexHTML.cxx
3 ** Lexer for HTML.
4 **/
5 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13
14 #include "Platform.h"
15
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "StyleContext.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 #define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START)
24 #define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START)
25 #define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START)
26
27 enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock };
28 enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc };
29
30 static inline bool IsAWordChar(const int ch) {
31 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
32 }
33
34 static inline bool IsAWordStart(const int ch) {
35 return (ch < 0x80) && (isalnum(ch) || ch == '_');
36 }
37
38 static inline int MakeLowerCase(int ch) {
39 if (ch < 'A' || ch > 'Z')
40 return ch;
41 else
42 return ch - 'A' + 'a';
43 }
44
45 static void GetTextSegment(Accessor &styler, unsigned int start, unsigned int end, char *s, size_t len) {
46 size_t i = 0;
47 for (; (i < end - start + 1) && (i < len-1); i++) {
48 s[i] = static_cast<char>(MakeLowerCase(styler[start + i]));
49 }
50 s[i] = '\0';
51 }
52
53 static script_type segIsScriptingIndicator(Accessor &styler, unsigned int start, unsigned int end, script_type prevValue) {
54 char s[100];
55 GetTextSegment(styler, start, end, s, sizeof(s));
56 //Platform::DebugPrintf("Scripting indicator [%s]\n", s);
57 if (strstr(s, "src")) // External script
58 return eScriptNone;
59 if (strstr(s, "vbs"))
60 return eScriptVBS;
61 if (strstr(s, "pyth"))
62 return eScriptPython;
63 if (strstr(s, "javas"))
64 return eScriptJS;
65 if (strstr(s, "jscr"))
66 return eScriptJS;
67 if (strstr(s, "php"))
68 return eScriptPHP;
69 if (strstr(s, "xml"))
70 return eScriptXML;
71
72 return prevValue;
73 }
74
75 static int PrintScriptingIndicatorOffset(Accessor &styler, unsigned int start, unsigned int end) {
76 int iResult = 0;
77 char s[100];
78 GetTextSegment(styler, start, end, s, sizeof(s));
79 if (0 == strncmp(s, "php", 3)) {
80 iResult = 3;
81 }
82
83 return iResult;
84 }
85
86 static script_type ScriptOfState(int state) {
87 if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
88 return eScriptPython;
89 } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
90 return eScriptVBS;
91 } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
92 return eScriptJS;
93 } else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) {
94 return eScriptPHP;
95 } else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) {
96 return eScriptSGML;
97 } else if (state == SCE_H_SGML_BLOCK_DEFAULT) {
98 return eScriptSGMLblock;
99 } else {
100 return eScriptNone;
101 }
102 }
103
104 static int statePrintForState(int state, script_mode inScriptType) {
105 int StateToPrint;
106
107 if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
108 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON);
109 } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
110 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS);
111 } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
112 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS);
113 } else {
114 StateToPrint = state;
115 }
116
117 return StateToPrint;
118 }
119
120 static int stateForPrintState(int StateToPrint) {
121 int state;
122
123 if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) {
124 state = StateToPrint - SCE_HA_PYTHON;
125 } else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) {
126 state = StateToPrint - SCE_HA_VBS;
127 } else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) {
128 state = StateToPrint - SCE_HA_JS;
129 } else {
130 state = StateToPrint;
131 }
132
133 return state;
134 }
135
136 static inline bool IsNumber(unsigned int start, Accessor &styler) {
137 return IsADigit(styler[start]) || (styler[start] == '.') ||
138 (styler[start] == '-') || (styler[start] == '#');
139 }
140
141 static inline bool isStringState(int state) {
142 bool bResult;
143
144 switch (state) {
145 case SCE_HJ_DOUBLESTRING:
146 case SCE_HJ_SINGLESTRING:
147 case SCE_HJA_DOUBLESTRING:
148 case SCE_HJA_SINGLESTRING:
149 case SCE_HB_STRING:
150 case SCE_HBA_STRING:
151 case SCE_HP_STRING:
152 case SCE_HPA_STRING:
153 case SCE_HPHP_HSTRING:
154 case SCE_HPHP_SIMPLESTRING:
155 case SCE_HPHP_HSTRING_VARIABLE:
156 case SCE_HPHP_COMPLEX_VARIABLE:
157 bResult = true;
158 break;
159 default :
160 bResult = false;
161 break;
162 }
163 return bResult;
164 }
165
166 // not really well done, since it's only comments that should lex the %> and <%
167 static inline bool isCommentASPState(int state) {
168 bool bResult;
169
170 switch (state) {
171 case SCE_HJ_COMMENT:
172 case SCE_HJ_COMMENTLINE:
173 case SCE_HJ_COMMENTDOC:
174 case SCE_HB_COMMENTLINE:
175 case SCE_HP_COMMENTLINE:
176 case SCE_HPHP_COMMENT:
177 case SCE_HPHP_COMMENTLINE:
178 bResult = true;
179 break;
180 default :
181 bResult = false;
182 break;
183 }
184 return bResult;
185 }
186
187 static void classifyAttribHTML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
188 bool wordIsNumber = IsNumber(start, styler);
189 char chAttr = SCE_H_ATTRIBUTEUNKNOWN;
190 if (wordIsNumber) {
191 chAttr = SCE_H_NUMBER;
192 } else {
193 char s[100];
194 GetTextSegment(styler, start, end, s, sizeof(s));
195 if (keywords.InList(s))
196 chAttr = SCE_H_ATTRIBUTE;
197 }
198 if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords)
199 // No keywords -> all are known
200 chAttr = SCE_H_ATTRIBUTE;
201 styler.ColourTo(end, chAttr);
202 }
203
204 static int classifyTagHTML(unsigned int start, unsigned int end,
205 WordList &keywords, Accessor &styler, bool &tagDontFold,
206 bool caseSensitive) {
207 char s[30 + 2];
208 // Copy after the '<'
209 unsigned int i = 0;
210 for (unsigned int cPos = start; cPos <= end && i < 30; cPos++) {
211 char ch = styler[cPos];
212 if ((ch != '<') && (ch != '/')) {
213 s[i++] = caseSensitive ? ch : static_cast<char>(MakeLowerCase(ch));
214 }
215 }
216
217 //The following is only a quick hack, to see if this whole thing would work
218 //we first need the tagname with a trailing space...
219 s[i] = ' ';
220 s[i+1] = '\0';
221
222 //...to find it in the list of no-container-tags
223 // (There are many more. We will need a keywordlist in the property file for this)
224 tagDontFold = (NULL != strstr("meta link img area br hr input ",s));
225
226 //now we can remove the trailing space
227 s[i] = '\0';
228
229 bool isScript = false;
230 char chAttr = SCE_H_TAGUNKNOWN;
231 if (s[0] == '!') {
232 chAttr = SCE_H_SGML_DEFAULT;
233 } else if (s[0] == '/') { // Closing tag
234 if (keywords.InList(s + 1))
235 chAttr = SCE_H_TAG;
236 } else {
237 if (keywords.InList(s)) {
238 chAttr = SCE_H_TAG;
239 isScript = 0 == strcmp(s, "script");
240 }
241 }
242 if ((chAttr == SCE_H_TAGUNKNOWN) && !keywords) {
243 // No keywords -> all are known
244 chAttr = SCE_H_TAG;
245 isScript = 0 == strcmp(s, "script");
246 }
247 styler.ColourTo(end, chAttr);
248 return isScript ? SCE_H_SCRIPT : chAttr;
249 }
250
251 static void classifyWordHTJS(unsigned int start, unsigned int end,
252 WordList &keywords, Accessor &styler, script_mode inScriptType) {
253 char chAttr = SCE_HJ_WORD;
254 bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.');
255 if (wordIsNumber)
256 chAttr = SCE_HJ_NUMBER;
257 else {
258 char s[30 + 1];
259 unsigned int i = 0;
260 for (; i < end - start + 1 && i < 30; i++) {
261 s[i] = styler[start + i];
262 }
263 s[i] = '\0';
264 if (keywords.InList(s))
265 chAttr = SCE_HJ_KEYWORD;
266 }
267 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
268 }
269
270 static int classifyWordHTVB(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, script_mode inScriptType) {
271 char chAttr = SCE_HB_IDENTIFIER;
272 bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.');
273 if (wordIsNumber)
274 chAttr = SCE_HB_NUMBER;
275 else {
276 char s[100];
277 GetTextSegment(styler, start, end, s, sizeof(s));
278 if (keywords.InList(s)) {
279 chAttr = SCE_HB_WORD;
280 if (strcmp(s, "rem") == 0)
281 chAttr = SCE_HB_COMMENTLINE;
282 }
283 }
284 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
285 if (chAttr == SCE_HB_COMMENTLINE)
286 return SCE_HB_COMMENTLINE;
287 else
288 return SCE_HB_DEFAULT;
289 }
290
291 static void classifyWordHTPy(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord, script_mode inScriptType) {
292 bool wordIsNumber = IsADigit(styler[start]);
293 char s[30 + 1];
294 unsigned int i = 0;
295 for (; i < end - start + 1 && i < 30; i++) {
296 s[i] = styler[start + i];
297 }
298 s[i] = '\0';
299 char chAttr = SCE_HP_IDENTIFIER;
300 if (0 == strcmp(prevWord, "class"))
301 chAttr = SCE_HP_CLASSNAME;
302 else if (0 == strcmp(prevWord, "def"))
303 chAttr = SCE_HP_DEFNAME;
304 else if (wordIsNumber)
305 chAttr = SCE_HP_NUMBER;
306 else if (keywords.InList(s))
307 chAttr = SCE_HP_WORD;
308 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
309 strcpy(prevWord, s);
310 }
311
312 // Update the word colour to default or keyword
313 // Called when in a PHP word
314 static void classifyWordHTPHP(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
315 char chAttr = SCE_HPHP_DEFAULT;
316 bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.' && start+1 <= end && IsADigit(styler[start+1]));
317 if (wordIsNumber)
318 chAttr = SCE_HPHP_NUMBER;
319 else {
320 char s[100];
321 GetTextSegment(styler, start, end, s, sizeof(s));
322 if (keywords.InList(s))
323 chAttr = SCE_HPHP_WORD;
324 }
325 styler.ColourTo(end, chAttr);
326 }
327
328 static bool isWordHSGML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
329 char s[30 + 1];
330 unsigned int i = 0;
331 for (; i < end - start + 1 && i < 30; i++) {
332 s[i] = styler[start + i];
333 }
334 s[i] = '\0';
335 return keywords.InList(s);
336 }
337
338 static bool isWordCdata(unsigned int start, unsigned int end, Accessor &styler) {
339 char s[30 + 1];
340 unsigned int i = 0;
341 for (; i < end - start + 1 && i < 30; i++) {
342 s[i] = styler[start + i];
343 }
344 s[i] = '\0';
345 return (0 == strcmp(s, "[CDATA["));
346 }
347
348 // Return the first state to reach when entering a scripting language
349 static int StateForScript(script_type scriptLanguage) {
350 int Result;
351 switch (scriptLanguage) {
352 case eScriptVBS:
353 Result = SCE_HB_START;
354 break;
355 case eScriptPython:
356 Result = SCE_HP_START;
357 break;
358 case eScriptPHP:
359 Result = SCE_HPHP_DEFAULT;
360 break;
361 case eScriptXML:
362 Result = SCE_H_TAGUNKNOWN;
363 break;
364 case eScriptSGML:
365 Result = SCE_H_SGML_DEFAULT;
366 break;
367 default :
368 Result = SCE_HJ_START;
369 break;
370 }
371 return Result;
372 }
373
374 static inline bool ishtmlwordchar(char ch) {
375 return !isascii(ch) ||
376 (isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#');
377 }
378
379 static inline bool issgmlwordchar(char ch) {
380 return !isascii(ch) ||
381 (isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '[');
382 }
383
384 static inline bool IsPhpWordStart(const unsigned char ch) {
385 return (isascii(ch) && (isalpha(ch) || (ch == '_'))) || (ch >= 0x7f);
386 }
387
388 static inline bool IsPhpWordChar(char ch) {
389 return IsADigit(ch) || IsPhpWordStart(ch);
390 }
391
392 static bool InTagState(int state) {
393 return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN ||
394 state == SCE_H_SCRIPT ||
395 state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN ||
396 state == SCE_H_NUMBER || state == SCE_H_OTHER ||
397 state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING;
398 }
399
400 static bool IsCommentState(const int state) {
401 return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT;
402 }
403
404 static bool IsScriptCommentState(const int state) {
405 return state == SCE_HJ_COMMENT || state == SCE_HJ_COMMENTLINE || state == SCE_HJA_COMMENT ||
406 state == SCE_HJA_COMMENTLINE || state == SCE_HB_COMMENTLINE || state == SCE_HBA_COMMENTLINE;
407 }
408
409 static bool isLineEnd(char ch) {
410 return ch == '\r' || ch == '\n';
411 }
412
413 static bool isOKBeforeRE(char ch) {
414 return (ch == '(') || (ch == '=') || (ch == ',');
415 }
416
417 static bool isPHPStringState(int state) {
418 return
419 (state == SCE_HPHP_HSTRING) ||
420 (state == SCE_HPHP_SIMPLESTRING) ||
421 (state == SCE_HPHP_HSTRING_VARIABLE) ||
422 (state == SCE_HPHP_COMPLEX_VARIABLE);
423 }
424
425 static int FindPhpStringDelimiter(char *phpStringDelimiter, const int phpStringDelimiterSize, int i, const int lengthDoc, Accessor &styler) {
426 int j;
427 while (i < lengthDoc && (styler[i] == ' ' || styler[i] == '\t'))
428 i++;
429 phpStringDelimiter[0] = '\n';
430 for (j = i; j < lengthDoc && styler[j] != '\n' && styler[j] != '\r'; j++) {
431 if (j - i < phpStringDelimiterSize - 2)
432 phpStringDelimiter[j-i+1] = styler[j];
433 else
434 i++;
435 }
436 phpStringDelimiter[j-i+1] = '\0';
437 return j;
438 }
439
440 static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
441 Accessor &styler) {
442 WordList &keywords = *keywordlists[0];
443 WordList &keywords2 = *keywordlists[1];
444 WordList &keywords3 = *keywordlists[2];
445 WordList &keywords4 = *keywordlists[3];
446 WordList &keywords5 = *keywordlists[4];
447 WordList &keywords6 = *keywordlists[5]; // SGML (DTD) keywords
448
449 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
450 styler.StartAt(startPos, STYLE_MAX);
451 char prevWord[200];
452 prevWord[0] = '\0';
453 char phpStringDelimiter[200]; // PHP is not limited in length, we are
454 phpStringDelimiter[0] = '\0';
455 int StateToPrint = initStyle;
456 int state = stateForPrintState(StateToPrint);
457
458 // If inside a tag, it may be a script tag, so reread from the start to ensure any language tags are seen
459 if (InTagState(state)) {
460 while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) {
461 startPos--;
462 length++;
463 }
464 state = SCE_H_DEFAULT;
465 }
466 // String can be heredoc, must find a delimiter first
467 while (startPos > 0 && isPHPStringState(state) && state != SCE_HPHP_SIMPLESTRING) {
468 startPos--;
469 length++;
470 state = styler.StyleAt(startPos);
471 }
472 styler.StartAt(startPos, STYLE_MAX);
473
474 int lineCurrent = styler.GetLine(startPos);
475 int lineState;
476 if (lineCurrent > 0) {
477 lineState = styler.GetLineState(lineCurrent);
478 } else {
479 // Default client and ASP scripting language is JavaScript
480 lineState = eScriptJS << 8;
481 lineState |= styler.GetPropertyInt("asp.default.language", eScriptJS) << 4;
482 }
483 script_mode inScriptType = script_mode((lineState >> 0) & 0x03); // 2 bits of scripting mode
484 bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag
485 bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag
486 bool tagDontFold = false; //some HTML tags should not be folded
487 script_type aspScript = script_type((lineState >> 4) & 0x0F); // 4 bits of script name
488 script_type clientScript = script_type((lineState >> 8) & 0x0F); // 4 bits of script name
489 int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state
490
491 script_type scriptLanguage = ScriptOfState(state);
492
493 const bool foldHTML = styler.GetPropertyInt("fold.html", 0) != 0;
494 const bool fold = foldHTML && styler.GetPropertyInt("fold", 0);
495 const bool foldHTMLPreprocessor = foldHTML && styler.GetPropertyInt("fold.html.preprocessor", 1);
496 const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
497 const bool caseSensitive = styler.GetPropertyInt("html.tags.case.sensitive", 0) != 0;
498
499 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
500 int levelCurrent = levelPrev;
501 int visibleChars = 0;
502
503 char chPrev = ' ';
504 char ch = ' ';
505 char chPrevNonWhite = ' ';
506 // look back to set chPrevNonWhite properly for better regex colouring
507 if (scriptLanguage == eScriptJS && startPos > 0) {
508 int back = startPos;
509 int style = 0;
510 while (--back) {
511 style = styler.StyleAt(back);
512 if (style < SCE_HJ_DEFAULT || style > SCE_HJ_COMMENTDOC)
513 // includes SCE_HJ_COMMENT & SCE_HJ_COMMENTLINE
514 break;
515 }
516 if (style == SCE_HJ_SYMBOLS) {
517 chPrevNonWhite = styler.SafeGetCharAt(back);
518 }
519 }
520
521 styler.StartSegment(startPos);
522 const int lengthDoc = startPos + length;
523 for (int i = startPos; i < lengthDoc; i++) {
524 const char chPrev2 = chPrev;
525 chPrev = ch;
526 if (!isspacechar(ch) && state != SCE_HJ_COMMENT &&
527 state != SCE_HJ_COMMENTLINE && state != SCE_HJ_COMMENTDOC)
528 chPrevNonWhite = ch;
529 ch = styler[i];
530 char chNext = styler.SafeGetCharAt(i + 1);
531 const char chNext2 = styler.SafeGetCharAt(i + 2);
532
533 // Handle DBCS codepages
534 if (styler.IsLeadByte(ch)) {
535 chPrev = ' ';
536 i += 1;
537 continue;
538 }
539
540 if ((!isspacechar(ch) || !foldCompact) && fold)
541 visibleChars++;
542
543 // decide what is the current state to print (depending of the script tag)
544 StateToPrint = statePrintForState(state, inScriptType);
545
546 // handle script folding
547 if (fold) {
548 switch (scriptLanguage) {
549 case eScriptJS:
550 case eScriptPHP:
551 //not currently supported case eScriptVBS:
552
553 if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) {
554 //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle);
555 //if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) {
556 if ((ch == '{') || (ch == '}')) {
557 levelCurrent += (ch == '{') ? 1 : -1;
558 }
559 }
560 break;
561 case eScriptPython:
562 if (state != SCE_HP_COMMENTLINE) {
563 if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) {
564 levelCurrent++;
565 } else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) {
566 // check if the number of tabs is lower than the level
567 int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8;
568 for (int j = 0; Findlevel > 0; j++) {
569 char chTmp = styler.SafeGetCharAt(i + j + 1);
570 if (chTmp == '\t') {
571 Findlevel -= 8;
572 } else if (chTmp == ' ') {
573 Findlevel--;
574 } else {
575 break;
576 }
577 }
578
579 if (Findlevel > 0) {
580 levelCurrent -= Findlevel / 8;
581 if (Findlevel % 8)
582 levelCurrent--;
583 }
584 }
585 }
586 break;
587 default:
588 break;
589 }
590 }
591
592 if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
593 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
594 // Avoid triggering two times on Dos/Win
595 // New line -> record any line state onto /next/ line
596 if (fold) {
597 int lev = levelPrev;
598 if (visibleChars == 0)
599 lev |= SC_FOLDLEVELWHITEFLAG;
600 if ((levelCurrent > levelPrev) && (visibleChars > 0))
601 lev |= SC_FOLDLEVELHEADERFLAG;
602
603 styler.SetLevel(lineCurrent, lev);
604 visibleChars = 0;
605 levelPrev = levelCurrent;
606 }
607 lineCurrent++;
608 styler.SetLineState(lineCurrent,
609 ((inScriptType & 0x03) << 0) |
610 ((tagOpened & 0x01) << 2) |
611 ((tagClosing & 0x01) << 3) |
612 ((aspScript & 0x0F) << 4) |
613 ((clientScript & 0x0F) << 8) |
614 ((beforePreProc & 0xFF) << 12));
615 }
616
617 // generic end of script processing
618 else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) {
619 // Check if it's the end of the script tag (or any other HTML tag)
620 switch (state) {
621 // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!)
622 case SCE_H_DOUBLESTRING:
623 case SCE_H_SINGLESTRING:
624 case SCE_HJ_COMMENT:
625 case SCE_HJ_COMMENTDOC:
626 //case SCE_HJ_COMMENTLINE: // removed as this is a common thing done to hide
627 // the end of script marker from some JS interpreters.
628 case SCE_HJ_DOUBLESTRING:
629 case SCE_HJ_SINGLESTRING:
630 case SCE_HJ_REGEX:
631 case SCE_HB_STRING:
632 case SCE_HP_STRING:
633 case SCE_HP_TRIPLE:
634 case SCE_HP_TRIPLEDOUBLE:
635 break;
636 default :
637 // check if the closing tag is a script tag
638 if (state == SCE_HJ_COMMENTLINE) {
639 char tag[7]; // room for the <script> tag
640 char chr; // current char
641 int j=0;
642 chr = styler.SafeGetCharAt(i+2);
643 while (j < 6 && !isspacechar(chr)) {
644 tag[j++] = static_cast<char>(MakeLowerCase(chr));
645 chr = styler.SafeGetCharAt(i+2+j);
646 }
647 tag[j] = '\0';
648 if (strcmp(tag, "script") != 0) break;
649 }
650 // closing tag of the script (it's a closing HTML tag anyway)
651 styler.ColourTo(i - 1, StateToPrint);
652 state = SCE_H_TAGUNKNOWN;
653 inScriptType = eHtml;
654 scriptLanguage = eScriptNone;
655 clientScript = eScriptJS;
656 i += 2;
657 visibleChars += 2;
658 tagClosing = true;
659 continue;
660 }
661 }
662
663 /////////////////////////////////////
664 // handle the start of PHP pre-processor = Non-HTML
665 else if ((state != SCE_H_ASPAT) &&
666 !isPHPStringState(state) &&
667 (state != SCE_HPHP_COMMENT) &&
668 (ch == '<') &&
669 (chNext == '?') &&
670 !IsScriptCommentState(state) ) {
671 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment() + 2, i + 10, eScriptPHP);
672 if (scriptLanguage != eScriptPHP && isStringState(state)) continue;
673 styler.ColourTo(i - 1, StateToPrint);
674 beforePreProc = state;
675 i++;
676 visibleChars++;
677 i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 10);
678 if (scriptLanguage == eScriptXML)
679 styler.ColourTo(i, SCE_H_XMLSTART);
680 else
681 styler.ColourTo(i, SCE_H_QUESTION);
682 state = StateForScript(scriptLanguage);
683 if (inScriptType == eNonHtmlScript)
684 inScriptType = eNonHtmlScriptPreProc;
685 else
686 inScriptType = eNonHtmlPreProc;
687 // Fold whole script, but not if the XML first tag (all XML-like tags in this case)
688 if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) {
689 levelCurrent++;
690 }
691 // should be better
692 ch = styler.SafeGetCharAt(i);
693 continue;
694 }
695
696 // handle the start of ASP pre-processor = Non-HTML
697 else if (!isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) {
698 styler.ColourTo(i - 1, StateToPrint);
699 beforePreProc = state;
700 if (inScriptType == eNonHtmlScript)
701 inScriptType = eNonHtmlScriptPreProc;
702 else
703 inScriptType = eNonHtmlPreProc;
704
705 if (chNext2 == '@') {
706 i += 2; // place as if it was the second next char treated
707 visibleChars += 2;
708 state = SCE_H_ASPAT;
709 } else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) {
710 styler.ColourTo(i + 3, SCE_H_ASP);
711 state = SCE_H_XCCOMMENT;
712 scriptLanguage = eScriptVBS;
713 continue;
714 } else {
715 if (chNext2 == '=') {
716 i += 2; // place as if it was the second next char treated
717 visibleChars += 2;
718 } else {
719 i++; // place as if it was the next char treated
720 visibleChars++;
721 }
722
723 state = StateForScript(aspScript);
724 }
725 scriptLanguage = eScriptVBS;
726 styler.ColourTo(i, SCE_H_ASP);
727 // fold whole script
728 if (foldHTMLPreprocessor)
729 levelCurrent++;
730 // should be better
731 ch = styler.SafeGetCharAt(i);
732 continue;
733 }
734
735 /////////////////////////////////////
736 // handle the start of SGML language (DTD)
737 else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) &&
738 (chPrev == '<') &&
739 (ch == '!') &&
740 (StateToPrint != SCE_H_CDATA) &&
741 (!IsCommentState(StateToPrint)) &&
742 (!IsScriptCommentState(StateToPrint)) ) {
743 beforePreProc = state;
744 styler.ColourTo(i - 2, StateToPrint);
745 if ((chNext == '-') && (chNext2 == '-')) {
746 state = SCE_H_COMMENT; // wait for a pending command
747 styler.ColourTo(i + 2, SCE_H_COMMENT);
748 i += 2; // follow styling after the --
749 } else if (isWordCdata(i + 1, i + 7, styler)) {
750 state = SCE_H_CDATA;
751 } else {
752 styler.ColourTo(i, SCE_H_SGML_DEFAULT); // <! is default
753 scriptLanguage = eScriptSGML;
754 state = SCE_H_SGML_COMMAND; // wait for a pending command
755 }
756 // fold whole tag (-- when closing the tag)
757 if (foldHTMLPreprocessor)
758 levelCurrent++;
759 continue;
760 }
761
762 // handle the end of a pre-processor = Non-HTML
763 else if ((
764 ((inScriptType == eNonHtmlPreProc)
765 || (inScriptType == eNonHtmlScriptPreProc)) && (
766 ((scriptLanguage == eScriptPHP) && (ch == '?') && !isPHPStringState(state) && (state != SCE_HPHP_COMMENT)) ||
767 ((scriptLanguage != eScriptNone) && !isStringState(state) &&
768 ((ch == '%') || (ch == '?')))
769 ) && (chNext == '>')) ||
770 ((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) {
771 if (state == SCE_H_ASPAT) {
772 aspScript = segIsScriptingIndicator(styler,
773 styler.GetStartSegment(), i - 1, aspScript);
774 }
775 // Bounce out of any ASP mode
776 switch (state) {
777 case SCE_HJ_WORD:
778 classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
779 break;
780 case SCE_HB_WORD:
781 classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
782 break;
783 case SCE_HP_WORD:
784 classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType);
785 break;
786 case SCE_HPHP_WORD:
787 classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
788 break;
789 case SCE_H_XCCOMMENT:
790 styler.ColourTo(i - 1, state);
791 break;
792 default :
793 styler.ColourTo(i - 1, StateToPrint);
794 break;
795 }
796 if (scriptLanguage != eScriptSGML) {
797 i++;
798 visibleChars++;
799 }
800 if (ch == '%')
801 styler.ColourTo(i, SCE_H_ASP);
802 else if (scriptLanguage == eScriptXML)
803 styler.ColourTo(i, SCE_H_XMLEND);
804 else if (scriptLanguage == eScriptSGML)
805 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
806 else
807 styler.ColourTo(i, SCE_H_QUESTION);
808 state = beforePreProc;
809 if (inScriptType == eNonHtmlScriptPreProc)
810 inScriptType = eNonHtmlScript;
811 else
812 inScriptType = eHtml;
813 // Unfold all scripting languages, except for XML tag
814 if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) {
815 levelCurrent--;
816 }
817 scriptLanguage = eScriptNone;
818 continue;
819 }
820 /////////////////////////////////////
821
822 switch (state) {
823 case SCE_H_DEFAULT:
824 if (ch == '<') {
825 // in HTML, fold on tag open and unfold on tag close
826 tagOpened = true;
827 tagClosing = (chNext == '/');
828 styler.ColourTo(i - 1, StateToPrint);
829 if (chNext != '!')
830 state = SCE_H_TAGUNKNOWN;
831 } else if (ch == '&') {
832 styler.ColourTo(i - 1, SCE_H_DEFAULT);
833 state = SCE_H_ENTITY;
834 }
835 break;
836 case SCE_H_SGML_DEFAULT:
837 case SCE_H_SGML_BLOCK_DEFAULT:
838 // if (scriptLanguage == eScriptSGMLblock)
839 // StateToPrint = SCE_H_SGML_BLOCK_DEFAULT;
840
841 if (ch == '\"') {
842 styler.ColourTo(i - 1, StateToPrint);
843 state = SCE_H_SGML_DOUBLESTRING;
844 } else if (ch == '\'') {
845 styler.ColourTo(i - 1, StateToPrint);
846 state = SCE_H_SGML_SIMPLESTRING;
847 } else if ((ch == '-') && (chPrev == '-')) {
848 styler.ColourTo(i - 2, StateToPrint);
849 state = SCE_H_SGML_COMMENT;
850 } else if (isascii(ch) && isalpha(ch) && (chPrev == '%')) {
851 styler.ColourTo(i - 2, StateToPrint);
852 state = SCE_H_SGML_ENTITY;
853 } else if (ch == '#') {
854 styler.ColourTo(i - 1, StateToPrint);
855 state = SCE_H_SGML_SPECIAL;
856 } else if (ch == '[') {
857 styler.ColourTo(i - 1, StateToPrint);
858 scriptLanguage = eScriptSGMLblock;
859 state = SCE_H_SGML_BLOCK_DEFAULT;
860 } else if (ch == ']') {
861 if (scriptLanguage == eScriptSGMLblock) {
862 styler.ColourTo(i, StateToPrint);
863 scriptLanguage = eScriptSGML;
864 } else {
865 styler.ColourTo(i - 1, StateToPrint);
866 styler.ColourTo(i, SCE_H_SGML_ERROR);
867 }
868 state = SCE_H_SGML_DEFAULT;
869 } else if (scriptLanguage == eScriptSGMLblock) {
870 if ((ch == '!') && (chPrev == '<')) {
871 styler.ColourTo(i - 2, StateToPrint);
872 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
873 state = SCE_H_SGML_COMMAND;
874 } else if (ch == '>') {
875 styler.ColourTo(i - 1, StateToPrint);
876 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
877 }
878 }
879 break;
880 case SCE_H_SGML_COMMAND:
881 if ((ch == '-') && (chPrev == '-')) {
882 styler.ColourTo(i - 2, StateToPrint);
883 state = SCE_H_SGML_COMMENT;
884 } else if (!issgmlwordchar(ch)) {
885 if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) {
886 styler.ColourTo(i - 1, StateToPrint);
887 state = SCE_H_SGML_1ST_PARAM;
888 } else {
889 state = SCE_H_SGML_ERROR;
890 }
891 }
892 break;
893 case SCE_H_SGML_1ST_PARAM:
894 // wait for the beginning of the word
895 if ((ch == '-') && (chPrev == '-')) {
896 if (scriptLanguage == eScriptSGMLblock) {
897 styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT);
898 } else {
899 styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT);
900 }
901 state = SCE_H_SGML_1ST_PARAM_COMMENT;
902 } else if (issgmlwordchar(ch)) {
903 if (scriptLanguage == eScriptSGMLblock) {
904 styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT);
905 } else {
906 styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT);
907 }
908 // find the length of the word
909 int size = 1;
910 while (ishtmlwordchar(styler.SafeGetCharAt(i + size)))
911 size++;
912 styler.ColourTo(i + size - 1, StateToPrint);
913 i += size - 1;
914 visibleChars += size - 1;
915 ch = styler.SafeGetCharAt(i);
916 if (scriptLanguage == eScriptSGMLblock) {
917 state = SCE_H_SGML_BLOCK_DEFAULT;
918 } else {
919 state = SCE_H_SGML_DEFAULT;
920 }
921 continue;
922 }
923 break;
924 case SCE_H_SGML_ERROR:
925 if ((ch == '-') && (chPrev == '-')) {
926 styler.ColourTo(i - 2, StateToPrint);
927 state = SCE_H_SGML_COMMENT;
928 }
929 case SCE_H_SGML_DOUBLESTRING:
930 if (ch == '\"') {
931 styler.ColourTo(i, StateToPrint);
932 state = SCE_H_SGML_DEFAULT;
933 }
934 break;
935 case SCE_H_SGML_SIMPLESTRING:
936 if (ch == '\'') {
937 styler.ColourTo(i, StateToPrint);
938 state = SCE_H_SGML_DEFAULT;
939 }
940 break;
941 case SCE_H_SGML_COMMENT:
942 if ((ch == '-') && (chPrev == '-')) {
943 styler.ColourTo(i, StateToPrint);
944 state = SCE_H_SGML_DEFAULT;
945 }
946 break;
947 case SCE_H_CDATA:
948 if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) {
949 styler.ColourTo(i, StateToPrint);
950 state = SCE_H_DEFAULT;
951 levelCurrent--;
952 }
953 break;
954 case SCE_H_COMMENT:
955 if ((chPrev2 == '-') && (chPrev == '-') && (ch == '>')) {
956 styler.ColourTo(i, StateToPrint);
957 state = SCE_H_DEFAULT;
958 levelCurrent--;
959 }
960 break;
961 case SCE_H_SGML_1ST_PARAM_COMMENT:
962 if ((ch == '-') && (chPrev == '-')) {
963 styler.ColourTo(i, SCE_H_SGML_COMMENT);
964 state = SCE_H_SGML_1ST_PARAM;
965 }
966 break;
967 case SCE_H_SGML_SPECIAL:
968 if (!(isascii(ch) && isupper(ch))) {
969 styler.ColourTo(i - 1, StateToPrint);
970 if (isalnum(ch)) {
971 state = SCE_H_SGML_ERROR;
972 } else {
973 state = SCE_H_SGML_DEFAULT;
974 }
975 }
976 break;
977 case SCE_H_SGML_ENTITY:
978 if (ch == ';') {
979 styler.ColourTo(i, StateToPrint);
980 state = SCE_H_SGML_DEFAULT;
981 } else if (!(isascii(ch) && isalnum(ch)) && ch != '-' && ch != '.') {
982 styler.ColourTo(i, SCE_H_SGML_ERROR);
983 state = SCE_H_SGML_DEFAULT;
984 }
985 break;
986 case SCE_H_ENTITY:
987 if (ch == ';') {
988 styler.ColourTo(i, StateToPrint);
989 state = SCE_H_DEFAULT;
990 }
991 if (ch != '#' && !(isascii(ch) && isalnum(ch)) // Should check that '#' follows '&', but it is unlikely anyway...
992 && ch != '.' && ch != '-' && ch != '_' && ch != ':') { // valid in XML
993 styler.ColourTo(i, SCE_H_TAGUNKNOWN);
994 state = SCE_H_DEFAULT;
995 }
996 break;
997 case SCE_H_TAGUNKNOWN:
998 if (!ishtmlwordchar(ch) && !((ch == '/') && (chPrev == '<')) && ch != '[') {
999 int eClass = classifyTagHTML(styler.GetStartSegment(),
1000 i - 1, keywords, styler, tagDontFold, caseSensitive);
1001 if (eClass == SCE_H_SCRIPT) {
1002 if (!tagClosing) {
1003 inScriptType = eNonHtmlScript;
1004 scriptLanguage = clientScript;
1005 eClass = SCE_H_TAG;
1006 } else {
1007 scriptLanguage = eScriptNone;
1008 eClass = SCE_H_TAG;
1009 }
1010 }
1011 if (ch == '>') {
1012 styler.ColourTo(i, eClass);
1013 if (inScriptType == eNonHtmlScript) {
1014 state = StateForScript(scriptLanguage);
1015 } else {
1016 state = SCE_H_DEFAULT;
1017 }
1018 tagOpened = false;
1019 if (!tagDontFold){
1020 if (tagClosing) {
1021 levelCurrent--;
1022 } else {
1023 levelCurrent++;
1024 }
1025 }
1026 tagClosing = false;
1027 } else if (ch == '/' && chNext == '>') {
1028 if (eClass == SCE_H_TAGUNKNOWN) {
1029 styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN);
1030 } else {
1031 styler.ColourTo(i - 1, StateToPrint);
1032 styler.ColourTo(i + 1, SCE_H_TAGEND);
1033 }
1034 i++;
1035 ch = chNext;
1036 state = SCE_H_DEFAULT;
1037 tagOpened = false;
1038 } else {
1039 if (eClass != SCE_H_TAGUNKNOWN) {
1040 if (eClass == SCE_H_SGML_DEFAULT) {
1041 state = SCE_H_SGML_DEFAULT;
1042 } else {
1043 state = SCE_H_OTHER;
1044 }
1045 }
1046 }
1047 }
1048 break;
1049 case SCE_H_ATTRIBUTE:
1050 if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') {
1051 if (inScriptType == eNonHtmlScript) {
1052 int scriptLanguagePrev = scriptLanguage;
1053 clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage);
1054 scriptLanguage = clientScript;
1055 if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone))
1056 inScriptType = eHtml;
1057 }
1058 classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler);
1059 if (ch == '>') {
1060 styler.ColourTo(i, SCE_H_TAG);
1061 if (inScriptType == eNonHtmlScript) {
1062 state = StateForScript(scriptLanguage);
1063 } else {
1064 state = SCE_H_DEFAULT;
1065 }
1066 tagOpened = false;
1067 if (!tagDontFold){
1068 if (tagClosing){
1069 levelCurrent--;
1070 } else {
1071 levelCurrent++;
1072 }
1073 }
1074 tagClosing = false;
1075 } else if (ch == '=') {
1076 styler.ColourTo(i, SCE_H_OTHER);
1077 state = SCE_H_VALUE;
1078 } else {
1079 state = SCE_H_OTHER;
1080 }
1081 }
1082 break;
1083 case SCE_H_OTHER:
1084 if (ch == '>') {
1085 styler.ColourTo(i - 1, StateToPrint);
1086 styler.ColourTo(i, SCE_H_TAG);
1087 if (inScriptType == eNonHtmlScript) {
1088 state = StateForScript(scriptLanguage);
1089 } else {
1090 state = SCE_H_DEFAULT;
1091 }
1092 tagOpened = false;
1093 if (!tagDontFold){
1094 if (tagClosing){
1095 levelCurrent--;
1096 } else {
1097 levelCurrent++;
1098 }
1099 }
1100 tagClosing = false;
1101 } else if (ch == '\"') {
1102 styler.ColourTo(i - 1, StateToPrint);
1103 state = SCE_H_DOUBLESTRING;
1104 } else if (ch == '\'') {
1105 styler.ColourTo(i - 1, StateToPrint);
1106 state = SCE_H_SINGLESTRING;
1107 } else if (ch == '=') {
1108 styler.ColourTo(i, StateToPrint);
1109 state = SCE_H_VALUE;
1110 } else if (ch == '/' && chNext == '>') {
1111 styler.ColourTo(i - 1, StateToPrint);
1112 styler.ColourTo(i + 1, SCE_H_TAGEND);
1113 i++;
1114 ch = chNext;
1115 state = SCE_H_DEFAULT;
1116 tagOpened = false;
1117 } else if (ch == '?' && chNext == '>') {
1118 styler.ColourTo(i - 1, StateToPrint);
1119 styler.ColourTo(i + 1, SCE_H_XMLEND);
1120 i++;
1121 ch = chNext;
1122 state = SCE_H_DEFAULT;
1123 } else if (ishtmlwordchar(ch)) {
1124 styler.ColourTo(i - 1, StateToPrint);
1125 state = SCE_H_ATTRIBUTE;
1126 }
1127 break;
1128 case SCE_H_DOUBLESTRING:
1129 if (ch == '\"') {
1130 if (inScriptType == eNonHtmlScript) {
1131 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
1132 }
1133 styler.ColourTo(i, SCE_H_DOUBLESTRING);
1134 state = SCE_H_OTHER;
1135 }
1136 break;
1137 case SCE_H_SINGLESTRING:
1138 if (ch == '\'') {
1139 if (inScriptType == eNonHtmlScript) {
1140 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
1141 }
1142 styler.ColourTo(i, SCE_H_SINGLESTRING);
1143 state = SCE_H_OTHER;
1144 }
1145 break;
1146 case SCE_H_VALUE:
1147 if (!ishtmlwordchar(ch)) {
1148 if (ch == '\"' && chPrev == '=') {
1149 // Should really test for being first character
1150 state = SCE_H_DOUBLESTRING;
1151 } else if (ch == '\'' && chPrev == '=') {
1152 state = SCE_H_SINGLESTRING;
1153 } else {
1154 if (IsNumber(styler.GetStartSegment(), styler)) {
1155 styler.ColourTo(i - 1, SCE_H_NUMBER);
1156 } else {
1157 styler.ColourTo(i - 1, StateToPrint);
1158 }
1159 if (ch == '>') {
1160 styler.ColourTo(i, SCE_H_TAG);
1161 if (inScriptType == eNonHtmlScript) {
1162 state = StateForScript(scriptLanguage);
1163 } else {
1164 state = SCE_H_DEFAULT;
1165 }
1166 tagOpened = false;
1167 if (!tagDontFold){
1168 if (tagClosing){
1169 levelCurrent--;
1170 } else {
1171 levelCurrent++;
1172 }
1173 }
1174 tagClosing = false;
1175 } else {
1176 state = SCE_H_OTHER;
1177 }
1178 }
1179 }
1180 break;
1181 case SCE_HJ_DEFAULT:
1182 case SCE_HJ_START:
1183 case SCE_HJ_SYMBOLS:
1184 if (iswordstart(ch)) {
1185 styler.ColourTo(i - 1, StateToPrint);
1186 state = SCE_HJ_WORD;
1187 } else if (ch == '/' && chNext == '*') {
1188 styler.ColourTo(i - 1, StateToPrint);
1189 if (chNext2 == '*')
1190 state = SCE_HJ_COMMENTDOC;
1191 else
1192 state = SCE_HJ_COMMENT;
1193 } else if (ch == '/' && chNext == '/') {
1194 styler.ColourTo(i - 1, StateToPrint);
1195 state = SCE_HJ_COMMENTLINE;
1196 } else if (ch == '/' && isOKBeforeRE(chPrevNonWhite)) {
1197 styler.ColourTo(i - 1, StateToPrint);
1198 state = SCE_HJ_REGEX;
1199 } else if (ch == '\"') {
1200 styler.ColourTo(i - 1, StateToPrint);
1201 state = SCE_HJ_DOUBLESTRING;
1202 } else if (ch == '\'') {
1203 styler.ColourTo(i - 1, StateToPrint);
1204 state = SCE_HJ_SINGLESTRING;
1205 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1206 styler.SafeGetCharAt(i + 3) == '-') {
1207 styler.ColourTo(i - 1, StateToPrint);
1208 state = SCE_HJ_COMMENTLINE;
1209 } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1210 styler.ColourTo(i - 1, StateToPrint);
1211 state = SCE_HJ_COMMENTLINE;
1212 i += 2;
1213 } else if (isoperator(ch)) {
1214 styler.ColourTo(i - 1, StateToPrint);
1215 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1216 state = SCE_HJ_DEFAULT;
1217 } else if ((ch == ' ') || (ch == '\t')) {
1218 if (state == SCE_HJ_START) {
1219 styler.ColourTo(i - 1, StateToPrint);
1220 state = SCE_HJ_DEFAULT;
1221 }
1222 }
1223 break;
1224 case SCE_HJ_WORD:
1225 if (!iswordchar(ch)) {
1226 classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
1227 //styler.ColourTo(i - 1, eHTJSKeyword);
1228 state = SCE_HJ_DEFAULT;
1229 if (ch == '/' && chNext == '*') {
1230 if (chNext2 == '*')
1231 state = SCE_HJ_COMMENTDOC;
1232 else
1233 state = SCE_HJ_COMMENT;
1234 } else if (ch == '/' && chNext == '/') {
1235 state = SCE_HJ_COMMENTLINE;
1236 } else if (ch == '\"') {
1237 state = SCE_HJ_DOUBLESTRING;
1238 } else if (ch == '\'') {
1239 state = SCE_HJ_SINGLESTRING;
1240 } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1241 styler.ColourTo(i - 1, StateToPrint);
1242 state = SCE_HJ_COMMENTLINE;
1243 i += 2;
1244 } else if (isoperator(ch)) {
1245 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1246 state = SCE_HJ_DEFAULT;
1247 }
1248 }
1249 break;
1250 case SCE_HJ_COMMENT:
1251 case SCE_HJ_COMMENTDOC:
1252 if (ch == '/' && chPrev == '*') {
1253 styler.ColourTo(i, StateToPrint);
1254 state = SCE_HJ_DEFAULT;
1255 ch = ' ';
1256 }
1257 break;
1258 case SCE_HJ_COMMENTLINE:
1259 if (ch == '\r' || ch == '\n') {
1260 styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType));
1261 state = SCE_HJ_DEFAULT;
1262 ch = ' ';
1263 }
1264 break;
1265 case SCE_HJ_DOUBLESTRING:
1266 if (ch == '\\') {
1267 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1268 i++;
1269 }
1270 } else if (ch == '\"') {
1271 styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType));
1272 state = SCE_HJ_DEFAULT;
1273 } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1274 styler.ColourTo(i - 1, StateToPrint);
1275 state = SCE_HJ_COMMENTLINE;
1276 i += 2;
1277 } else if (isLineEnd(ch)) {
1278 styler.ColourTo(i - 1, StateToPrint);
1279 state = SCE_HJ_STRINGEOL;
1280 }
1281 break;
1282 case SCE_HJ_SINGLESTRING:
1283 if (ch == '\\') {
1284 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1285 i++;
1286 }
1287 } else if (ch == '\'') {
1288 styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType));
1289 state = SCE_HJ_DEFAULT;
1290 } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1291 styler.ColourTo(i - 1, StateToPrint);
1292 state = SCE_HJ_COMMENTLINE;
1293 i += 2;
1294 } else if (isLineEnd(ch)) {
1295 styler.ColourTo(i - 1, StateToPrint);
1296 state = SCE_HJ_STRINGEOL;
1297 }
1298 break;
1299 case SCE_HJ_STRINGEOL:
1300 if (!isLineEnd(ch)) {
1301 styler.ColourTo(i - 1, StateToPrint);
1302 state = SCE_HJ_DEFAULT;
1303 } else if (!isLineEnd(chNext)) {
1304 styler.ColourTo(i, StateToPrint);
1305 state = SCE_HJ_DEFAULT;
1306 }
1307 break;
1308 case SCE_HJ_REGEX:
1309 if (ch == '\r' || ch == '\n' || ch == '/') {
1310 if (ch == '/') {
1311 while (isascii(chNext) && islower(chNext)) { // gobble regex flags
1312 i++;
1313 ch = chNext;
1314 chNext = styler.SafeGetCharAt(i + 1);
1315 }
1316 }
1317 styler.ColourTo(i, StateToPrint);
1318 state = SCE_HJ_DEFAULT;
1319 } else if (ch == '\\') {
1320 // Gobble up the quoted character
1321 if (chNext == '\\' || chNext == '/') {
1322 i++;
1323 ch = chNext;
1324 chNext = styler.SafeGetCharAt(i + 1);
1325 }
1326 }
1327 break;
1328 case SCE_HB_DEFAULT:
1329 case SCE_HB_START:
1330 if (iswordstart(ch)) {
1331 styler.ColourTo(i - 1, StateToPrint);
1332 state = SCE_HB_WORD;
1333 } else if (ch == '\'') {
1334 styler.ColourTo(i - 1, StateToPrint);
1335 state = SCE_HB_COMMENTLINE;
1336 } else if (ch == '\"') {
1337 styler.ColourTo(i - 1, StateToPrint);
1338 state = SCE_HB_STRING;
1339 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1340 styler.SafeGetCharAt(i + 3) == '-') {
1341 styler.ColourTo(i - 1, StateToPrint);
1342 state = SCE_HB_COMMENTLINE;
1343 } else if (isoperator(ch)) {
1344 styler.ColourTo(i - 1, StateToPrint);
1345 styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
1346 state = SCE_HB_DEFAULT;
1347 } else if ((ch == ' ') || (ch == '\t')) {
1348 if (state == SCE_HB_START) {
1349 styler.ColourTo(i - 1, StateToPrint);
1350 state = SCE_HB_DEFAULT;
1351 }
1352 }
1353 break;
1354 case SCE_HB_WORD:
1355 if (!iswordchar(ch)) {
1356 state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
1357 if (state == SCE_HB_DEFAULT) {
1358 if (ch == '\"') {
1359 state = SCE_HB_STRING;
1360 } else if (ch == '\'') {
1361 state = SCE_HB_COMMENTLINE;
1362 } else if (isoperator(ch)) {
1363 styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
1364 state = SCE_HB_DEFAULT;
1365 }
1366 }
1367 }
1368 break;
1369 case SCE_HB_STRING:
1370 if (ch == '\"') {
1371 styler.ColourTo(i, StateToPrint);
1372 state = SCE_HB_DEFAULT;
1373 } else if (ch == '\r' || ch == '\n') {
1374 styler.ColourTo(i - 1, StateToPrint);
1375 state = SCE_HB_STRINGEOL;
1376 }
1377 break;
1378 case SCE_HB_COMMENTLINE:
1379 if (ch == '\r' || ch == '\n') {
1380 styler.ColourTo(i - 1, StateToPrint);
1381 state = SCE_HB_DEFAULT;
1382 }
1383 break;
1384 case SCE_HB_STRINGEOL:
1385 if (!isLineEnd(ch)) {
1386 styler.ColourTo(i - 1, StateToPrint);
1387 state = SCE_HB_DEFAULT;
1388 } else if (!isLineEnd(chNext)) {
1389 styler.ColourTo(i, StateToPrint);
1390 state = SCE_HB_DEFAULT;
1391 }
1392 break;
1393 case SCE_HP_DEFAULT:
1394 case SCE_HP_START:
1395 if (iswordstart(ch)) {
1396 styler.ColourTo(i - 1, StateToPrint);
1397 state = SCE_HP_WORD;
1398 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1399 styler.SafeGetCharAt(i + 3) == '-') {
1400 styler.ColourTo(i - 1, StateToPrint);
1401 state = SCE_HP_COMMENTLINE;
1402 } else if (ch == '#') {
1403 styler.ColourTo(i - 1, StateToPrint);
1404 state = SCE_HP_COMMENTLINE;
1405 } else if (ch == '\"') {
1406 styler.ColourTo(i - 1, StateToPrint);
1407 if (chNext == '\"' && chNext2 == '\"') {
1408 i += 2;
1409 state = SCE_HP_TRIPLEDOUBLE;
1410 ch = ' ';
1411 chPrev = ' ';
1412 chNext = styler.SafeGetCharAt(i + 1);
1413 } else {
1414 // state = statePrintForState(SCE_HP_STRING,inScriptType);
1415 state = SCE_HP_STRING;
1416 }
1417 } else if (ch == '\'') {
1418 styler.ColourTo(i - 1, StateToPrint);
1419 if (chNext == '\'' && chNext2 == '\'') {
1420 i += 2;
1421 state = SCE_HP_TRIPLE;
1422 ch = ' ';
1423 chPrev = ' ';
1424 chNext = styler.SafeGetCharAt(i + 1);
1425 } else {
1426 state = SCE_HP_CHARACTER;
1427 }
1428 } else if (isoperator(ch)) {
1429 styler.ColourTo(i - 1, StateToPrint);
1430 styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
1431 } else if ((ch == ' ') || (ch == '\t')) {
1432 if (state == SCE_HP_START) {
1433 styler.ColourTo(i - 1, StateToPrint);
1434 state = SCE_HP_DEFAULT;
1435 }
1436 }
1437 break;
1438 case SCE_HP_WORD:
1439 if (!iswordchar(ch)) {
1440 classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType);
1441 state = SCE_HP_DEFAULT;
1442 if (ch == '#') {
1443 state = SCE_HP_COMMENTLINE;
1444 } else if (ch == '\"') {
1445 if (chNext == '\"' && chNext2 == '\"') {
1446 i += 2;
1447 state = SCE_HP_TRIPLEDOUBLE;
1448 ch = ' ';
1449 chPrev = ' ';
1450 chNext = styler.SafeGetCharAt(i + 1);
1451 } else {
1452 state = SCE_HP_STRING;
1453 }
1454 } else if (ch == '\'') {
1455 if (chNext == '\'' && chNext2 == '\'') {
1456 i += 2;
1457 state = SCE_HP_TRIPLE;
1458 ch = ' ';
1459 chPrev = ' ';
1460 chNext = styler.SafeGetCharAt(i + 1);
1461 } else {
1462 state = SCE_HP_CHARACTER;
1463 }
1464 } else if (isoperator(ch)) {
1465 styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
1466 }
1467 }
1468 break;
1469 case SCE_HP_COMMENTLINE:
1470 if (ch == '\r' || ch == '\n') {
1471 styler.ColourTo(i - 1, StateToPrint);
1472 state = SCE_HP_DEFAULT;
1473 }
1474 break;
1475 case SCE_HP_STRING:
1476 if (ch == '\\') {
1477 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1478 i++;
1479 ch = chNext;
1480 chNext = styler.SafeGetCharAt(i + 1);
1481 }
1482 } else if (ch == '\"') {
1483 styler.ColourTo(i, StateToPrint);
1484 state = SCE_HP_DEFAULT;
1485 }
1486 break;
1487 case SCE_HP_CHARACTER:
1488 if (ch == '\\') {
1489 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1490 i++;
1491 ch = chNext;
1492 chNext = styler.SafeGetCharAt(i + 1);
1493 }
1494 } else if (ch == '\'') {
1495 styler.ColourTo(i, StateToPrint);
1496 state = SCE_HP_DEFAULT;
1497 }
1498 break;
1499 case SCE_HP_TRIPLE:
1500 if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') {
1501 styler.ColourTo(i, StateToPrint);
1502 state = SCE_HP_DEFAULT;
1503 }
1504 break;
1505 case SCE_HP_TRIPLEDOUBLE:
1506 if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') {
1507 styler.ColourTo(i, StateToPrint);
1508 state = SCE_HP_DEFAULT;
1509 }
1510 break;
1511 ///////////// start - PHP state handling
1512 case SCE_HPHP_WORD:
1513 if (!iswordchar(ch)) {
1514 classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
1515 if (ch == '/' && chNext == '*') {
1516 i++;
1517 state = SCE_HPHP_COMMENT;
1518 } else if (ch == '/' && chNext == '/') {
1519 i++;
1520 state = SCE_HPHP_COMMENTLINE;
1521 } else if (ch == '#') {
1522 state = SCE_HPHP_COMMENTLINE;
1523 } else if (ch == '\"') {
1524 state = SCE_HPHP_HSTRING;
1525 strcpy(phpStringDelimiter, "\"");
1526 } else if (styler.Match(i, "<<<")) {
1527 state = SCE_HPHP_HSTRING;
1528 i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler);
1529 } else if (ch == '\'') {
1530 state = SCE_HPHP_SIMPLESTRING;
1531 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1532 state = SCE_HPHP_VARIABLE;
1533 } else if (isoperator(ch)) {
1534 state = SCE_HPHP_OPERATOR;
1535 } else {
1536 state = SCE_HPHP_DEFAULT;
1537 }
1538 }
1539 break;
1540 case SCE_HPHP_NUMBER:
1541 // recognize bases 8,10 or 16 integers OR floating-point numbers
1542 if (!IsADigit(ch)
1543 && strchr(".xXabcdefABCDEF", ch) == NULL
1544 && ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) {
1545 styler.ColourTo(i - 1, SCE_HPHP_NUMBER);
1546 if (isoperator(ch))
1547 state = SCE_HPHP_OPERATOR;
1548 else
1549 state = SCE_HPHP_DEFAULT;
1550 }
1551 break;
1552 case SCE_HPHP_VARIABLE:
1553 if (!IsPhpWordChar(ch)) {
1554 styler.ColourTo(i - 1, SCE_HPHP_VARIABLE);
1555 if (isoperator(ch))
1556 state = SCE_HPHP_OPERATOR;
1557 else
1558 state = SCE_HPHP_DEFAULT;
1559 }
1560 break;
1561 case SCE_HPHP_COMMENT:
1562 if (ch == '/' && chPrev == '*') {
1563 styler.ColourTo(i, StateToPrint);
1564 state = SCE_HPHP_DEFAULT;
1565 }
1566 break;
1567 case SCE_HPHP_COMMENTLINE:
1568 if (ch == '\r' || ch == '\n') {
1569 styler.ColourTo(i - 1, StateToPrint);
1570 state = SCE_HPHP_DEFAULT;
1571 }
1572 break;
1573 case SCE_HPHP_HSTRING:
1574 if (ch == '\\' && (phpStringDelimiter[0] == '\"' || chNext == '$' || chNext == '{')) {
1575 // skip the next char
1576 i++;
1577 } else if (((ch == '{' && chNext == '$') || (ch == '$' && chNext == '{'))
1578 && IsPhpWordStart(chNext2)) {
1579 styler.ColourTo(i - 1, StateToPrint);
1580 state = SCE_HPHP_COMPLEX_VARIABLE;
1581 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1582 styler.ColourTo(i - 1, StateToPrint);
1583 state = SCE_HPHP_HSTRING_VARIABLE;
1584 } else if (styler.Match(i, phpStringDelimiter)) {
1585 if (strlen(phpStringDelimiter) > 1)
1586 i += strlen(phpStringDelimiter) - 1;
1587 styler.ColourTo(i, StateToPrint);
1588 state = SCE_HPHP_DEFAULT;
1589 }
1590 break;
1591 case SCE_HPHP_SIMPLESTRING:
1592 if (ch == '\\') {
1593 // skip the next char
1594 i++;
1595 } else if (ch == '\'') {
1596 styler.ColourTo(i, StateToPrint);
1597 state = SCE_HPHP_DEFAULT;
1598 }
1599 break;
1600 case SCE_HPHP_HSTRING_VARIABLE:
1601 if (!IsPhpWordChar(ch)) {
1602 styler.ColourTo(i - 1, StateToPrint);
1603 i--; // strange but it works
1604 state = SCE_HPHP_HSTRING;
1605 }
1606 break;
1607 case SCE_HPHP_COMPLEX_VARIABLE:
1608 if (ch == '}') {
1609 styler.ColourTo(i, StateToPrint);
1610 state = SCE_HPHP_HSTRING;
1611 }
1612 break;
1613 case SCE_HPHP_OPERATOR:
1614 case SCE_HPHP_DEFAULT:
1615 styler.ColourTo(i - 1, StateToPrint);
1616 if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) {
1617 state = SCE_HPHP_NUMBER;
1618 } else if (iswordstart(ch)) {
1619 state = SCE_HPHP_WORD;
1620 } else if (ch == '/' && chNext == '*') {
1621 i++;
1622 state = SCE_HPHP_COMMENT;
1623 } else if (ch == '/' && chNext == '/') {
1624 i++;
1625 state = SCE_HPHP_COMMENTLINE;
1626 } else if (ch == '#') {
1627 state = SCE_HPHP_COMMENTLINE;
1628 } else if (ch == '\"') {
1629 state = SCE_HPHP_HSTRING;
1630 strcpy(phpStringDelimiter, "\"");
1631 } else if (styler.Match(i, "<<<")) {
1632 state = SCE_HPHP_HSTRING;
1633 i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler);
1634 } else if (ch == '\'') {
1635 state = SCE_HPHP_SIMPLESTRING;
1636 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1637 state = SCE_HPHP_VARIABLE;
1638 } else if (isoperator(ch)) {
1639 state = SCE_HPHP_OPERATOR;
1640 } else if ((state == SCE_HPHP_OPERATOR) && (isspacechar(ch))) {
1641 state = SCE_HPHP_DEFAULT;
1642 }
1643 break;
1644 ///////////// end - PHP state handling
1645 }
1646
1647 // Some of the above terminated their lexeme but since the same character starts
1648 // the same class again, only reenter if non empty segment.
1649
1650 bool nonEmptySegment = i >= static_cast<int>(styler.GetStartSegment());
1651 if (state == SCE_HB_DEFAULT) { // One of the above succeeded
1652 if ((ch == '\"') && (nonEmptySegment)) {
1653 state = SCE_HB_STRING;
1654 } else if (ch == '\'') {
1655 state = SCE_HB_COMMENTLINE;
1656 } else if (iswordstart(ch)) {
1657 state = SCE_HB_WORD;
1658 } else if (isoperator(ch)) {
1659 styler.ColourTo(i, SCE_HB_DEFAULT);
1660 }
1661 } else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded
1662 if ((ch == '\"') && (nonEmptySegment)) {
1663 state = SCE_HBA_STRING;
1664 } else if (ch == '\'') {
1665 state = SCE_HBA_COMMENTLINE;
1666 } else if (iswordstart(ch)) {
1667 state = SCE_HBA_WORD;
1668 } else if (isoperator(ch)) {
1669 styler.ColourTo(i, SCE_HBA_DEFAULT);
1670 }
1671 } else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded
1672 if (ch == '/' && chNext == '*') {
1673 if (styler.SafeGetCharAt(i + 2) == '*')
1674 state = SCE_HJ_COMMENTDOC;
1675 else
1676 state = SCE_HJ_COMMENT;
1677 } else if (ch == '/' && chNext == '/') {
1678 state = SCE_HJ_COMMENTLINE;
1679 } else if ((ch == '\"') && (nonEmptySegment)) {
1680 state = SCE_HJ_DOUBLESTRING;
1681 } else if ((ch == '\'') && (nonEmptySegment)) {
1682 state = SCE_HJ_SINGLESTRING;
1683 } else if (iswordstart(ch)) {
1684 state = SCE_HJ_WORD;
1685 } else if (isoperator(ch)) {
1686 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1687 }
1688 }
1689 }
1690
1691 StateToPrint = statePrintForState(state, inScriptType);
1692 styler.ColourTo(lengthDoc - 1, StateToPrint);
1693
1694 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
1695 if (fold) {
1696 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
1697 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
1698 }
1699 }
1700
1701 static bool isASPScript(int state) {
1702 return
1703 (state >= SCE_HJA_START && state <= SCE_HJA_REGEX) ||
1704 (state >= SCE_HBA_START && state <= SCE_HBA_STRINGEOL) ||
1705 (state >= SCE_HPA_DEFAULT && state <= SCE_HPA_IDENTIFIER);
1706 }
1707
1708 static void ColouriseHBAPiece(StyleContext &sc, WordList *keywordlists[]) {
1709 WordList &keywordsVBS = *keywordlists[2];
1710 if (sc.state == SCE_HBA_WORD) {
1711 if (!IsAWordChar(sc.ch)) {
1712 char s[100];
1713 sc.GetCurrentLowered(s, sizeof(s));
1714 if (keywordsVBS.InList(s)) {
1715 if (strcmp(s, "rem") == 0) {
1716 sc.ChangeState(SCE_HBA_COMMENTLINE);
1717 if (sc.atLineEnd) {
1718 sc.SetState(SCE_HBA_DEFAULT);
1719 }
1720 } else {
1721 sc.SetState(SCE_HBA_DEFAULT);
1722 }
1723 } else {
1724 sc.ChangeState(SCE_HBA_IDENTIFIER);
1725 sc.SetState(SCE_HBA_DEFAULT);
1726 }
1727 }
1728 } else if (sc.state == SCE_HBA_NUMBER) {
1729 if (!IsAWordChar(sc.ch)) {
1730 sc.SetState(SCE_HBA_DEFAULT);
1731 }
1732 } else if (sc.state == SCE_HBA_STRING) {
1733 if (sc.ch == '\"') {
1734 sc.ForwardSetState(SCE_HBA_DEFAULT);
1735 } else if (sc.ch == '\r' || sc.ch == '\n') {
1736 sc.ChangeState(SCE_HBA_STRINGEOL);
1737 sc.ForwardSetState(SCE_HBA_DEFAULT);
1738 }
1739 } else if (sc.state == SCE_HBA_COMMENTLINE) {
1740 if (sc.ch == '\r' || sc.ch == '\n') {
1741 sc.SetState(SCE_HBA_DEFAULT);
1742 }
1743 }
1744
1745 if (sc.state == SCE_HBA_DEFAULT) {
1746 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
1747 sc.SetState(SCE_HBA_NUMBER);
1748 } else if (IsAWordStart(sc.ch)) {
1749 sc.SetState(SCE_HBA_WORD);
1750 } else if (sc.ch == '\'') {
1751 sc.SetState(SCE_HBA_COMMENTLINE);
1752 } else if (sc.ch == '\"') {
1753 sc.SetState(SCE_HBA_STRING);
1754 }
1755 }
1756 }
1757
1758 static void ColouriseHTMLPiece(StyleContext &sc, WordList *keywordlists[]) {
1759 WordList &keywordsTags = *keywordlists[0];
1760 if (sc.state == SCE_H_COMMENT) {
1761 if (sc.Match("-->")) {
1762 sc.Forward();
1763 sc.Forward();
1764 sc.ForwardSetState(SCE_H_DEFAULT);
1765 }
1766 } else if (sc.state == SCE_H_ENTITY) {
1767 if (sc.ch == ';') {
1768 sc.ForwardSetState(SCE_H_DEFAULT);
1769 } else if (sc.ch != '#' && (sc.ch < 0x80) && !isalnum(sc.ch) // Should check that '#' follows '&', but it is unlikely anyway...
1770 && sc.ch != '.' && sc.ch != '-' && sc.ch != '_' && sc.ch != ':') { // valid in XML
1771 sc.ChangeState(SCE_H_TAGUNKNOWN);
1772 sc.SetState(SCE_H_DEFAULT);
1773 }
1774 } else if (sc.state == SCE_H_TAGUNKNOWN) {
1775 if (!ishtmlwordchar(static_cast<char>(sc.ch)) && !((sc.ch == '/') && (sc.chPrev == '<')) && sc.ch != '[') {
1776 char s[100];
1777 sc.GetCurrentLowered(s, sizeof(s));
1778 if (s[1] == '/') {
1779 if (keywordsTags.InList(s + 2)) {
1780 sc.ChangeState(SCE_H_TAG);
1781 }
1782 } else {
1783 if (keywordsTags.InList(s + 1)) {
1784 sc.ChangeState(SCE_H_TAG);
1785 }
1786 }
1787 if (sc.ch == '>') {
1788 sc.ForwardSetState(SCE_H_DEFAULT);
1789 } else if (sc.Match('/', '>')) {
1790 sc.SetState(SCE_H_TAGEND);
1791 sc.Forward();
1792 sc.ForwardSetState(SCE_H_DEFAULT);
1793 } else {
1794 sc.SetState(SCE_H_OTHER);
1795 }
1796 }
1797 } else if (sc.state == SCE_H_ATTRIBUTE) {
1798 if (!ishtmlwordchar(static_cast<char>(sc.ch))) {
1799 char s[100];
1800 sc.GetCurrentLowered(s, sizeof(s));
1801 if (!keywordsTags.InList(s)) {
1802 sc.ChangeState(SCE_H_ATTRIBUTEUNKNOWN);
1803 }
1804 sc.SetState(SCE_H_OTHER);
1805 }
1806 } else if (sc.state == SCE_H_OTHER) {
1807 if (sc.ch == '>') {
1808 sc.SetState(SCE_H_TAG);
1809 sc.ForwardSetState(SCE_H_DEFAULT);
1810 } else if (sc.Match('/', '>')) {
1811 sc.SetState(SCE_H_TAG);
1812 sc.Forward();
1813 sc.ForwardSetState(SCE_H_DEFAULT);
1814 } else if (sc.chPrev == '=') {
1815 sc.SetState(SCE_H_VALUE);
1816 }
1817 } else if (sc.state == SCE_H_DOUBLESTRING) {
1818 if (sc.ch == '\"') {
1819 sc.ForwardSetState(SCE_H_OTHER);
1820 }
1821 } else if (sc.state == SCE_H_SINGLESTRING) {
1822 if (sc.ch == '\'') {
1823 sc.ForwardSetState(SCE_H_OTHER);
1824 }
1825 } else if (sc.state == SCE_H_NUMBER) {
1826 if (!IsADigit(sc.ch)) {
1827 sc.SetState(SCE_H_OTHER);
1828 }
1829 }
1830
1831 if (sc.state == SCE_H_DEFAULT) {
1832 if (sc.ch == '<') {
1833 if (sc.Match("<!--"))
1834 sc.SetState(SCE_H_COMMENT);
1835 else
1836 sc.SetState(SCE_H_TAGUNKNOWN);
1837 } else if (sc.ch == '&') {
1838 sc.SetState(SCE_H_ENTITY);
1839 }
1840 } else if ((sc.state == SCE_H_OTHER) || (sc.state == SCE_H_VALUE)) {
1841 if (sc.ch == '\"' && sc.chPrev == '=') {
1842 sc.SetState(SCE_H_DOUBLESTRING);
1843 } else if (sc.ch == '\'' && sc.chPrev == '=') {
1844 sc.SetState(SCE_H_SINGLESTRING);
1845 } else if (IsADigit(sc.ch)) {
1846 sc.SetState(SCE_H_NUMBER);
1847 } else if (sc.ch == '>') {
1848 sc.SetState(SCE_H_TAG);
1849 sc.ForwardSetState(SCE_H_DEFAULT);
1850 } else if (ishtmlwordchar(static_cast<char>(sc.ch))) {
1851 sc.SetState(SCE_H_ATTRIBUTE);
1852 }
1853 }
1854 }
1855
1856 static void ColouriseASPPiece(StyleContext &sc, WordList *keywordlists[]) {
1857 // Possibly exit current state to either SCE_H_DEFAULT or SCE_HBA_DEFAULT
1858 if ((sc.state == SCE_H_ASPAT || isASPScript(sc.state)) && sc.Match('%', '>')) {
1859 sc.SetState(SCE_H_ASP);
1860 sc.Forward();
1861 sc.ForwardSetState(SCE_H_DEFAULT);
1862 }
1863
1864 // Handle some ASP script
1865 if (sc.state >= SCE_HBA_START && sc.state <= SCE_HBA_STRINGEOL) {
1866 ColouriseHBAPiece(sc, keywordlists);
1867 } else if (sc.state >= SCE_H_DEFAULT && sc.state <= SCE_H_SGML_BLOCK_DEFAULT) {
1868 ColouriseHTMLPiece(sc, keywordlists);
1869 }
1870
1871 // Enter new sc.state
1872 if ((sc.state == SCE_H_DEFAULT) || (sc.state == SCE_H_TAGUNKNOWN)) {
1873 if (sc.Match('<', '%')) {
1874 if (sc.state == SCE_H_TAGUNKNOWN)
1875 sc.ChangeState(SCE_H_ASP);
1876 else
1877 sc.SetState(SCE_H_ASP);
1878 sc.Forward();
1879 sc.Forward();
1880 if (sc.ch == '@') {
1881 sc.ForwardSetState(SCE_H_ASPAT);
1882 } else {
1883 if (sc.ch == '=') {
1884 sc.Forward();
1885 }
1886 sc.SetState(SCE_HBA_DEFAULT);
1887 }
1888 }
1889 }
1890 }
1891
1892 static void ColouriseASPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
1893 Accessor &styler) {
1894 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
1895 StyleContext sc(startPos, length, initStyle, styler, 0x7f);
1896 for (; sc.More(); sc.Forward()) {
1897 ColouriseASPPiece(sc, keywordlists);
1898 }
1899 sc.Complete();
1900 }
1901
1902 static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
1903 // Possibly exit current state to either SCE_H_DEFAULT or SCE_HBA_DEFAULT
1904 if (sc.state >= SCE_HPHP_DEFAULT && sc.state <= SCE_HPHP_OPERATOR) {
1905 if (!isPHPStringState(sc.state) &&
1906 (sc.state != SCE_HPHP_COMMENT) &&
1907 (sc.Match('?', '>'))) {
1908 sc.SetState(SCE_H_QUESTION);
1909 sc.Forward();
1910 sc.ForwardSetState(SCE_H_DEFAULT);
1911 }
1912 }
1913
1914 if (sc.state >= SCE_H_DEFAULT && sc.state <= SCE_H_SGML_BLOCK_DEFAULT) {
1915 ColouriseHTMLPiece(sc, keywordlists);
1916 }
1917
1918 // Handle some PHP script
1919 if (sc.state == SCE_HPHP_WORD) {
1920 if (!IsPhpWordChar(static_cast<char>(sc.ch))) {
1921 sc.SetState(SCE_HPHP_DEFAULT);
1922 }
1923 } else if (sc.state == SCE_HPHP_COMMENTLINE) {
1924 if (sc.ch == '\r' || sc.ch == '\n') {
1925 sc.SetState(SCE_HPHP_DEFAULT);
1926 }
1927 } else if (sc.state == SCE_HPHP_COMMENT) {
1928 if (sc.Match('*', '/')) {
1929 sc.Forward();
1930 sc.Forward();
1931 sc.SetState(SCE_HPHP_DEFAULT);
1932 }
1933 } else if (sc.state == SCE_HPHP_HSTRING) {
1934 if (sc.ch == '\"') {
1935 sc.ForwardSetState(SCE_HPHP_DEFAULT);
1936 }
1937 } else if (sc.state == SCE_HPHP_SIMPLESTRING) {
1938 if (sc.ch == '\'') {
1939 sc.ForwardSetState(SCE_HPHP_DEFAULT);
1940 }
1941 } else if (sc.state == SCE_HPHP_VARIABLE) {
1942 if (!IsPhpWordChar(static_cast<char>(sc.ch))) {
1943 sc.SetState(SCE_HPHP_DEFAULT);
1944 }
1945 } else if (sc.state == SCE_HPHP_OPERATOR) {
1946 sc.SetState(SCE_HPHP_DEFAULT);
1947 }
1948
1949 // Enter new sc.state
1950 if ((sc.state == SCE_H_DEFAULT) || (sc.state == SCE_H_TAGUNKNOWN)) {
1951 if (sc.Match("<?php")) {
1952 sc.SetState(SCE_H_QUESTION);
1953 sc.Forward();
1954 sc.Forward();
1955 sc.Forward();
1956 sc.Forward();
1957 sc.Forward();
1958 sc.SetState(SCE_HPHP_DEFAULT);
1959 }
1960 }
1961 if (sc.state == SCE_HPHP_DEFAULT) {
1962 if (IsPhpWordStart(static_cast<char>(sc.ch))) {
1963 sc.SetState(SCE_HPHP_WORD);
1964 } else if (sc.ch == '#') {
1965 sc.SetState(SCE_HPHP_COMMENTLINE);
1966 } else if (sc.Match("<!--")) {
1967 sc.SetState(SCE_HPHP_COMMENTLINE);
1968 } else if (sc.Match('/', '/')) {
1969 sc.SetState(SCE_HPHP_COMMENTLINE);
1970 } else if (sc.Match('/', '*')) {
1971 sc.SetState(SCE_HPHP_COMMENT);
1972 } else if (sc.ch == '\"') {
1973 sc.SetState(SCE_HPHP_HSTRING);
1974 } else if (sc.ch == '\'') {
1975 sc.SetState(SCE_HPHP_SIMPLESTRING);
1976 } else if (sc.ch == '$' && IsPhpWordStart(static_cast<char>(sc.chNext))) {
1977 sc.SetState(SCE_HPHP_VARIABLE);
1978 } else if (isoperator(static_cast<char>(sc.ch))) {
1979 sc.SetState(SCE_HPHP_OPERATOR);
1980 }
1981 }
1982 }
1983
1984 static void ColourisePHPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
1985 Accessor &styler) {
1986 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
1987 StyleContext sc(startPos, length, initStyle, styler, 0x7f);
1988 for (; sc.More(); sc.Forward()) {
1989 ColourisePHPPiece(sc, keywordlists);
1990 }
1991 sc.Complete();
1992 }
1993
1994 static void ColourisePHPScriptDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
1995 Accessor &styler) {
1996 if(startPos == 0) initStyle = SCE_HPHP_DEFAULT;
1997 ColouriseHyperTextDoc(startPos,length,initStyle,keywordlists,styler);
1998 }
1999
2000 static const char * const htmlWordListDesc[] = {
2001 "HTML elements and attributes",
2002 "JavaScript keywords",
2003 "VBScript keywords",
2004 "Python keywords",
2005 "PHP keywords",
2006 "SGML and DTD keywords",
2007 0,
2008 };
2009
2010 static const char * const phpscriptWordListDesc[] = {
2011 "", //Unused
2012 "", //Unused
2013 "", //Unused
2014 "", //Unused
2015 "PHP keywords",
2016 "", //Unused
2017 0,
2018 };
2019
2020 LexerModule lmHTML(SCLEX_HTML, ColouriseHyperTextDoc, "hypertext", 0, htmlWordListDesc, 7);
2021 LexerModule lmXML(SCLEX_XML, ColouriseHyperTextDoc, "xml", 0, htmlWordListDesc, 7);
2022 // SCLEX_ASP and SCLEX_PHP should not be used in new code: use SCLEX_HTML instead.
2023 LexerModule lmASP(SCLEX_ASP, ColouriseASPDoc, "asp", 0, htmlWordListDesc, 7);
2024 LexerModule lmPHP(SCLEX_PHP, ColourisePHPDoc, "php", 0, htmlWordListDesc, 7);
2025 LexerModule lmPHPSCRIPT(SCLEX_PHPSCRIPT, ColourisePHPScriptDoc, "phpscript", 0, phpscriptWordListDesc, 7);